Кажется, я нашел решение.
Я решил использовать многопроцессорность, запуская по одному пауку в каждом процессе и передавая задачу в качестве параметра init. В некоторых случаях этот подход может быть неуместным, но он работает для меня.
Я пробовал этот способ раньше, но получал исключение twisted.internet.error.ReactorNotRestartable
. Это было вызвано многократным вызовом start()
метода CrawlerProcess
в каждом процессе, что неверно. Здесь Я нашел простой и понятный пример запуска паука в al oop с использованием обратных вызовов.
Поэтому я разделил свой список tasks
между процессами. Затем внутри метода crawl(tasks)
я создаю цепочку обратных вызовов для многократного запуска моего паука, каждый раз передавая различную задачу в качестве параметра init.
import multiprocessing
import numpy as np
from scrapy.crawler import CrawlerProcess
from scrapy.utils.project import get_project_settings
tasks = [{'start_url': 'https://www.theguardian.com/', 'selenium': False},
{'start_url': 'https://www.nytimes.com/', 'selenium': True}]
def crawl(tasks):
process = CrawlerProcess(get_project_settings())
def run_spider(_, index=0):
if index < len(tasks):
deferred = process.crawl('test_spider', task=tasks[index])
deferred.addCallback(run_spider, index + 1)
return deferred
run_spider(None)
process.start()
def main():
processes = 2
with multiprocessing.Pool(processes) as pool:
pool.map(crawl, np.array_split(tasks, processes))
if __name__ == '__main__':
main()
Код TestSpider
в моем вопроснике должен изменить соответствующим образом, чтобы принять задачу в качестве параметра init.
def __init__(self, task):
scrapy.Spider.__init__(self)
self.task = task
def start_requests(self):
yield scrapy.Request(url=self.task['start_url'], callback=self.parse, meta=self.task)