在 Scrapy 中为特定请求加延迟
使用 Scrapy 抓取页面,有时候不想全局 DOWNLOAD_DELAY,而是只让某些请求慢一点(比如翻页、访问敏感接口)。
下面是一个按请求定制 delay的小方案,方便以后直接抄。
核心思路
- 写一个 Downloader Middleware
- 从
request.meta里读一个自定义字段:delay_request_by(单位:秒) - 如果存在,就用 Twisted 的
reactor.callLater暂停这次请求一会儿再继续。
Downloader Middleware
middlewares.py
from twisted.internet.defer import Deferred
from twisted.internet import reactor
class DelayedRequestsMiddleware(object):
# reference from: https://stackoverflow.com/questions/19135875/add-a-delay-to-a-specific-scrapy-request
def process_request(self, request, spider):
delay_s = request.meta.get('delay_request_by', None)
if not delay_s:
return # 没有设置就直接放行
deferred = Deferred()
reactor.callLater(delay_s, deferred.callback, None)
return deferred # 返回 Deferred,让 Scrapy 等待
在 settings.py 中启用
DOWNLOADER_MIDDLEWARES = {
'myproject.middlewares.DelayedRequestsMiddleware': 543,
}
把
myproject.middlewares换成自己项目的实际路径即可。
在 Spider 里为特定请求加延迟
spider.py
class SomeSpider(scrapy.Spider):
name = 'some-spider'
# ...
def parse(self, response):
# ...
yield scrapy.Request(
next_page,
callback=self.parse,
meta={'delay_request_by': 5} # 这里指定延迟 5 秒
)
# ...
- 不需要延迟的请求:不要带
delay_request_by,或者设为None。 - 需要特殊照顾的请求:直接在
meta里带上秒数即可。