非同期モード爬虫類
目的:操作のクローラをクロールで高性能非同期データ
非同期モード爬虫類:
マルチプロセス、マルチスレッド(推奨)
利点:あなたは、プロセスまたはスレッドを開始することができますが、最初の操作のためだけでは遮断され、ブロック操作を非同期に実行することができます
短所:無制限開くことができません。
スレッドプール、プロセスプール(適切な使用)
メリット:あなたは、システムのオーバーヘッドを削減、プロセスまたはスレッドの作成と評価の破壊率にシステムを減らすことができます
短所:プールのスレッドやプロセスの数は、ライン上に持っています
+シングルスレッドの非同期コルーチン(推奨)
event_loop:私たちは、このイベントループに登録されている機能のいくつかを置くことができるイベントループ、無限ループの等価な、
一定の条件が満たされた場合、関数が周期的に実行されます。coroutine:协程对象,我们可以将协程对象注册到事件循环中,它会被事件循环调用。 我们可以使用 async 关键字来定义一个方法,这个方法在调用时不会立即被执行,而是返回 一个协程对象。 task:任务,它是对协程对象的进一步封装,包含了任务的各个状态。 future:代表将来执行或还没有执行的任务,实际上和 task 没有本质区别。 async 定义一个协程. await 用来挂起阻塞方法的执行。
基本的な使用スレッドプール
#使用线程池方式执行
import time
from multiprocessing.dummy import Pool
def get_page(str):
print("正在下载 :",str)
time.sleep(2)
print('下载成功:',str)
start_time = time.time()
name_list =['xiaozi','aa','bb','cc']
#实例化一个线程池对象
pool = Pool(4)
#将列表中每一个列表元素传递给get_page进行处理。
pool.map(get_page,name_list)
pool.close()
pool.join()
print(time.time()-start_time)
スレッドプールの実装:梨の動画をクロール
import requests, re
from lxml import etree
from multiprocessing.dummy import Pool
headers = {
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3945.79 Safari/537.36"
}
url = "https://www.pearvideo.com/category_4"
page_text = requests.get(url=url, headers=headers).text
tree = etree.HTML(page_text)
li_list = tree.xpath('//*[@id="listvideoListUl"]/li')
video_urls_list = []
for li in li_list:
detail_url = 'https://www.pearvideo.com/' + li.xpath('./div/a/@href')[0]
detail_page_text = requests.get(url=detail_url, headers=headers).text
tree = etree.HTML(detail_page_text)
video_name = tree.xpath('//*[@id="poster"]/img/@alt')[0] + ".mp4"
# js动态加载,只能使用正则解析video_url
ex = 'srcUrl="(.*?)",vdoUrl'
video_url = re.findall(ex, detail_page_text)[0]
video_info = {
"name": video_name,
"url": video_url
}
video_urls_list.append(video_info)
def get_video_data(dic):
url = dic["url"]
name = dic["name"]
print(name, "正在下载...")
video_data = requests.get(url=url, headers=headers).content
with open(name, "wb") as fp:
fp.write(video_data)
print(name, "正在成功")
pool = Pool(4)
pool.map(get_video_data, video_urls_list)
pool.close()
pool.join()
コルーチンの基本的な使用
シングルタスクコルーチンを使用します
import asyncio
async def request(url):
print('正在请求的url是',url)
print('请求成功,',url)
return url
#async修饰的函数,调用之后返回的一个协程对象
c = request('www.baidu.com')
# # 创建一个事件循环对象
# loop = asyncio.get_event_loop()
# # 将协程对象注册到事件循环对象,即loop中
# # 此步骤既注册,又启动了事件循环
# loop.run_until_complete(c)
# task的使用 task是对协程对象的进一步封装
# loop = asyncio.get_event_loop()
# task = loop.create_task(c)
# print(task)
# loop.run_until_complete(task)
# print(task)
# future的使用 future也是协程对象的进一步封装 与task无本质区别
# loop = asyncio.get_event_loop()
# task = asyncio.ensure_future(c)
# print(task)
# loop.run_until_complete(task)
# print(task)
# 绑定回调
def callback_fun(task):
# result返回的就是任务对象中封装的协程对象对应函数的返回值
print(task.result())
loop = asyncio.get_event_loop()
task = asyncio.ensure_future(c)
# 任务对象执行前绑定回调函数
task.add_done_callback(callback_fun)
# 执行任务对象
loop.run_until_complete(task)
マルチタスクコルーチンの使用
マルチタスク:タスクリストの登録を使用してくださいwait
:loop.run_until_complete(asyncio.wait(tasks))
requests.getが同期要求に基づいて、要求は、非同期要求モジュールベースの伝送ネットワーク開発URLを使用する必要があります
aiohttp:要求モジュールに基づいて非同期ネットワーク
# 使用Flask模拟服务器
import asyncio
import requests
import time
start = time.time()
urls = [
'http://127.0.0.1:5000/bobo',
'http://127.0.0.1:5000/jay',
'http://127.0.0.1:5000/tom',
]
async def get_page(url):
print('正在下载', url)
#requests.get是基于同步的请求,必须使用基于异步的网络请求模块进行制定url的请求发送
#aiohttp: 基于异步网络请求的模块
response = requests.get(url=url)
print('下载完毕', response.text)
# 将任务添加到任务列表
tasks = [asyncio.ensure_future(get_page(url)) for url in urls]
#将任务列表注册到事件循环对象
loop = asyncio.get_event_loop()
loop.run_until_complete(asyncio.wait(tasks))
print('总耗时:', time.time()-start)
マルチタスクコルーチンの使用非同期
モジュールの使用 aiohttp
フェッチ応答データを操作する前のawaitマニュアルをハングアップするために使用されなければなりません await
# 环境安装:pip install aiohttp
# 使用该模块中的ClientSession
import requests
import asyncio
import time
import aiohttp
async def get_page(url):
async with aiohttp.ClientSession() as session:
# get()、post():
# headers,关键字传参
# params/data,
# proxy='http://ip:port',不在是字典
async with await session.get(url) as response:
# text()返回字符串形式的响应数据
# read()返回的二进制形式的响应数据
# json()返回的就是json对象
# 注意:获取响应数据操作之前一定要使用await进行手动挂起
page_text = await response.text()
print(page_text)
start = time.time()
urls = ['http://127.0.0.1:5000/bobo' for i in range(10)]
tasks = [asyncio.ensure_future(get_page(url)) for url in urls]
loop = asyncio.get_event_loop()
loop.run_until_complete(asyncio.wait(tasks))
print('总耗时:', time.time()-start)
戦闘:4kの美しい写真をクロール
知識:非同期機能パッケージをクロールXPathデータ解析、マルチタスクコルーチン
import requests
from lxml import etree
import time, os
import asyncio
import aiohttp
start = time.time()
headers = {
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3945.79 Safari/537.36"
}
if not os.path.exists('./libs'):
os.mkdir('./libs')
def get_img_info(page_url, pic_info_list):
"""
获取图片信息
:param page_url: 页面url
:param pic_info_list: 把图片url和图片名以字典的形式存放在pic_info_list列表中
:return:
"""
url = page_url
page_text = requests.get(url=url, headers=headers).text
tree = etree.HTML(page_text)
li_list = tree.xpath('//div[@class="slist"]/ul/li')
for li in li_list:
img_src = 'http://pic.netbian.com' + li.xpath('./a/img/@src')[0]
name = li.xpath('./a/img/@alt')[0].encode('iso-8859-1').decode('gbk')
pic_info_list.append({"url": img_src, "name": name})
# 同步爬取
# data = requests.get(url=img_src).content
# path = './libs/'+name
# with open(path,'wb') as fp:
# fp.write(data)
# print(name,'下载成功')
# 一下是异步爬取的代码
async def down_img(dic):
"""
多任务异步协程下载图片
:param dic:
:return:
"""
img_url = dic["url"]
img_name = dic["name"]
async with aiohttp.ClientSession() as session:
async with await session.get(url=img_url, headers=headers) as response:
img_data = await response.read()
with open(f"libs/{img_name}.jpg", "wb") as fp:
fp.write(img_data)
print(f"{img_name}, 下载成功!!!")
url1 = 'http://pic.netbian.com/4kmeinv/index.html'
url2 = 'http://pic.netbian.com/4kmeinv/index_%d.html'
pic_info_list = []
# 第一页图片
get_img_info(url1, pic_info_list)
# 第2-4页图片
for page in range(2,5):
new_url = format(url2 % page)
get_img_info(new_url, pic_info_list)
# 多任务异步协程启动
tasks = [asyncio.ensure_future(down_img(dic)) for dic in pic_info_list]
loop = asyncio.get_event_loop()
loop.run_until_complete(asyncio.wait(tasks))
print('总耗时:', time.time()-start)