【问题标题】:scrapy - seperate output file per starurlscrapy - 每个starurl的单独输出文件
【发布时间】:2018-05-01 20:45:27
【问题描述】:

我有一个运行良好的爬虫:

`# -*- coding: utf-8 -*-
import scrapy


class AllCategoriesSpider(scrapy.Spider):
    name = 'vieles'
    allowed_domains = ['examplewiki.de']
    start_urls = ['http://www.exampleregelwiki.de/index.php/categoryA.html','http://www.exampleregelwiki.de/index.php/categoryB.html','http://www.exampleregelwiki.de/index.php/categoryC.html',]

#"Titel": :

def parse(self, response):
    urls = response.css('a.ulSubMenu::attr(href)').extract() # links to den subpages
    for url in urls:
        url = response.urljoin(url)
        yield scrapy.Request(url=url,callback=self.parse_details)

def parse_details(self,response):
    yield {
        "Titel": response.css("li.active.last::text").extract(),
        "Content": response.css('div.ce_text.first.last.block').extract(),
    }

` 与

scrapy runpider spider.py -o dat.json 它将所有信息保存到 dat.json

我希望每个起始 url 有一个输出文件 categoryA.json categoryB.json 等等。

similar question 没有得到答复,我无法复制 this answer 并且我无法从 suggestions there 中学习。

如何实现拥有多个输出文件的目标,每个 starturl 一个? 我只想运行一个命令/shellscript/文件来实现这一点。

【问题讨论】:

    标签: python python-3.x web-scraping scrapy scrapy-spider


    【解决方案1】:

    您没有在代码中使用真实的 url,所以我使用我的页面进行测试。
    我必须更改 css 选择器并使用不同的字段。

    我将它保存为csv,因为它更容易附加数据。
    JSON 需要从文件中读取所有项目,添加新项目并将所有项目再次保存在同一个文件中。


    我创建了额外的字段Category 稍后将其用作管道中的文件名

    items.py

    import scrapy
    
    class CategoryItem(scrapy.Item):
        Title = scrapy.Field()
        Date = scrapy.Field()
        # extra field use later as filename 
        Category = scrapy.Field()
    

    在蜘蛛中,我从 url 获取类别并使用 meta in Request 发送到 parse_details
    parse_details 中,我将category 添加到Item

    spiders/example.py

    import scrapy
    
    class ExampleSpider(scrapy.Spider):
        name = 'example'
        allowed_domains = ['blog.furas.pl']
        start_urls = ['http://blog.furas.pl/category/python.html','http://blog.furas.pl/category/html.html','http://blog.furas.pl/category/linux.html']
    
        def parse(self, response):
    
            # get category from url
            category = response.url.split('/')[-1][:-5]
    
            urls = response.css('article a::attr(href)').extract() # links to den subpages
    
            for url in urls:
                # skip some urls
                if ('/tag/' not in url) and ('/category/' not in url):
                    url = response.urljoin(url)
                    # add category (as meta) to send it to callback function
                    yield scrapy.Request(url=url, callback=self.parse_details, meta={'category': category})
    
        def parse_details(self, response):
    
            # get category
            category = response.meta['category']
    
            # get only first title (or empty string '') and strip it
            title = response.css('h1.entry-title a::text').extract_first('')
            title = title.strip()
    
            # get only first date (or empty string '') and strip it
            date = response.css('.published::text').extract_first('')
            date = date.strip()
    
            yield {
                'Title': title,
                'Date': date,
                'Category': category,
            }
    

    在管道中,我得到category 并使用它打开文件以追加和保存项目。

    pipelines.py

    import csv
    
    class CategoryPipeline(object):
    
        def process_item(self, item, spider):
    
            # get category and use it as filename
            filename = item['Category'] + '.csv'
    
            # open file for appending
            with open(filename, 'a') as f:
                writer = csv.writer(f)
    
                # write only selected elements 
                row = [item['Title'], item['Date']]
                writer.writerow(row)
    
                #write all data in row
                #warning: item is dictionary so item.values() don't have to return always values in the same order
                #writer.writerow(item.values())
    
            return item
    

    在设置中,我必须取消注释管道才能激活它。

    settings.py

    ITEM_PIPELINES = {
        'category.pipelines.CategoryPipeline': 300,
    }
    

    GitHub 上的完整代码:python-examples/scrapy/save-categories-in-separated-files


    顺便说一句:我认为您可以直接在parse_details 中写入文件。

    【讨论】:

    • 我从来没有做过项目,只做过蜘蛛,所以你的回答有点超出我的想象。如何使用 parse_details?
    • 默认情况下Request 从页面获取数据并执行parse(),但在您的代码中您执行Request 以获取subpabe 并执行parse_details() (scrapy.Request(..., callback=self.parse_details,...))。如果您没有使用项目,那么您可以直接在parse_details 中使用with open(...) ...,您将不需要CategoryPipeline
    • 你的意思是我可以在解析详细信息函数中直接写入文件吗?
    • 是的,你可以在函数parse_details中写文件——这是你的代码,没有人能阻止你;)
    猜你喜欢
    • 2020-06-22
    • 2014-07-15
    • 2013-10-01
    • 2012-08-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多