无聊的前言
前几天溜阿松有点多,心血来潮想到一个有意思的炒作点子。但要实现需要几十个视频封面,虽然F12找图片直链很容易,但一个一个下实在有点麻烦,刚好在学python的requests库,就想写个爬虫全爬下来。
爬虫基本思路
爬虫有很多写法,Java,JavaScript,Python都可以,但python的requests库很方便,最常用的明显是python爬虫。在具体代码实现层面,大多数爬虫都有非常相似的结构:
- 分析网页结构,找出有规律的接口
- 利用requests库发起请求
这两个过程是通用的,但对下面的操作,静态网页与动态网页不同:
对静态网页,利用beautifulsoup库解析页面抓取内容
对动态网页,利用json库解析得到的json数据
静态网页即在浏览网页过程中没有浏览器与服务器交互的网页,此时Ctrl+u与F12审查元素得到的源码相同,直接发起请求,再用bs4库解析网页源码内容即可.
bs4库也是非常好用的python解析库,对于爬虫,找到需要爬取部分的网页源码,然后注意其周围唯一的元素名或class名再用find_all()具体解析即可。
例如:
1 2 3 4 5 6 7 8 9 10 11 12 13
| def find(url): web = requests.get(url, headers=headers) html = web.content.decode("utf-8") soup = BeautifulSoup(html, "lxml") lis = soup.find_all('li', class_="small-item fakeDanmu-item") url0 = lis[1].a.img['src'] img_url = 'http://'+url0 return img_url
|
但静态网页没有网页交互,且需要一次性加载出所有内容,较为不便。动态网页则没有这种劣势,动态网页利用Ajax不断发起对服务器的请求,无需刷新页面即可完成内容更新。
实战:爬取B站个人主页视频封面
本来准备用bs4解析页面,结果发现请求后找不到内容😓,才发现B站个人主页是Ajax动态网页
主页里的投稿列表是通过一个XHR(即Ajax的json请求)获取的,因此动态页面爬取反而更简单,只需要分析页面找到对应的api,对这个api发起请求获取json数据,再用json库转成python字典,就能轻松找到封面直链url。
1 2 3 4 5 6
| def find_url(url0, num0): web = requests.get(url0) data = json.loads(web.text) pic_url = data["data"]["list"]["vlist"][num0]["pic"] return pic_url
|
上面这个函数的参数num0为变量,可以利用这个循环爬取内容,这样就取得了封面图片直链,下一步是将其下载至指定目录
1 2 3 4 5 6 7 8 9 10
| def download(url1, download_num): jpg = requests.get(url1, headers=headers) f = open("azusa" + str(download_num) + ".jpg", 'wb') f.write(jpg.content) f.close() print('Pic saved!')
|
再在主函数里写入循环调用这两个函数即可,完整爬虫源码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42
|
import requests
import json path = "/mnt/c/workplace"
url = "https://api.bilibili.com/x/space/arc/search?mid=231590&ps=30&tid=0&pn=1&keyword=&order=click&jsonp=jsonp" headers = { 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) ' 'Chrome/96.0.4664.110 Safari/537.36', 'referer': 'https://space.bilibili.com/231590/video'}
def find_url(url0, num0): web = requests.get(url0,headers=headers) data = json.loads(web.text) pic_url = data["data"]["list"]["vlist"][num0]["pic"] return pic_url def download(url1, download_num): jpg = requests.get(url1, headers=headers) f = open("azusa" + str(download_num) + ".jpg", 'wb') f.write(jpg.content) f.close() print('Pic saved!') def main(): for num in range(30): url1 = find_url(url, num) download(url1, num) print('all pics are saved!') if __name__ == '__main__': main()
|
大功告成。