Python中使用requests替代scrapy下载器速度很慢,如何优化?

class MyDownloaderMiddleware(object):
def process_request(self, request, spider):
    res = requests.get(request.url)
    return HtmlResponse(request.url, body=res.content, encoding='utf-8', request=request)

scrapy 的下载器调教起来不如 requests 方便,所以想用 requests 替代


Python中使用requests替代scrapy下载器速度很慢,如何优化?

16 回复

因为你这是一个同步操作,用 deferreds


用requests替代Scrapy下载器慢是正常的,Scrapy内置了异步并发和连接复用机制。要提速,直接用aiohttp搞异步并发最直接。

import aiohttp
import asyncio
from time import time

async def fetch(session, url):
    async with session.get(url) as response:
        return await response.text()

async def main():
    urls = ['http://example.com/page{}'.format(i) for i in range(100)]
    
    connector = aiohttp.TCPConnector(limit=50)  # 调大并发连接数
    timeout = aiohttp.ClientTimeout(total=30)
    
    async with aiohttp.ClientSession(connector=connector, timeout=timeout) as session:
        tasks = [fetch(session, url) for url in urls]
        results = await asyncio.gather(*tasks, return_exceptions=True)
        
        for url, result in zip(urls, results):
            if isinstance(result, Exception):
                print(f"Failed {url}: {result}")
            else:
                print(f"Got {url}: {len(result)} chars")

if __name__ == '__main__':
    start = time()
    asyncio.run(main())
    print(f"Time: {time() - start:.2f}s")

关键点:

  1. 用aiohttp替代requests:原生支持异步,比requests快一个数量级
  2. 调大TCPConnector的limit参数:默认是100,根据机器性能可以调到200-500
  3. 设置合理的timeout:避免单个请求卡住整个流程
  4. 批量使用asyncio.gather:一次性并发多个请求

如果非要坚持用requests,可以用ThreadPoolExecutor搞线程池,但效果不如aiohttp:

from concurrent.futures import ThreadPoolExecutor
import requests

def fetch(url):
    return requests.get(url).text

with ThreadPoolExecutor(max_workers=50) as executor:
    results = list(executor.map(fetch, urls))

简单说就是换异步库或者上线程池。

又想像同步一样逻辑清晰,又想有异步一样的性能,貌似很难调和呢……

不要用 requests.get !

用同一个 requests.Session ,你能提速一倍以上!

能分享个 demo 不,文档啃的太慢
一直没研究锅 twisted
实际代码中用的 requests.Session ,但速度比原生还是差的太多

twisted 的确有点啰嗦……

参考 scrapy 源码啊。日难看的,不想看第二遍

找到相关源码了 scrapy/core/downloader/handlers/init.py
太别扭了

Twisted 我硬是没学会。。有一些门槛。。

面向需求学习 ←_←

你这是在乱搞啊,下载中间件是负责修改每个 request 和 response 的,是不做下载这个动作的!你在里面加一个 requests.get 操作,等于每个网页你都下载了两遍,而且这个 get 操作还是同步的!!

不好意思没认真看,下载了两遍是我说错的,你在 process_request 里返回了 response ,那 scrapy 就不会再去下载这个网页,但这样,并发就完全没有了,跟单线程用 requests 没什么区别

嗯,所以需要重写下载器,方便 twisted 异步调用

请问楼主找到好的解决方法了么,有没有 demo 提供参考一下。

回到顶部