如何使用Scrapy将抓取的数据导出为可读json

6mw9ycah  于 2022-11-09  发布在  其他
关注(0)|答案(1)|浏览(166)

根据SO,我写了一个spider,把每个域保存到一个单独的json文件中。我必须使用CrawlSpider来访问子链接。
但是这个文件包含了json的数据,不能被pandas读取。它应该有一个很好的和可读的新行分隔的json。但是Scrapy希望导出的json是字节型的。

所需的输出格式为:

{"content": "text", "scrape_date": "36456456456"}
{"content": "text", "scrape_date": "56445435435"}

我的spider.py:

import scrapy
import time
import json
from scrapy.linkextractors import LinkExtractor
from scrapy.spiders import CrawlSpider, Rule
from scrapy.crawler import CrawlerProcess
from urllib.parse import urlparse

DICT = {
    'quotes.toscrape.com': 'domain1.json',
    'stadt-koeln.de': 'domain2.json',
}

class PagingIncremental(CrawlSpider):
    name = "my_spider"

    allowed_domains = ['quotes.toscrape.com', 'stadt-koeln.de']

    start_urls = [
        'https://quotes.toscrape.com/page/1/',
        'https://www.stadt-koeln.de/leben-in-koeln/planen-bauen/bebauungsplaene/aufstellen-eines-bauleitplanes'
    ]

    custom_settings = {
        'DOWNLOAD_DELAY': '0',
        'FEED_EXPORT_ENCODING': 'utf-8',
        'DEPTH_LIMIT': '1',
        'AUTOTHROTTLE_ENABLED': 'True',
        'AUTOTHROTTLE_START_DELAY': '1',
        'AUTOTHROTTLE_MAX_DELAY': '3'
    }
    # Visit all found sublinks
    rules = (
        Rule(LinkExtractor(allow=r""), callback='parse', follow=False),
    )

    def parse(self, response):

        item = {}

        # get domain from each sub page 
        domain = urlparse(response.url).netloc
        domain = domain.replace("www.", "")

        # if domain from DICT above matches with domain from subpage
        # all sublinks are stored in the same output file
        item["filename"] = DICT[domain]
        item["content"] = response.xpath("//p/text()").getall() 
        item['scrape_date'] = int(time.time())

        yield item

if __name__ == "__main__":
    process = CrawlerProcess(settings={
    })

    # process = CrawlerProcess()
    process.crawl(PagingIncremental)
    process.start()

我的pipelines.py

from scrapy.exporters import JsonItemExporter

class SaveJsonPipeline:
    def process_item(self, item, spider):

        filename = item['filename']
        del item['filename']

        # if the file exists it will append the data 
        JsonItemExporter(open(filename, "ab")).export_item(item)

        return item

我的settings.py

ITEM_PIPELINES = {
   '<project_name>.pipelines.SaveJsonPipeline': 300,
}

如果我使用a而不是ab以非二进制格式导出pipelines.py中的数据,Scrapy会说:

JsonItemExporter(open(filename, "a")).export_item(item)
  File "c:\python\lib\site-packages\scrapy\exporters.py", line 135, in export_item
    self.file.write(to_bytes(data, self.encoding))
TypeError: write() argument must be str, not bytes

任何想法和解决方案都将获得奖励!

sqyvllje

sqyvllje1#

您应该使用JsonLinesItemExporter而不是JsonItemExporter来获取分隔行中的每个项目。
不要麻烦bytes,因为文档提到它必须在bytes mode中打开文件。
pandas.read_json()中,您可以使用选项lines=True来读取JSONL(多行JSON):

df = pd.read_json('domain1.json', lines=True)

完整的工作代码。

所有代码都在一个文件中,因此每个人都可以简单地复制和测试它。
我使用'__main__.SaveJsonPipeline'从当前文件加载类。
我还添加了代码来删除content中的空格,并加入一个字符串:
第一个

相关问题