Мне нужно сделать тысячи запросов, для авторизации которых требуется токен сеанса.
Одновременная постановка всех запросов приводит к сбою в тысячах запросов, поскольку срок действия маркера сеанса истекает до выдачи более поздних запросов.
Итак, я отправляю разумное количество запросов, которые будут надежно завершены до истечения срока действия токена сеанса.
Когда пакет запросов завершается, срабатывает сигнал spider_idle.
Если требуются дополнительные запросы, обработчик сигнала запрашивает новый маркер сеанса, который будет использоваться со следующей партией запросов.
Это работает при нормальном запуске одного паука или одного паука через CrawlerProcess.
Однако сигнал spider_idle завершается ошибкой, когда несколько пауков проходят через CrawlerProcess.
Один паук выполнит сигнал spider_idle, как и ожидалось, но другие потерпят неудачу с этим исключением:
2019-06-14 10:41:22 [scrapy.utils.signal] ERROR: Error caught on signal handler: <bound method ?.spider_idle of <SpideIdleTest None at 0x7f514b33c550>>
Traceback (most recent call last):
File "/home/loren/.virtualenv/spider_idle_test/local/lib/python2.7/site-packages/scrapy/utils/signal.py", line 30, in send_catch_log
*arguments, **named)
File "/home/loren/.virtualenv/spider_idle_test/local/lib/python2.7/site-packages/pydispatch/robustapply.py", line 55, in robustApply
return receiver(*arguments, **named)
File "fails_with_multiple_spiders.py", line 25, in spider_idle
spider)
File "/home/loren/.virtualenv/spider_idle_test/local/lib/python2.7/site-packages/scrapy/core/engine.py", line 209, in crawl
"Spider %r not opened when crawling: %s" % (spider.name, request)
Я создал репо, который показывает, что spider_idle ведет себя как ожидалось с одним пауком и не работает с несколькими пауками.
https://github.com/loren-magnuson/scrapy_spider_idle_test
Вот версия, которая показывает сбои:
import scrapy
from scrapy.crawler import CrawlerProcess
from scrapy import Request, signals
from scrapy.exceptions import DontCloseSpider
from scrapy.xlib.pydispatch import dispatcher
class SpiderIdleTest(scrapy.Spider):
custom_settings = {
'CONCURRENT_REQUESTS': 1,
'DOWNLOAD_DELAY': 2,
}
def __init__(self):
dispatcher.connect(self.spider_idle, signals.spider_idle)
self.idle_retries = 0
def spider_idle(self, spider):
self.idle_retries += 1
if self.idle_retries < 3:
self.crawler.engine.crawl(
Request('https://www.google.com',
self.parse,
dont_filter=True),
spider)
raise DontCloseSpider("Stayin' alive")
def start_requests(self):
yield Request('https://www.google.com', self.parse)
def parse(self, response):
print(response.css('title::text').extract_first())
process = CrawlerProcess()
process.crawl(SpiderIdleTest)
process.crawl(SpiderIdleTest)
process.crawl(SpiderIdleTest)
process.start()