简谈异步爬虫aiohttp

发布于:2023-01-11 ⋅ 阅读:(611) ⋅ 点赞:(0)

         之前涉及到的爬虫,都基本上使用的requests库进行爬取。但是request获取网站内容的话,是有相应时间的,要不然也不会设置timeout了。
        但是,响应时间内,程序也在等待,响应时间越长等待时间就相对变长。
        因为python的自身原因多线程就不做最优选了(但是我很喜欢用=)),多进程则是利用cpu的多核在同一时间内进行多个任务。

        因此就该引出一个概念——协程coroutine。

一、协程

        协程又叫微线程,将一个任务挂起并记住当前的状态进行调度切换。假如一个程序有两个方法A和B,协程就可以随时停止A来执行B,但是协程的本质还是单线程。

        在爬虫程序中,在请求相应的时间内,就可以利用这个时间去执行其他的方法,当相应完成之后在继续处理,充分利用资源。

        python中使用协程最常用的库应该就是asyncio了。

        这边按我写的一个代理测试的脚本做一个例子,我这里使用的是ipidea的代理,好的代理能帮助你更好的获取数据,高质量低延迟,而且新用户可以白嫖哦!

        地址:「全球HTTP」- IPIDEA企业爬虫代理IP , 高速HTTP定制服务商

import asyncio
import requests
from loguru import logger
import time

start = time.time()
async def get_res(url,headers,entry):
    proxies = {
        'http': entry,
        'https': entry,
    }
    for i in range(3):
        try:
            if proxies and headers:
                res = requests.get(url, headers=headers, proxies=proxies)
                if res.status_code == 200 and res:
                    logger.success('请求成功')
                    return res
        except:
            logger.warning('')

async def IPtest():
    url = "https://ipinfo.io/widget"
    headers = {
        "accept": "*/*",
        "authority": "ipinfo.io",
        "referer": "https://ipinfo.io/",
        "User-Agent": "Mozilla/5.0 (iPhone; CPU iPhone OS 10_3_3 like Mac OS X) AppleWebKit/603.3.8 (KHTML, like Gecko) Mobile/14G60 MicroMessenger/6.5.19 NetType/4G Language/zh_TW",
    }
    proxies = "代理"
    await get_res(url,headers,proxies)

tasks = [asyncio.ensure_future(IPtest()) for _ in range (10)]
loop = asyncio.get_event_loop()
loop.run_until_complete(asyncio.wait(tasks))
end = time.time()
print(end-start)

        首先引入asyncio包,用async定义了两个方法,一个是开始方法IPtest,提供待请求信息,之后调用get_res方法,接受提供的信息进行请求。

        为什么使用async去定义,因为async定义的是无法直接执行的协程对象
        tasks,使用asynio的ensure_future方法,封装协程对象创建任务,这里的tasks是for循环创建了10个任务存到一个list里。
        loop,使用asyncio的get_event_loop方法,创建了事件循环。然后再使用loop对象的run_until_complete方法将tasks绑定到事件循环中执行。

        执行,效果如下:

        但是,requests包不是真正的异步请求方式,还有进一步的提升空间,于是就有了真正的异步请求方法:aiohttp。 

二、aiohttp 

        aiohttp是可以支持异步请求的一个请求库,需要和asyncio配合使用,实现真正的异步请求。
        将上面的requests进行改写,代码如下:

import asyncio
from loguru import logger
import aiohttp
import time

start = time.time()
async def get_res(url,headers,proxies):
    for i in range(3):
        try:
            async with aiohttp.ClientSession() as session:
                res = await session.get(url,proxy=proxies,headers=headers,timeout=5)
                if res and res.status == 200:
                    return await res.text()
        except:
            logger.warning('')

async def IPtest():
    url = "https://ipinfo.io/widget"
    headers = {
        "accept": "*/*",
        "authority": "ipinfo.io",
        "referer": "https://ipinfo.io/",
        "User-Agent": "Mozilla/5.0 (iPhone; CPU iPhone OS 10_3_3 like Mac OS X) AppleWebKit/603.3.8 (KHTML, like Gecko) Mobile/14G60 MicroMessenger/6.5.19 NetType/4G Language/zh_TW",
    }
    proxies = "代理"
    res = await get_res(url,headers,proxies)
    if res:
        logger.success("success")

tasks = [asyncio.ensure_future(IPtest()) for _ in range (10)]
loop = asyncio.get_event_loop()
loop.run_until_complete(asyncio.wait(tasks))
end = time.time()
print(end-start)

         同样是10个事件,aiohttp的速度也快太多了?

         但是,有几个需要注意的点:
                1、aiohttp再导入的时候,必须导入asyncio。因为异步爬取需要asyncio提供协程的事件循环。
                2、 异步方法需要用async修饰。
                3、with  as  也需要async来修饰。
                4、协程如果有数据返回需要await修饰。

         这里就简单的说一下协程和aiohttp。

 

本文含有隐藏内容,请 开通VIP 后查看

网站公告

今日签到

点亮在社区的每一天
去签到