在Scrapy中如何使用aiohttp

  • 当我们从一些代理 IP 供应商购买代理 IP 时,他们可能是提供一个网址供我们查询当前可用的代理 IP。我们周期性访问这个网址,拿到最新的 IP,再分给爬虫使用。

  • 最正确的做法,是单独有一个代理池程序,它负责请求这个网址,获取所有的代理
    IP,然后维护到一个池子里面。爬虫只需要从这个池子里面拿就可以了。

  • 但有时候,因为某些原因,我们可能暂时无法或者暂时没有时间开发代理池程序,于是不得不直接让爬虫去请求代理 IP 供应商提供的网址获取代理
    IP。这个时候我们就面临了一个问题——爬虫应该怎么去请求代理网址?特别是当你使用的是 Scrapy,那么这个问题变得尤为麻烦

  • 我们一般在 Scrapy 的下载器中间件里面设置爬虫的代理,但问题来了,在下载器中间件里面,你怎么发起网络请求?

    于是很多人退而求其次,在下载器中间件里面,用 requests 来请求代理供应商的网址,例如:

import requests
import json
import random

 class ProxyMiddleware:
     def process_request(self, request, spider):
         ip_info = requests.get('代理供应商的网址').json()
         ip_list = ip_info['proxy']
         ip = random.choice(ip_list)
         request.meta['proxy'] = ip
  • 我们知道,Scrapy 是一个异步爬虫框架,而 requests 是一个同步网络库。在 Scrapy 里面运行 requests,会在
    requests 等待请求的时候卡死整个 Scrapy 所有请求,从而拖慢整个爬虫的运行效率。

    当然,你可以在 Scrapy 的爬虫里面,每次发起待爬请求前,先yield
    scrapy.Request(‘代理供应商网址’),请求一次代理供应商的网址,并在对应的回调函数里面拿到代理IP再发正常的请求。但这样的写法,会让爬虫代码变得很混乱。

    为了避免这种混乱,在下载器中间件里面获取代理 IP 当然是最好的,但又不能用 requests,应该如何是好呢?

    实际上,我们可以在 Scrapy 里面,使用 aiohttp,这样既能拿到代理IP,又能不阻塞整个爬虫。

    Scrapy 现在官方已经部分支持 asyncio 异步框架了,所以我们可以直接使用async def重新定义下载器中间件,并在里面使用
    aiohttp 发起网络请求。

    为了说明如何编写代码,我们用 Scrapy 创建一个示例爬虫。正常情况下,这个爬虫使用 5
    个并发,每个请求延迟1秒访问http://exercise.kingname.info/exercise_middleware_ip/并打印网站返回的结果,如下图所示。
    在这里插入图片描述

  • 请求频率和延迟如下图所示:
    在这里插入图片描述
    请求频率接近1秒钟一次。

  • 现在,我们创建一个中间件,在这个中间件里面,使用 requests 请求一个需要延迟 5 秒钟才会返回的网址:
    在这里插入图片描述
    在这里插入图片描述
    从图中可以知道,requests 卡住了整个 Scrapy。在请求这个延迟 5 秒的网址时,Scrapy 无法发起其他的请求。

  • 现在,我们把 requests 替换为 aiohttp,看看效果。

import asyncio
import aiohttp
 
 
 
 
class TestAiohttp:
    async def get_ip(self):
        async with aiohttp.ClientSession() as client:
            resp = await client.get('http://httpbin.org/delay/5')
            result = await resp.json()
            print(result)
 
 
    async def process_request(self, request, spider):
        print('请求一个延迟5秒的网址开始')
        await asyncio.create_task(self.get_ip())
 
 
  • 如下图所示:
    在这里插入图片描述
  • 现在,我们直接运行这个爬虫,理论上应该会遇到一个报错,如下图所示:
    在这里插入图片描述
    这是正常现象,要在 Scrapy 里面启用 asyncio,需要额外在settings.py文件中,添加一行配置:
TWISTED_REACTOR = 'twisted.internet.asyncioreactor.AsyncioSelectorReactor'

  • 添加了这一行配置以后,再次运行爬虫,可以看到效果如下图所示:

在这里插入图片描述
刚刚启动的时候,爬虫会瞬间启动 5 个并发,所以会同时打印出请求一个延迟5秒的网址开始5次。然后稍稍停 5 秒,这 5 个请求几乎同时完成,于是同时打印出这个延迟网址的返回信息。接下来,后面的请求就是每秒一个。

这说明,Scrapy 的异步机制成功启动了。首先第一个请求延迟网址发起以后,由于当前请求数还没有达到最大并发 5,所以立刻就会利用这个等待时间发起第二个请求。由于现在请求数还不够 5 个,于是马上又会发起第三个请求,直到凑够 5 个并发请求为止。

当第一个请求延迟网站返回以后,Scrapy 去请求正式的第一页。在等待第一页返回的过程中,第二个延迟请求完成并返回,于是 Scrapy 去请求正式网址的第二页……

总之,从 Scrapy 打印出的信息可以看出,现在 Scrapy 与 aiohttp 协同工作,异步机制正常运转。

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值