2017-04-13 3 views
3

Ich baue einen Schaber für www.apkmirror.com mit Scrapy (mit der SitemapSpider Spider). Bisher wurden folgende Werke:So füllen Sie ein scrapy.Field als Wörterbuch

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 

wo die ApkMirrorScraperItem in items.py ist wie folgt definiert:

class ApkmirrorScraperItem(scrapy.Item): 
    url = scrapy.Field() 
    title = scrapy.Field() 
    developer = scrapy.Field() 

Die resultierende JSON ausgegeben, wenn ich es aus dem Projektverzeichnis laufen mit dem Befehl

scrapy crawl apkmirror-spider -o data.json 

ist ein Array von JSON-Wörterbüchern mit den Schlüsseln url, title und developer und t Er korrespondiert mit Strings als Werten. Ich möchte, dies ändern, aber so, dass der Wert von developer selbst ein Wörterbuch mit einem name Feld, so dass ich es so bevölkern können:

item['developer']['name'] = response.xpath('//h3[@title]/a/text()').extract_first() 

Allerdings, wenn ich das versuche ich bekomme KeyError s , auch wenn ich die developer 's Field (die eine dict nach https://doc.scrapy.org/en/latest/topics/items.html#item-fields ist) als developer = scrapy.Field(name=None) initialisieren. Wie kann ich das tun?

Antwort

3

Scrapy implementiert Felder intern als dicts, aber dies bedeutet nicht, dass sie als dicts aufgerufen werden sollten. Wenn Sie item['developer'] anrufen, was Sie wirklich tun, ist die Wert des Feldes, nicht das Feld selbst. Wenn der Wert noch nicht festgelegt wurde, wird ein KeyError ausgelöst.

In Anbetracht dessen gibt es zwei Möglichkeiten, wie Sie Ihr Problem lösen könnten.

Zuerst ein, setzen Sie einfach den Entwickler Feldwert auf einen 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 

zweiten, eine neue Entwickler-Klasse erstellen und den Entwickler Wert eine Instanz dieser Klasse sein:

# 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 

Hoffe es hilft :)

Verwandte Themen