Как заполнить scrapy.Field как словарь
Я строю скребок для http://www.apkmirror.com/, используя Scrapy (с пауком SitemapSpider). Пока что работают следующие:
DEBUG = True
from scrapy.spiders import SitemapSpider
from apkmirror_scraper.items import ApkmirrorScraperItem
class ApkmirrorSitemapSpider(SitemapSpider):
name = 'apkmirror-spider'
sitemap_urls = ['http://www.apkmirror.com/sitemap_index.xml']
sitemap_rules = [(r'.*-android-apk-download/$', 'parse')]
if DEBUG:
custom_settings = {'CLOSESPIDER_PAGECOUNT': 20}
def parse(self, response):
item = ApkmirrorScraperItem()
item['url'] = response.url
item['title'] = response.xpath('//h1[@title]/text()').extract_first()
item['developer'] = response.xpath('//h3[@title]/a/text()').extract_first()
return item
где ApkMirrorScraperItem
определяется в items.py
следующее:
class ApkmirrorScraperItem(scrapy.Item):
url = scrapy.Field()
title = scrapy.Field()
developer = scrapy.Field()
Результирующий вывод JSON, если я запускаю его из каталога проекта с помощью команды
scrapy crawl apkmirror-spider -o data.json
массив JSON-словарей с ключами url
, title
, а также developer
и соответствующие строки в качестве значений. Я хотел бы изменить это, однако, чтобы значение developer
сам по себе словарь с name
поле, так что я могу заполнить его так:
item['developer']['name'] = response.xpath('//h3[@title]/a/text()').extract_first()
Однако, если я попробую это, я получу KeyError
с, также если я инициализирую developer
"s Field
(который является dict
Согласно https://doc.scrapy.org/en/latest/topics/items.html) как developer = scrapy.Field(name=None)
, Как я могу пойти по этому поводу?
1 ответ
Scrapy реализует поля внутренне как диктовки, но это не означает, что к ним следует обращаться как к диктовкам. Когда вы звоните item['developer']
что вы действительно делаете, так это получаете значение поля, а не само поле. Таким образом, если значение еще не было установлено, это вызовет KeyError.
Учитывая это, есть два способа решения вашей проблемы.
Во-первых, просто установите для поля разработчика значение dict:
def parse(self, response):
item = ApkmirrorScraperItem()
item['url'] = response.url
item['title'] = response.xpath('//h1[@title]/text()').extract_first()
item['developer'] = {'name': response.xpath('//h3[@title]/a/text()').extract_first()}
return item
Во-вторых, создайте новый класс Developer и установите значение для разработчика в качестве экземпляра этого класса:
# this can go to items.py
class Developer(scrapy.Item):
name = scrapy.Field()
def parse(self, response):
item = ApkmirrorScraperItem()
item['url'] = response.url
item['title'] = response.xpath('//h1[@title]/text()').extract_first()
dev = Developer()
dev['name'] = response.xpath('//h3[@title]/a/text()').extract_first()
item['developer'] = dev
return item
Надеюсь, поможет:)