2011-10-20 3 views
2

J'ai passé pas mal de temps à passer en revue la documentation et les tutoriels de Scrapy, et depuis, je me suis branché sur un crawler très basique. Cependant, je ne suis pas en mesure d'obtenir la sortie dans un fichier JSON. J'ai l'impression qu'il me manque quelque chose d'évident, mais je n'ai pas été capable de renverser les choses après avoir regardé un certain nombre d'autres exemples, et essayé plusieurs choses différentes.Scrapy :: Problèmes avec l'export JSON

Pour être complet, j'inclurai tout le code approprié. Ce que j'essaie d'obtenir ici, ce sont des éléments spécifiques et leurs prix associés. Les prix changeront assez souvent, et les articles changeront avec une fréquence beaucoup plus basse.

Voici mon items.py:

class CartItems(Item): 
    url = Field() 
    name = Field() 
    price = Field() 

Et voici l'araignée:

from scrapy.selector import HtmlXPathSelector                                   
from scrapy.contrib.spiders import CrawlSpider, Rule 
from scrapy.item import Item, Field 

from Example.items import CartItems 

class DomainSpider(CrawlSpider): 
    name = 'example.com' 
    allowed_domains = ['example.com'] 
    start_urls = ['http://www.example.com/path/to/desired/page'] 


    def parse(self, response): 
     hxs = HtmlXPathSelector(response) 
     cart = CartItems() 
     cart['url'] = hxs.select('//title/text()').extract() 
     cart['name'] = hxs.select('//td/text()').extract()[1] 
     cart['price'] = hxs.select('//td/text()').extract()[2] 
     return cart 

Si par exemple je lance hxs.select ('// td/text()') .extract() [1] de la coquille Scrapy sur l'URL http://www.example.com/path/to/desired/page, je reçois la réponse suivante:

u'Text field I am trying to download' 

EDIT:Ok, donc j'ai écrit un pipeline qui suit celui que j'ai trouvé dans le wiki (j'ai raté cette section quand j'ai creusé ces derniers jours), juste modifié pour utiliser JSON au lieu de XML.

from scrapy.xlib.pydispatch import dispatcher 
from scrapy import signals 
from scrapy.contrib.exporter import JsonItemExporter 

class JsonExportPipeline(object): 

    def __init__(self): 
     dispatcher.connect(self.spider_opened, signals.spider_opened) 
     dispatcher.connect(self.spider_closed, signals.spider_closed) 
     self.files = {} 

    def spider_opened(self, spider): 
     file = open('%s_items.json' % spider.name, 'w+b') 
     self.files[spider] = file 
     self.exporter = JsonItemExporter(file) 
     self.exporter.start_exporting() 

    def spider_closed(self, spider): 
     self.exporter.finish_exporting() 
     file = self.files.pop(spider) 
     file.close() 

    def process_item(self, item, spider): 
     self.exporter.export_item(item) 
     return item 

Cela fait un fichier de sortie "example.com_items.json", mais tout ce qu'il contient est "[]". Donc, quelque chose ne va pas encore ici. Est-ce le problème avec l'araignée, ou le pipeline n'est pas fait correctement? Clairement, il me manque quelque chose ici, donc si quelqu'un pouvait me pousser dans la bonne direction, ou me lier tous les exemples qui pourraient aider, ce serait très apprécié.

Répondre

1

JsonItemExporter est assez simple:

class JsonItemExporter(JsonLinesItemExporter): 

    def __init__(self, file, **kwargs): 
     self._configure(kwargs) 
     self.file = file 
     self.encoder = json.JSONEncoder(**kwargs) 
     self.first_item = True 

    def start_exporting(self): 
     self.file.write("[") 

    def finish_exporting(self): 
     self.file.write("]") 

    def export_item(self, item): 
     if self.first_item: 
      self.first_item = False 
     else: 
      self.file.write(',\n') 
     itemdict = dict(self._get_serialized_fields(item)) 
     self.file.write(self.encoder.encode(itemdict)) 

Donc, j'ai deux conclusions:

  1. fichier est créé - votre pipeline est actif et crochets spider_opened et spider_closed événements.

  2. process_item n'est jamais appelé. Peut-être qu'aucun article n'est éraflé, donc aucun article n'est passé à ce pipeline?

En outre, je pense qu'il ya un bug dans le code:

def spider_opened(self, spider): 
    file = open('%s_items.json' % spider.name, 'w+b') 
    self.files[spider] = file 
    self.exporter = JsonItemExporter(file) 
    self.exporter.start_exporting() 

self.exporter = JsonItemExporter(file) - ne pas dire qu'il n'y a qu'un seul exportateur est actif tout le temps? Une fois qu'une araignée est ouverte, vous créez un exportateur. Pendant que cette araignée est active, une autre peut s'ouvrir et self.exporter sera remplacée par un nouvel exportateur.

1

J'ai copié votre code depuis JsonExportPipeline et testé sur ma machine. Cela fonctionne très bien avec mon araignée.

Donc, je pense que vous devriez vérifier la page.Peut-être que votre fonction d'analyse a quelque chose de mal à extraire le contenu. Quelle est la fonction ci-dessous:

def parse(self, response): 
    hxs = HtmlXPathSelector(response) 
    cart = CartItems() 
    cart['url'] = hxs.select('//title/text()').extract() 
    cart['name'] = hxs.select('//td/text()').extract()[1] 
    cart['price'] = hxs.select('//td/text()').extract()[2] 
    return cart 
+0

a travaillé pour moi aussi –