异步爬虫(高效爬虫)

news/2024/7/19 10:16:51 标签: 爬虫, python

文章目录

  • 一、单线程串行爬取
  • 二、多线程并行爬取
  • 三、单线程+异步协程
    • 1、绑定回调
    • 2、多任务协成

如果有多个URL等待我们爬取,我们通常是一次只能爬取一个,爬取效率低,异步爬虫可以提高爬取效率,可以一次多多个URL同时同时发起请求

异步爬虫方式:
一、多线程、多进程(不建议):可以为爬取阻塞(多个URL等待爬取)单独开启线程或进程,多个爬取URL异步执行(不能开启无限多个)
二、线程池、进程池:可以降低系统对进程或者线程创建和消除的频率,从而降低系统的开销,池中进程或线程的数量是有上限的

一、单线程串行爬取

用时间延时模拟爬取每个网址的耗时时间
单线程爬取一次只能爬取一个,以下面为例,一次爬取一个,爬取4个需要8秒

python">import time

# 模拟爬取每个网址耗时
def get_page(url):
    time.sleep(2)

# 开始时间
start_time = time.time()
# URL
url_list = ['url1', 'url2', 'url3', 'url4']
for url in url_list:
    get_page(url)
# 结束时间
end_time = time.time()
# 输出总耗时
print(end_time-start_time)

二、多线程并行爬取

一次可以对多个URL同时进行爬取,以下面为例,开启4个进程,则可以对4个URL同时发起请求,总时间为2秒

python">import time
from multiprocessing.dummy import Pool

# 模拟爬取每个网址耗时
def get_page(url):
    time.sleep(2)

url_list = ['url1', 'url2', 'url3', 'url4']
# 开始时间
start_time = time.time()
# 实例化线程对象,4表示开启了4个进程
pool = Pool(4)
# 讲列表中url_list每一个列表元素传递给get_page进行处理
pool.map(get_page, url_list)
# 结束时间
end_time = time.time()
print(end_time-start_time)

三、单线程+异步协程

event_loop:事件循环,相当于一个无限循环,可以把一些函数注册到这个循环上,当满足某些条件的时候,函数就会被循环执行
coroutine:协程对象,我们可以将协程对象注册到事件循环中,它会被事件循环调用。我们可以使用async关键字来定义一个方法,这个方法在调用时不会立即被执行,而是返回一个协程对象。
task:任务,它是对协程对象的进一步封装,包含了任务的各个状态。
future:代表将来执行或还没有执行的任务,实际上和 task没有本质区别。async定义一个协程。
await用来挂起阻塞方法的执行。

python">import asyncio

async def request(url):
    print('模拟请求')

# 调用async修饰的函数之后返回一个协程对象
c = request('url')
# 创建一个事件循环对象
loop = asyncio.new_event_loop()
# 将协程对象注册到loop中.然后启动loop
loop.run_until_complete(c)
print(c)
# <coroutine object request at 0x000001F5BDDA8040>

task的使用

python">import asyncio

async def request(url):
    print('模拟请求')

# 调用async修饰的函数之后返回一个协程对象
c = request('https://www.baidu.com')
# 创建一个事件循环对象
loop = asyncio.new_event_loop()
# 基于loop创建一个task对象
task = loop.create_task(c)
# 注册循环之前的输出
print(task)
loop.run_until_complete(task)
# 注册循环之后的输出
print(task)
''' 输出如下
<Task pending name='Task-1' coro=<request() running at E:\Code\pythonProject\main.py:4>>
模拟请求
<Task finished name='Task-1' coro=<request() done, defined at E:\Code\pythonProject\main.py:4> result=None>
'''

future的使用

python">import asyncio

async def request(url):
    print('模拟请求')

# 调用async修饰的函数之后返回一个协程对象
c = request('https://www.baidu.com')
# 创建一个事件循环对象
loop = asyncio.new_event_loop()
# 基于loop创建一个task对象
task = asyncio.ensure_future(c, loop=loop)
print(task)
loop.run_until_complete(task)
print(task)
'''
<Task pending name='Task-1' coro=<request() running at E:\Code\pythonProject\main.py:3>>
模拟请求
<Task finished name='Task-1' coro=<request() done, defined at E:\Code\pythonProject\main.py:3> result=None>
'''

1、绑定回调

python">import asyncio

async def request(url):
    print('模拟请求')
    return url

def callback_func(task):
    # result返回的是任务对象中封装的携程对象对应函数的返回值,即上面返回的url
    print(task.result())

# async修饰的函数,调用之后返回的一个协程对象
c = request('url')

loop = asyncio.new_event_loop()
task = asyncio.ensure_future(c, loop=loop)
# 将回调函数绑定到任务对象中
task.add_done_callback(callback_func) # task
loop.run_until_complete(task)
'''
模拟请求
url
'''

2、多任务协成

在异步协成中,如果出现了同步模块相关的代码,那么就无法实现异步,如下面的time.sleep(2),下面代码没起到异步作用,爬取三个网站需要6秒左右

python">import asyncio
import time

async def request(url):
    print('模拟请求')
    # 在异步协成中,如果出现了同步模块相关的代码,那么就无法实现异步
    time.sleep(2)
    return url

start = time.time()
urls = ['aaa', 'bbb', 'ccc']
# 任务列表:存放多个任务对象
stasks = []

# 将任务对象列表注册到事件循环当中
loop = asyncio.new_event_loop()
for url in urls:
    c = request(url)
    task = asyncio.ensure_future(c, loop=loop)
    stasks.append(task)
    
# 需要将任务列表封装到wait中
loop.run_until_complete(asyncio.wait(stasks))
print(time.time() - start)
'''
模拟请求
模拟请求
模拟请求
6.002672433853149
'''

这里就需要使用asyncio.sleep,当在asyncio中遇到阻塞操作必须进行手动挂起,使用await挂起,如下方法起到了异步左右,爬取三个URL只需要2秒左右

python">import asyncio
import time

async def request(url):
    print('模拟请求')
    # 当在asyncio中遇到阻塞操作必须进行手动挂起
    await asyncio.sleep(2)
    return url

start = time.time()
urls = ['aaa', 'bbb', 'ccc']
# 任务列表:存放多个任务对象
stasks = []

# 将任务对象列表注册到事件循环当中
loop = asyncio.new_event_loop()
for url in urls:
    c = request(url)
    task = asyncio.ensure_future(c, loop=loop)
    stasks.append(task)
    
# 需要将任务列表封装到wait中
loop.run_until_complete(asyncio.wait(stasks))
print(time.time() - start)
'''
模拟请求
模拟请求
模拟请求
2.0162434577941895
'''

requests.get请求是基于同步的,那么就无法实现异步,耗时较长

python">async def request(url):
    # requests.get请求是基于同步的,那么就无法实现异步
    response = requests.get(url=url)

必须使用基于异步的网络请求模块进行请求发送
aiohttp:基于异步网络请求的模块
pip install aiohttp

python">import aiohttp

async def request(url):
    async with aiohttp.ClientSession() as session:  # 返回session对象
        # 将get改为post为post请求
        # 参数:headers,params/data,proxy='http://ip:port
        async with await session.get(url) as response:   # 返回response对象
            # text()返回字符串形式的响应数据
        	# read()返回二进制形式的响应数据
        	# json()返回的是json对象
        	# 注意:在获取响应数据操作之前一定要使用await进行手动挂起
        	page_text = await response.text()
    

http://www.niftyadmin.cn/n/144344.html

相关文章

SUSE enterprise 12 解决 no module named ‘_lzma‘

近期要在SLE 12上配置Python环境&#xff0c;期间出现了这个问题 在网上搜了很久&#xff0c;大部分都是centos的解决方法&#xff0c;使用yum来安装。但是SUSE没有yum也没有apt只有zypper&#xff0c;我在zypper上没折腾出来。于是打算自己去找安装包。 解决过程 1、下载xz…

Pywinauto常用02--pywin32(Python调用win api)

pywin32&#xff08;Python调用win api&#xff09; pywin32是一个第三方模块库&#xff0c;主要的作用是方便python开发者快速调用windows API的一个模块库。 Win32gui: Windows图形界面接口模块。 主要负责操作窗口切换以及窗口中元素id标签的获取Win32api: Windows开发接口…

@Import使用场景

文章目录一、注解说明1. 注解源码2. 注解使用场景二、使用案例1. 引入普通类案例&#xff08;1&#xff09;新建User类&#xff08;2&#xff09;新建Spring配置类ImportConfig&#xff08;3&#xff09;新建ImportTest类&#xff08;4&#xff09;运行ImportTest类2. 引入实现…

IO流(C++)

文章目录1. C语言的输入与输出1.1 缓冲区2. 流&#xff08;stream&#xff09;C IO流3. C标准IO流3.1 iostream3.2 cin和cout的配合以空格或回车为分隔输入输出重载流插入和流提取运算符多行测试用例cin和cout适用于自定义类型内置类型->自定义类型自定义类型->内置类型4…

Java 流(Stream)、文件(File)和IO

Java是一种广泛使用的编程语言&#xff0c;它提供了许多处理流、文件和I/O的功能。Java中的流(Stream)提供了一个统一的接口来处理输入和输出数据&#xff0c;文件(File)提供了一种简单的方式来操作磁盘上的文件&#xff0c;而I/O则允许我们在Java程序中读写数据。 本文将详细…

【第72篇】深度学习在视频多目标跟踪中的应用综述

文章目录 摘要1、简介2、MOT:算法、指标和数据集2.1、MOT算法简介2.2、指标经典的指标完整的MOT指标ID 分数2.3、基准数据集3、MOT中的深度学习3.1、深度学习中的检测步骤3.1.1、Faster R-CNN3.1.2、SSD3.1.3、Other detectors3.1.4、cnn在检测步骤中的其他用途3.2、深度学习在…

hadoop集群优化(一):ntpd时间同步

说明 hadoop集群个节点时间同步非常重要&#xff0c;如果服务器间时间不同步&#xff0c;将引发集群服务异常。 主流设置时间同步服务的软件有两个ntpd和chrony&#xff0c;功能和稳定性推荐使用chrony。由于最早使用ntpd配置&#xff0c;这里先介绍ntpd时间同步&#xff0c;后…

OpenFeign设置header

设置Feign的Header信息(五种方式)概述在微服务间使用Feign进行远程调用时需要在 header 中添加信息&#xff0c;那么 springcloud open feign 如何设置 header 呢&#xff1f;有5种方式可以设置请求头信息&#xff1a;在RequestMapping注解里添加headers属性在方法参数前面添加…