8

我想为我在蜘蛛的 start_urls 中设置的每个 url 创建单独的输出文件,或者想以某种方式拆分输出文件 start url 明智。

以下是我的蜘蛛的 start_urls

start_urls = ['http://www.dmoz.org/Arts/', 'http://www.dmoz.org/Business/', 'http://www.dmoz.org/Computers/']

我想创建单独的输出文件,如

Arts.xml
Business.xml
Computers.xml

我不知道该怎么做。我正在考虑通过在项目管道类的 spider_opened 方法中实现一些类似的东西来实现这一点,

import re
from scrapy import signals
from scrapy.contrib.exporter import XmlItemExporter

class CleanDataPipeline(object):
    def __init__(self):
        self.cnt = 0
        self.filename = ''

    @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):
        referer_url = response.request.headers.get('referer', None)
        if referer_url in spider.start_urls:
            catname = re.search(r'/(.*)$', referer_url, re.I)
            self.filename = catname.group(1)

        file = open('output/' + str(self.cnt) + '_' + self.filename + '.xml', 'w+b')
        self.exporter = XmlItemExporter(file)
        self.exporter.start_exporting()

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

    def process_item(self, item, spider):
        self.cnt = self.cnt + 1
        self.spider_closed(spider)
        self.spider_opened(spider)
        self.exporter.export_item(item)
        return item

我试图在 start_urls 列表中找到每个抓取项目的引用 url。如果在 start_urls 中找到引用 URL,则将使用该引用 URL 创建文件名。但问题是如何在 spider_opened() 方法中访问响应对象。如果我可以在那里访问它,我可以基于它创建文件。

有什么帮助可以找到执行此操作的方法吗?提前致谢!

4

3 回答 3

5

我会实施一种更明确的方法(未经测试):

  • 配置可能的类别列表settings.py

    CATEGORIES = ['Arts', 'Business', 'Computers']
    
  • start_urls根据设置定义您的

    start_urls = ['http://www.dmoz.org/%s' % category for category in settings.CATEGORIES]
    
  • 添加category FieldItem班级

  • 在蜘蛛的 parse 方法中category根据当前设置字段response.url,例如:

    def parse(self, response):
         ...
         item['category'] = next(category for category in settings.CATEGORIES if category in response.url)
         ...
    
  • 在管道中为所有类别打开导出器,并根据以下内容选择要使用的导出器item['category']

    def spider_opened(self, spider):
        ...
        self.exporters = {}
        for category in settings.CATEGORIES:
            file = open('output/%s.xml' % category, 'w+b')
            exporter = XmlItemExporter(file)
            exporter.start_exporting()
            self.exporters[category] = exporter
    
    def spider_closed(self, spider):
        for exporter in self.exporters.itervalues(): 
            exporter.finish_exporting()
    
    def process_item(self, item, spider):
        self.exporters[item['category']].export_item(item)
        return item
    

您可能需要对其进行一些调整以使其正常工作,但我希望您明白 - 将类别存储在item正在处理的内部。根据项目类别值选择要导出到的文件。

希望有帮助。

于 2014-05-26T17:17:26.573 回答
1

只要您不将其存储在项目本身中,您就无法真正知道凝视网址。以下解决方案应该适合您:

  • 重新定义make_request_from_url以发送每个Request您制作的起始网址。您可以将其存储metaRequest. 使用以下每个绕过此起始 url Request

  • 一旦您决定将元素传递给管道,请填写项目的起始 urlresponse.meta['start_url']

希望能帮助到你。以下链接可能会有所帮助:

http://doc.scrapy.org/en/latest/topics/spiders.html#scrapy.spider.Spider.make_requests_from_url

http://doc.scrapy.org/en/latest/topics/request-response.html?highlight=meta#passing-additional-data-to-callback-functions

于 2014-05-26T17:13:45.177 回答
0

以下是我在项目中未设置类别的情况下为项目执行的操作:

从命令行传递参数,如下所示:

scrapy crawl reviews_spider -a brand_name=apple

接收参数并设置为 my_spider.py 中的蜘蛛参数

def __init__(self, brand_name, *args, **kwargs):
    self.brand_name = brand_name
    super(ReviewsSpider, self).__init__(*args, **kwargs)

    # i am reading start_urls from an external file depending on the passed argument
    with open('make_urls.json') as f:
        self.start_urls = json.loads(f.read())[self.brand_name]

pipelines.py

class ReviewSummaryItemPipeline(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):
        # change the output file name based on argument
        self.file = open(f'reviews_summary_{spider.brand_name}.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
于 2020-02-10T11:36:58.793 回答