Scrapy: как хранить очищенные данные в разных файлах json за один запуск сканера?

Я использую универсальных пауков со списком нескольких URL-адресов в поле start_urls.

Можно ли экспортировать один файл json для каждого URL-адреса?

Насколько я знаю, можно указать только один путь к одному конкретному выходному файлу.

Любые идеи, как решить эту проблему, приветствуются!

Обновлено: Это мой класс пауков:

import scrapy
from scrapy.linkextractors import LinkExtractor
from scrapy.spiders import CrawlSpider, Rule

class MySpider(CrawlSpider):
    name = 'my_spider'
    start_urls =  start_urls = ['www.domain1.com','www.domain2.com', 
   'www.domain3.com']


    custom_settings = {
                'FEED_EXPORT_ENCODING': 'utf-8',
                'DEPTH_LIMIT': '1',
                'FEED_URI': 'file:///C:/path/to/result.json',
    }

    rules = (
        Rule(LinkExtractor(allow=r"abc"), callback='parse_item', follow=True),
    )

    def parse_item(self, response):
        all_text = response.xpath("//p/text()").getall()

        yield {
            "text": " ".join(all_text),
            "url": response.url,
        }

вам нужно будет создать собственный класс Pipeline с process_item(), который сохранит item в разных файлах. Возможно, потребуется указать URL-адрес с помощью item

furas 17.03.2022 02:12

пример Конвейер, который сохраняет элементы с разными категориями в разных файлах — он использует значение из item для выбора имени файла: furas/примеры-python/scrapy/сохранение-категорий-в-разделенных-файлах

furas 17.03.2022 02:14

вы также можете запустить три отдельных сканера с разными доменами и разными файлами.

furas 17.03.2022 02:19

документация показывает аналогичный конвейер в Экспортеры предметов

furas 17.03.2022 02:46

Хорошо, кажется, что это определенно возможно. Это хорошо знать. Я думаю о лучшем подходе для моего паука. Если бы я добавил его в свой исходный пост, чтобы было легче говорить о том, какой вариант предпочтительнее.

Daniel 17.03.2022 09:34

Я вижу, вы уже получили ответ с кодом - и обе версии кажутся нормальными. Используйте версию, которая вам нравится.

furas 17.03.2022 17:13

Пожалуйста, взгляните на stackoverflow.com/questions/71679403/…. Я поднял вопрос вдогонку.

Daniel 30.03.2022 16:52
Почему в Python есть оператор "pass"?
Почему в Python есть оператор "pass"?
Оператор pass в Python - это простая концепция, которую могут быстро освоить даже новички без опыта программирования.
Некоторые методы, о которых вы не знали, что они существуют в Python
Некоторые методы, о которых вы не знали, что они существуют в Python
Python - самый известный и самый простой в изучении язык в наши дни. Имея широкий спектр применения в области машинного обучения, Data Science,...
Основы Python Часть I
Основы Python Часть I
Вы когда-нибудь задумывались, почему в программах на Python вы видите приведенный ниже код?
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
Алиса и Боб имеют неориентированный граф из n узлов и трех типов ребер:
Оптимизация кода с помощью тернарного оператора Python
Оптимизация кода с помощью тернарного оператора Python
И последнее, что мы хотели бы показать вам, прежде чем двигаться дальше, это
Советы по эффективной веб-разработке с помощью Python
Советы по эффективной веб-разработке с помощью Python
Как веб-разработчик, Python может стать мощным инструментом для создания эффективных и масштабируемых веб-приложений.
0
7
65
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Первый вариант

Вы можете сохранить элементы в пауке как Учебник по скрейпу, например:

import scrapy
import json

DICT = {
    'https://quotes.toscrape.com/page/1/': 'domain1.json',
    'https://quotes.toscrape.com/page/2/': 'domain2.json',
}


class MydomainSpider(scrapy.Spider):
    name = "mydomain"
    start_urls = [
        'https://quotes.toscrape.com/page/1/',
        'https://quotes.toscrape.com/page/2/',
    ]

    def parse(self, response):
        filename = DICT[response.url]
        with open(filename, 'w') as fp:
            json.dump({"content": response.body.decode("utf-8")}, fp)

Переменная DICT предназначена только для указания имени файла JSON, но вы также можете использовать домен в качестве имени файла.

Второй вариант

Вы можете попробовать использовать process_item в pipelines.py следующим образом:

from scrapy.exporters import JsonItemExporter


class SaveJsonPipeline:
    def process_item(self, item, spider):
       filename = item['filename']
       del item['filename']
       JsonItemExporter(open(filename, "wb")).export_item(item)
       return item

item['filename'] для сохранения имени файла для каждого start_url. Вам также нужно установить items.py, например:

import scrapy


class MydomainItem(scrapy.Item):
    filename = scrapy.Field()
    content = scrapy.Field()

твой паук:

import scrapy
from ..items import MydomainItem


DICT = {
    'https://quotes.toscrape.com/page/1/': 'domain1.json',
    'https://quotes.toscrape.com/page/2/': 'domain2.json',
}


class MydomainSpider(scrapy.Spider):
    name = 'mydomain'
    allowed_domains = ['mydomain.com']
    start_urls = [
        'https://quotes.toscrape.com/page/1/',
        'https://quotes.toscrape.com/page/2/',
    ]

    def parse(self, response):
        item = MydomainItem()
        item["filename"] = DICT[response.url]
        item["content"] = response.body.decode("utf-8")
        yield item

Перед запуском вам нужно добавить конвейер в настройках.

ITEM_PIPELINES = {
    'myproject.pipelines.SaveJsonPipeline': 300,
}

Я новичок в Scrapy, и все мои пауки не используют Scrapy.Item и Scrapy.Field. Знаете ли вы, как будет выглядеть ваше решение при использовании yield без Scrapy.Itemи Scrapy.Field?

Daniel 17.03.2022 09:00

Пожалуйста, взгляните на мое редактирование в моем исходном сообщении. Я добавил еще немного информации.

Daniel 17.03.2022 09:07

@Daniel Вы можете использовать обычный словарь item = dict() вместо item = MydomainItem() - и он все равно должен работать

furas 17.03.2022 17:09

@Daniel, ты можешь использовать обычный словарь, как сказал @furas. Вы можете изменить item = MydomainItem() на item = {}, и все тоже работает нормально.

Brenda S. 17.03.2022 20:32

Пожалуйста, взгляните на stackoverflow.com/questions/71679403/…. Я поднял уточняющий вопрос.

Daniel 30.03.2022 16:51

Другие вопросы по теме