9.异步爬虫

异步爬虫可以理解为非只单线程爬虫

我们下面做个例子,之前我们通过单线程爬取过梨视频 https://blog.csdn.net/potato123232/article/details/135672504

在保存视频的时候会慢一些,为了提升效率,我们使用异步爬虫爬取

目录

[1 线程池](#1 线程池)

[2 单线程+异步协程](#2 单线程+异步协程)

[2.1 aiohttp的基本使用](#2.1 aiohttp的基本使用)

[2.2 爬取梨视频](#2.2 爬取梨视频)

[3 单线程,协程,多线程的运行速度比较](#3 单线程,协程,多线程的运行速度比较)


1 线程池

线程池的基本用法在这里有提到 python并发任务-CSDN博客

多线程应仅用于耗时的部分,如果我们为了省事去将所有部分都封装为一个函数就容易出错

  • 走单线程可以成功爬取10个视频,当我将所有过程封装为一个函数时,使用多线程爬取会报错。在JS中的异步也会有这种问题,就像是请求还没请求完,后面加载就加载上了
python 复制代码
import requests
from lxml import etree
import random
import re
from multiprocessing.dummy import Pool

# 保存根页面
url = 'https://www.pearvideo.com/popular'
headers={'User-Agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/116.0.0.0 Safari/537.36'}
response = requests.get(url=url,headers=headers)
response.encoding = response.apparent_encoding
with open('./test.html','w',encoding='utf-8') as f:
    f.write(response.text)
print(response)

# 获取所有细节页面url
detail_htmls = []
tree = etree.HTML(response.text)
for i in range(1,len(tree.xpath('//*[@id="popularList"]/li'))+1):
    detail_htmls.append({'url':'https://www.pearvideo.com/' + tree.xpath('//*[@id="popularList"]/li[{}]/a/@href'.format(i))[0],'title':tree.xpath('//*[@id="popularList"]/li['+ str(i) +']/div[2]/a/h2/text()')[0]})

# print(detail_htmls)
p = re.compile(r'.*\/(.*?)-\d')

video_detail_list = []
for i in detail_htmls:
    contId = i['url'].split('_')[-1]
    mrd = round(random.random(), 16)
    headers['Host'] = 'www.pearvideo.com'
    headers['Referer'] = i['url']
    response = requests.get(url='https://www.pearvideo.com/videoStatus.jsp?contId=' + str(contId) + '&mrd=' + str(mrd),
                            headers=headers).text

    srcUrl = eval(response).get('videoInfo').get('videos').get('srcUrl')

    need_change_part = p.findall(srcUrl)[0]
    true_video_url = srcUrl.split(need_change_part)[0] + 'cont-' + contId + srcUrl.split(need_change_part)[1]

    video_name = re.sub(r'[\\/:*?"<>|]', '', i['title'])
    video_detail_list.append({"name":video_name,"url":true_video_url})

print(video_detail_list)
def get_video(item):
    response = requests.get(item['url'])
    with open('./result/' + str(item['name']) + '.mp4', 'wb') as fp:
        fp.write(response.content)
        print(item['url'] + '下载成功')

pool = Pool(4)
pool.map(get_video,video_detail_list)

耗时的部分只有保存,所以我们保存的部分剥离出来,这样就能成功爬取10个视频

2 单线程+异步协程

2.1 aiohttp的基本使用

我们先做个简单的服务,这三个服务无论请求哪一个都会等待两秒,然后返回一个字符串

之后我们尝试只用asyncio发起异步请求

从耗时来看这段代码并没有发起异步请求

这个时候我们可以使用aiohttp进行异步请求

  • 这个能看懂就行了,如果到了一定要使用的时候,看看别人怎么写的抄一抄就完了
  • 如果不加最后打印之前的await,那么就有可能会打印不出来东西,由于请求是异步的,他会跳过请求而执行下面,就像js中的定时器
  • response.text()是返回字符串类型的响应,read()是返回二进制类型的响应,json()返回的是json对象类型的响应
  • 除了发get请求还可以发post请求,参数与requests.get(),requests.post()基本一致(get用的params一致,post用的data一致,请求头headers一致,aiohttp的代理参数名为proxy,proxy参数值为字符串)

2.2 爬取梨视频

异步保存文件可以借助 aiofiles

python 复制代码
import requests
from lxml import etree
import random
import re
import aiohttp
import asyncio
import aiofiles

# 保存根页面
url = 'https://www.pearvideo.com/popular'
headers={'User-Agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/116.0.0.0 Safari/537.36'}
response = requests.get(url=url,headers=headers)
response.encoding = response.apparent_encoding
with open('./test.html','w',encoding='utf-8') as f:
    f.write(response.text)
print(response)

# 获取所有细节页面url
detail_htmls = []
tree = etree.HTML(response.text)
for i in range(1,len(tree.xpath('//*[@id="popularList"]/li'))+1):
    detail_htmls.append({'url':'https://www.pearvideo.com/' + tree.xpath('//*[@id="popularList"]/li[{}]/a/@href'.format(i))[0],'title':tree.xpath('//*[@id="popularList"]/li['+ str(i) +']/div[2]/a/h2/text()')[0]})

# print(detail_htmls)
p = re.compile(r'.*\/(.*?)-\d')

video_detail_list = []
for i in detail_htmls:
    contId = i['url'].split('_')[-1]
    mrd = round(random.random(), 16)
    headers['Host'] = 'www.pearvideo.com'
    headers['Referer'] = i['url']
    response = requests.get(url='https://www.pearvideo.com/videoStatus.jsp?contId=' + str(contId) + '&mrd=' + str(mrd),
                            headers=headers).text

    srcUrl = eval(response).get('videoInfo').get('videos').get('srcUrl')

    need_change_part = p.findall(srcUrl)[0]
    true_video_url = srcUrl.split(need_change_part)[0] + 'cont-' + contId + srcUrl.split(need_change_part)[1]

    video_name = re.sub(r'[\\/:*?"<>|]', '', i['title'])
    video_detail_list.append({"name":video_name,"url":true_video_url})

print(video_detail_list)

async def test(item):
    async with aiohttp.ClientSession() as session:
        async with await session.get(item['url']) as response:
            async with aiofiles.open('./result/' + str(item['name']) + '.mp4', 'wb') as fp:
                await fp.write(await response.read())
                print(item['url'] + '下载成功')

future_list = []
for something1 in video_detail_list:
    a = test(something1)
    future = asyncio.ensure_future(a)
    future_list.append(future)

loop = asyncio.get_event_loop()
loop.run_until_complete(asyncio.wait(future_list))

可以爬取成功,每个视频都可以点开看

但是代码在pycharm的返回值并不是0

3 单线程,协程,多线程的运行速度比较

就梨视频的例子来说,单线程最慢,多线程第二(因为我只用4线程,如果10线程应该还会快一些),感觉上来讲协程最快

相关推荐
csdn_aspnet1 小时前
Libvio.link爬虫技术深度解析:反爬机制破解与高效数据抓取
爬虫·反爬·libvio
0思必得03 小时前
[Web自动化] Selenium处理滚动条
前端·爬虫·python·selenium·自动化
vx_biyesheji00015 小时前
豆瓣电影推荐系统 | Python Django 协同过滤 Echarts可视化 深度学习 大数据 毕业设计源码
大数据·爬虫·python·深度学习·django·毕业设计·echarts
深蓝电商API5 小时前
爬虫IP封禁后的自动切换与检测机制
爬虫·python
喵手7 小时前
Python爬虫实战:公共自行车站点智能采集系统 - 从零构建生产级爬虫的完整实战(附CSV导出 + SQLite持久化存储)!
爬虫·python·爬虫实战·零基础python爬虫教学·采集公共自行车站点·公共自行车站点智能采集系统·采集公共自行车站点导出csv
喵手7 小时前
Python爬虫实战:地图 POI + 行政区反查实战 - 商圈热力数据准备完整方案(附CSV导出 + SQLite持久化存储)!
爬虫·python·爬虫实战·零基础python爬虫教学·地区poi·行政区反查·商圈热力数据采集
芷栀夏7 小时前
从 CANN 开源项目看现代爬虫架构的演进:轻量、智能与统一
人工智能·爬虫·架构·开源·cann
喵手1 天前
Python爬虫实战:HTTP缓存系统深度实战 — ETag、Last-Modified与requests-cache完全指南(附SQLite持久化存储)!
爬虫·python·爬虫实战·http缓存·etag·零基础python爬虫教学·requests-cache
喵手1 天前
Python爬虫实战:容器化与定时调度实战 - Docker + Cron + 日志轮转 + 失败重试完整方案(附CSV导出 + SQLite持久化存储)!
爬虫·python·爬虫实战·容器化·零基础python爬虫教学·csv导出·定时调度
喵手1 天前
Python爬虫实战:全站 Sitemap 自动发现 - 解析 sitemap.xml → 自动生成抓取队列的工业级实现!
爬虫·python·爬虫实战·零基础python爬虫教学·sitemap·解析sitemap.xml·自动生成抓取队列实现