Scrapy 管道以正确的格式导出 csv 文件

Posted

技术标签:

【中文标题】Scrapy 管道以正确的格式导出 csv 文件【英文标题】:Scrapy pipeline to export csv file in the right format 【发布时间】:2015-07-08 16:48:10 【问题描述】:

我根据下面alexce的建议进行了改进。我需要的是如下图。然而,每一行/每一行都应该是一个评论:带有日期、评分、评论文本和链接。

我需要让项目处理器处理每个页面的每个评论。 目前 TakeFirst() 只对页面进行第一次审查。所以 10 页,我只有 10 行/行,如下图。

蜘蛛代码如下:

import scrapy
from amazon.items import AmazonItem

class AmazonSpider(scrapy.Spider):
   name = "amazon"
   allowed_domains = ['amazon.co.uk']
   start_urls = [
    'http://www.amazon.co.uk/product-reviews/B0042EU3A2/'.format(page) for      page in xrange(1,114)

]

def parse(self, response):
    for sel in response.xpath('//*[@id="productReviews"]//tr/td[1]'):
        item = AmazonItem()
        item['rating'] = sel.xpath('div/div[2]/span[1]/span/@title').extract()
        item['date'] = sel.xpath('div/div[2]/span[2]/nobr/text()').extract()
        item['review'] = sel.xpath('div/div[6]/text()').extract()
        item['link'] = sel.xpath('div/div[7]/div[2]/div/div[1]/span[3]/a/@href').extract()

        yield item

【问题讨论】:

您只想在输出中显示评论文本,对吧? @alecxe 不,先生。只是作为一个例子。我想在 excel 中将评级、日期、评论、链接作为 4 个不同的列。谢谢! @alecxe 这是我在下面的尝试。它不起作用。可能是因为我不了解管道的机制。导入 csv 类 CsvWriterPipeline(object): def __init__(self): self.csvwriter = csv.writer(open('amazon.csv', 'wb')) def process_item(self, item, spider): self.csvwriter.writenow (item['rating'], item['date'], item['review'], item['link']) return item 您为什么要自己处理 CSV 导出?您还可以使用 scrapy crawl amazon -t csv -o Output_File.csv 获取包含您的字段的 csv 文件。然后可以将其导入您喜欢的电子表格程序。 如果您在命令行中使用-t csv,格式将为CSV 格式...也许您想尝试一下!?看看documentation。 【参考方案1】:

我从头开始,应该运行以下蜘蛛

scrapy crawl amazon -t csv -o Amazon.csv --loglevel=INFO

以便为我显示打开带有电子表格的 CSV 文件

希望这会有所帮助:-)

import scrapy

class AmazonItem(scrapy.Item):
    rating = scrapy.Field()
    date = scrapy.Field()
    review = scrapy.Field()
    link = scrapy.Field()

class AmazonSpider(scrapy.Spider):

    name = "amazon"
    allowed_domains = ['amazon.co.uk']
    start_urls = ['http://www.amazon.co.uk/product-reviews/B0042EU3A2/' ]

    def parse(self, response):

        for sel in response.xpath('//table[@id="productReviews"]//tr/td/div'):

            item = AmazonItem()
            item['rating'] = sel.xpath('./div/span/span/span/text()').extract()
            item['date'] = sel.xpath('./div/span/nobr/text()').extract()
            item['review'] = sel.xpath('./div[@class="reviewText"]/text()').extract()
            item['link'] = sel.xpath('.//a[contains(.,"Permalink")]/@href').extract()
            yield item

        xpath_Next_Page = './/table[@id="productReviews"]/following::*//span[@class="paging"]/a[contains(.,"Next")]/@href'
        if response.xpath(xpath_Next_Page):
            url_Next_Page = response.xpath(xpath_Next_Page).extract()[0]
            request = scrapy.Request(url_Next_Page, callback=self.parse)
            yield request

【讨论】:

你太棒了!!!谢谢!它就像一个魅力。有时我会在这里和那里错过链接/网址。不过没什么大不了的,我现在可以继续下一步进行后期数据处理!【参考方案2】:

如果使用 -t csv(由 Frank 在 cmets 中提出)由于某种原因对您不起作用,您始终可以直接使用内置的 CsvItemExporter in the custom pipeline,例如:

from scrapy import signals
from scrapy.contrib.exporter import CsvItemExporter


class AmazonPipeline(object):
    @classmethod
    def from_crawler(cls, crawler):
        pipeline = cls()
        crawler.signals.connect(pipeline.spider_opened, signals.spider_opened)
        crawler.signals.connect(pipeline.spider_closed, signals.spider_closed)
        return pipeline

    def spider_opened(self, spider):
        self.file = open('output.csv', 'w+b')
        self.exporter = CsvItemExporter(self.file)
        self.exporter.start_exporting()

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

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

你需要添加到ITEM_PIPELINES:

ITEM_PIPELINES = 
    'amazon.pipelines.AmazonPipeline': 300

另外,我会使用带有输入和输出处理器的Item Loader 来加入评论文本并用空格替换新行。创建一个ItemLoader 类:

from scrapy.contrib.loader import ItemLoader
from scrapy.contrib.loader.processor import TakeFirst, Join, MapCompose


class AmazonItemLoader(ItemLoader):
    default_output_processor = TakeFirst()

    review_in = MapCompose(lambda x: x.replace("\n", " "))
    review_out = Join()

然后,用它构造一个Item

def parse(self, response):
    for sel in response.xpath('//*[@id="productReviews"]//tr/td[1]'):
        loader = AmazonItemLoader(item=AmazonItem(), selector=sel)

        loader.add_xpath('rating', './/div/div[2]/span[1]/span/@title')
        loader.add_xpath('date', './/div/div[2]/span[2]/nobr/text()')
        loader.add_xpath('review', './/div/div[6]/text()')
        loader.add_xpath('link', './/div/div[7]/div[2]/div/div[1]/span[3]/a/@href')

        yield loader.load_item()

【讨论】:

非常感谢您为我指明方向!我认为装载机是要走的路。我需要进行一些微调,以获得适合我需要的正确布局。如果我被卡住了,我可能还会回到你身边。 ;-) 我又卡住了。我根据您的建议编辑了原始问题以反映改进。仍然无法以我喜欢的方式解决它。你能再检查一遍上面的问题吗?

以上是关于Scrapy 管道以正确的格式导出 csv 文件的主要内容,如果未能解决你的问题,请参考以下文章

以正确的格式将生成的 CSV 保存到服务器作为下载

scrapy pipelines导出各种格式

我应该创建管道以使用scrapy保存文件吗?

爬虫学习笔记—— Scrapy框架:媒体管道

scrapy 配置文件指定如何导出数据

关于导出csv格式文件的身份证号日期的处理