Scrapy :: JSON导出问题

2 投票
2 回答
6168 浏览
提问于 2025-04-17 04:42

我花了不少时间在Scrapy的文档和教程上,最近一直在努力做一个非常基础的爬虫。不过,我一直无法把输出结果保存到一个JSON文件里。我觉得我可能漏掉了什么明显的东西,但看了很多其他的例子后,还是没能找到解决办法,尝试了几种不同的方法也没有成功。

为了详细说明,我会把所有相关的代码都贴上来。我想要获取一些特定的商品及其对应的价格。价格会经常变化,而商品的变化频率要低得多。

这是我的items.py文件:

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

这是我的爬虫代码:

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

比如说,如果我在Scrapy的命令行中运行hxs.select('//td/text()').extract()[1],并且访问这个网址 http://www.example.com/path/to/desired/page,我得到的响应是:

u'Text field I am trying to download'

编辑:

好的,我写了一个管道,参考了我在维基上找到的一个(这几天我在翻阅的时候不小心漏掉了这一部分),只是把它改成了使用JSON而不是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

这个确实输出了一个文件“example.com_items.json”,但里面的内容只有“[]”。所以,看来还是哪里不对。问题出在爬虫上,还是管道没有写对呢?显然我还是缺少了一些东西,如果有人能给我一点提示,或者给我一些可能有帮助的例子,那就太感谢了。

2 个回答

1

我把你在JsonExportPipeline上的代码复制到了我的电脑上测试了一下。

结果在我的爬虫上运行得很好。

所以我觉得你应该检查一下网页。

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
1

JsonItemExporter 这个东西其实挺简单的:

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))

所以,我有两个结论:

  1. 文件已经创建 - 说明你的数据处理流程是活跃的,并且在监听 spider_openedspider_closed 这些事件。

  2. process_item 这个函数从来没有被调用过。可能是因为没有抓取到任何数据,所以没有数据被传递到这个处理流程里?

另外,我觉得代码里有个bug:

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) - 这是不是意味着一直只有一个导出器在工作?当一个爬虫启动时,你创建了一个导出器。而在这个爬虫运行的时候,可能会有另一个爬虫启动,这样 self.exporter 就会被新的导出器覆盖掉。

撰写回答