Python Scrapy如何在不同的文件中保存数据

2024-05-04 18:05:10 发布

您现在位置:Python中文网/ 问答频道 /正文

我想将http://quotes.toscrape.com/中的每个引号保存到csv文件中(2个字段:作者,引号)。另一个必要条件是将这些引号保存在不同的文件中,这些文件由它们所在的页面分开。ie:(page1.csv,page2.csv…)。我试图通过在我的spider中的custom_settings属性中声明提要导出来实现这一点,如下所示。但是,这甚至不会生成名为page-1.csv的文件。我是一个完全初学者使用刮痧,请尝试解释假设我知道很少或什么都没有

import scrapy
import urllib

class spidey(scrapy.Spider):
    name = "idk"
    start_urls = [
        "http://quotes.toscrape.com/"
    ]

    custom_settings = {
        'FEEDS' : {
            'file://page-1.csv' : { #edit: uri needs to be absolute path
                'format' : 'csv',
                'store_empty' : True
            }
        },
        'FEED_EXPORT_ENCODING' : 'utf-8',
        'FEED_EXPORT_FIELDS' : ['author', 'quote']
    }
    

    def parse(self, response):
        for qts in response.xpath("//*[@class=\"quote\"]"):
            author = qts.xpath("./span[2]/small/text()").get()
            quote = qts.xpath("./*[@class=\"text\"]/text()").get()
            yield {
                'author' : author,
                'quote' : quote
                }

        next_pg = response.xpath('//li[@class="next"]/a/@href').get()      
        if next_pg is not None:
            next_pg = urllib.parse.urljoin(self.start_urls[0], next_pg)
            yield scrapy.Request(next_pg, self.parse)

我是如何运行爬虫的:scrapy crawl idk 作为一个补充问题,我需要覆盖我的文件,而不是像指定-o标志时那样附加文件。是否可以在不必手动检查/删除spider中预先存在的文件的情况下执行此操作


Tags: 文件csvtextselfparseresponsexpath引号
1条回答
网友
1楼 · 发布于 2024-05-04 18:05:10

“设置”不支持将项目保存到以您在其中找到的页面命名的文件中(afaik)。如果您想实现这一点,您可以使用python的open函数和csv.writer方法中的parse为其创建自己的功能。另一种选择是编写一个item pipeline,它为不同的文件管理不同的item exporters

但是,您可以使用设置来限制具有^{}设置的文件中的项目数,该设置自Scrapy版本2.3以来一直受支持。
从Scrapy 2.4开始,也可以进行覆盖而不是追加到文件。在FEEDS中,您可以将overwrite设置为True,如下所示

如果将custom_settings替换为以下内容,它将生成包含10个项目的文件,每个项目名为page-,后面是batch_id,以一个项目开头。因此,您的前3个文件将命名为page-1.csv、page-2.csv和page-3.csv

    custom_settings = {
        'FEED_EXPORT_BATCH_ITEM_COUNT': 10,
        'FEEDS' : {
            'page-%(batch_id)d.csv' : {
                'format' : 'csv',
                'store_empty' : True,
                'overwrite': True
            }
        }
    }

作为管道实施

如果希望使用项目管道实现此功能,可以将当前所在的页码保存在返回的字典中,然后由项目管道处理和删除

您的pipelines.py(基于this example)中的管道可能如下所示:

from scrapy.exporters import CsvItemExporter


class PerFilenameExportPipeline:
    """Distribute items across multiple CSV files according to their 'page' field"""

    def open_spider(self, spider):
        self.filename_to_exporter = {}

    def close_spider(self, spider):
        for exporter in self.filename_to_exporter.values():
            exporter.finish_exporting()

    def _exporter_for_item(self, item):
        filename = 'page-' + str(item['page_no'])
        del item['page_no']
        if filename not in self.filename_to_exporter:
            f = open(f'{filename}.csv', 'wb')
            exporter = CsvItemExporter(f)
            exporter.start_exporting()
            self.filename_to_exporter[filename] = exporter
        return self.filename_to_exporter[filename]

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

然后,您需要向爬行器添加一个例程来获取您所在的页面,并在custom_settings中设置管道,您可以按照以下操作:

import scrapy
from ..pipelines import PerFilenameExportPipeline


class spidey(scrapy.Spider):
    name = "idk"
    custom_settings = {
        'ITEM_PIPELINES': {
            PerFilenameExportPipeline: 100
        }
    }
    
    def start_requests(self):
        yield scrapy.Request("http://quotes.toscrape.com/", cb_kwargs={'page_no': 1})

    def parse(self, response, page_no):
        for qts in response.xpath("//*[@class=\"quote\"]"):
            yield {
                'page_no': page_no,
                'author' : qts.xpath("./span[2]/small/text()").get(),
                'quote' : qts.xpath("./*[@class=\"text\"]/text()").get()
            }

        next_pg = response.xpath('//li[@class="next"]/a/@href').get()      
        if next_pg is not None:
            yield response.follow(next_pg, cb_kwargs={'page_no': page_no + 1})

然而,这有一个问题。由于我无法理解的原因,最后一个文件(page-10.csv)保持为空。我问过为什么会这样

相关问题 更多 >