Я написал небольшой пример паука, чтобы проиллюстрировать мою проблему:
class ListEntrySpider(scrapy.Spider):
start_urls = ['https://example.com/lists']
def parse(self, response):
for i in json.dumps(response.text)['ids']:
scrapy.Request(f'https://example.com/list/{i}', callback=self.parse_lists)
def parse_lists(self, response):
for entry in json.dumps(response.text)['list']:
yield ListEntryItem(**entry)
Мне нужно иметь все элементы, которые являются результатом нескольких запросов (все ListEntryItem
s в массиве внутри паука, так что диспетчеризациязапросы, которые зависят от всех элементов.
Моя первая идея состояла в том, чтобы объединить запросы в цепочку и передать оставшиеся идентификаторы и уже извлеченные элементы в метаатрибут запроса, пока не будет достигнут последний запрос.
class ListEntrySpider(scrapy.Spider):
start_urls = ['https://example.com/lists']
def parse(self, response):
ids = json.dumps(response.text)['ids']
yield self._create_request(ids, [])
def parse_lists(self, response):
self._create_request(response.meta['ids'], response.meta['items'].extend(list(self._extract_lists(response))))
def finish(self, response):
items = response.meta['items'].extend(list(self._extract_lists(response)))
def _extract_lists(self, response):
for entry in json.dumps(response.text)['list']:
yield ListEntryItem(**entry)
def _create_request(self, ids: list, items: List[ListEntryItem]):
i = ids.pop(0)
return scrapy.Request(
f'https://example.com/list/{i}',
meta={'ids': ids, 'items': items},
callback=self.parse_lists if len(ids) > 1 else self.finish
)
Как видите, мое решение выглядит очень сложным. Я ищу что-то более читаемое и менее сложное.