高性能异步爬虫
目的:在爬虫中使用异步实现高性能的数据爬取操作。
异步爬虫的方式:
- 多线程,多进程(不建议):
好处:可以为相关阻塞的操作单独开启线程或者进程,阻塞操作就可以异步执行。
弊端:无法无限制的开启多线程或者多进程。
- 线程池、进程池(可以适当的使用)
好处:可以降低系统对进程或者线程创建和销毁的一个频率,从而很好的降低系统的开销。
弊端:池中线程或者进程的数量有上限。
爬取目标:梨视频排行榜8个视频
目标网址:https://www.pearvideo.com/popular_5
代码
import requests
from lxml import etree
import re
from multiprocessing.dummy import Pool
headers = { # 模拟浏览器头部信息
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.61 Safari/537.36"
}
# 对下述url发起请求解析出视频详情页的url和视频的名称
url = 'https://www.pearvideo.com/popular_5'
page_text = requests.get(url=url, headers=headers).text
tree = etree.HTML(page_text)
li_list = tree.xpath('//ul[@id="popularList"]/li')
urls = [] # 存储所有的视频链接和名字
for li in li_list:
detail_url = 'https://www.pearvideo.com/' + li.xpath('./div[2]/a/@href')[0]
name = li.xpath('./div[2]/a/h2/text()')[0]
# 去掉特殊字符
name = re.sub(u"([^\u4e00-\u9fa5\u0030-\u0039\u0041-\u005a\u0061-\u007a])", "", name) + '.mp4'
print(detail_url, name)
# 对视频详情页的url发起请求
detail_page_text = requests.get(url=detail_url, headers=headers).text
# xpath只能定位标签 无法定位js代码 所以此处使用正则表达式
ex = 'srcUrl="(.*?)",vdoUrl'
video_url = re.findall(ex, detail_page_text)[0]
dic = {
'name': name,
'url': video_url
}
urls.append(dic)
print(urls)
# 对视频链接发起请求获取视频的二进制数据,然后将视频数据进行返回
def get_video_data(dic):
url = dic['url']
print(dic['name'], '正在下载...')
data = requests.get(url=url, headers=headers).content # 获取二进制数据
# 持久化操作
with open(dic['name'], 'wb') as fp:
fp.write(data)
print(dic['name'], '下载成功!')
# 使用线程池对视频数据进行请求
pool = Pool(8)
pool.map(get_video_data, urls)
pool.close() # 关闭线程池
pool.join() # 主线程等待子线程结束后再结束
效果图