Как создать пользовательский экспортер Scrapy Item?

Я пытаюсь создать пользовательский экспортер Scrapy Item на основе jsonlinesitemexporter, чтобы я мог немного изменить структуру, которую он производит.

Я прочитал документацию здесь http://doc.scrapy.org/en/latest/topics/exporters.html но в нем не указано, как создать пользовательского экспортера, где его хранить или как связать его с конвейером.

Я определил, как идти на заказ с экспортерами корма, но это не будет соответствовать моим требованиям, как я хочу назвать этого экспортера из моего конвейера.

вот код, который я придумал, который был сохранен в файле в корне проекта под названием exporters.py

from scrapy.contrib.exporter import JsonLinesItemExporter

class FanItemExporter(JsonLinesItemExporter):

def __init__(self, file, **kwargs):
    self._configure(kwargs, dont_fail=True)
    self.file = file
    self.encoder = ScrapyJSONEncoder(**kwargs)
    self.first_item = True

def start_exporting(self):
    self.file.write("""{
'product': [""")

def finish_exporting(self):
    self.file.write("]}")

def export_item(self, item):
    if self.first_item:
        self.first_item = False
    else:
        self.file.write(',n')
    itemdict = dict(self._get_serialized_fields(item))
    self.file.write(self.encoder.encode(itemdict))

Я просто попытался вызвать это из моего конвейера с помощью FanItemExporter и попробовать варианты импорта, но это ни к чему не приводит.

1 ответов


это правда, что в документации Scrapy четко не указано, где разместить экспортера номенклатуры. Чтобы использовать экспортер номенклатуры, выполните следующие действия.

  1. выберите класс экспортера товара и импортируйте его в pipeline.py в каталоге проекта. Это может быть заранее определенный экспортер товара (ex. XmlItemExporter) или определенные пользователем (например,FanItemExporter определено в вопросе)
  2. создайте класс конвейера элементов в pipeline.py. Экземпляр импортного экспортером товара в этой класс. Подробности будут объяснены в более поздней части ответа.
  3. теперь зарегистрируйте этот класс конвейера в .

Ниже приводится подробное объяснение каждого шага. Решение вопроса включено в каждый этап.

Шаг 1

  • если используется предварительно определенный класс экспортера номенклатур, импортируйте его из scrapy.exporters модуль.
    Бывший: from scrapy.exporters import XmlItemExporter

  • Если вам нужен изготовленный на заказ экспортер, определите пользовательский класс в файле. Я предлагаю разместить класс в . Поместите этот файл в папку проекта (где settings.py, items.py проживают).

    при создании нового подкласса всегда полезно импортировать BaseItemExporter. Было бы уместно, если бы мы намеревались полностью изменить функциональность. Однако в этом вопросе большая часть функциональности близка к JsonLinesItemExporter.

следовательно, я прикрепляю две версии одного и того же ItemExporter. Один выдвигается версия BaseItemExporter класс и другой расширяется JsonLinesItemExporter класс

Вариант 1 расширение BaseItemExporter

С BaseItemExporter является родительским классом,start_exporting(), finish_exporting(), export_item() должно быть переопределено в соответствии с нашими потребностями.

from scrapy.exporters import BaseItemExporter
from scrapy.utils.serialize import ScrapyJSONEncoder
from scrapy.utils.python import to_bytes

class FanItemExporter(BaseItemExporter):

    def __init__(self, file, **kwargs):
        self._configure(kwargs, dont_fail=True)
        self.file = file
        self.encoder = ScrapyJSONEncoder(**kwargs)
        self.first_item = True

    def start_exporting(self):
        self.file.write(b'{\'product\': [')

    def finish_exporting(self):
        self.file.write(b'\n]}')

    def export_item(self, item):
        if self.first_item:
            self.first_item = False
        else:
            self.file.write(b',\n')
        itemdict = dict(self._get_serialized_fields(item))
        self.file.write(to_bytes(self.encoder.encode(itemdict)))

Вариант 2 расширение JsonLinesItemExporter

JsonLinesItemExporter обеспечивает точно такую же реализацию export_item() метод. Поэтому только start_exporting() и finish_exporting() методы отмененный.

реализация JsonLinesItemExporter можно увидеть в папке python_dir\pkgs\scrapy-1.1.0-py35_0\Lib\site-packages\scrapy\exporters.py

from scrapy.exporters import JsonItemExporter

class FanItemExporter(JsonItemExporter):

    def __init__(self, file, **kwargs):
        # To initialize the object we use JsonItemExporter's constructor
        super().__init__(file)

    def start_exporting(self):
        self.file.write(b'{\'product\': [')

    def finish_exporting(self):
        self.file.write(b'\n]}')

Примечание: при записи данных в файл важно отметить, что стандартные классы экспортеров номенклатур ожидают двоичные файлы. Следовательно, мы должны открыть файл в двоичном режиме (b). По той же причине, write() метод в обеих версиях write bytes в файл.

Шаг 2

создание конвейера элементов класс.

from project_name.exporters import FanItemExporter

class FanExportPipeline(object):
    def __init__(self, file_name):
        # Storing output filename
        self.file_name = file_name
        # Creating a file handle and setting it to None
        self.file_handle = None

    @classmethod
    def from_crawler(cls, crawler):
        # getting the value of FILE_NAME field from settings.py
        output_file_name = crawler.settings.get('FILE_NAME')

        # cls() calls FanExportPipeline's constructor
        # Returning a FanExportPipeline object
        return cls(output_file_name)

    def open_spider(self, spider):
        print('Custom export opened')

        # Opening file in binary-write mode
        file = open(self.file_name, 'wb')
        self.file_handle = file

        # Creating a FanItemExporter object and initiating export
        self.exporter = FanItemExporter(file)
        self.exporter.start_exporting()

    def close_spider(self, spider):
        print('Custom Exporter closed')

        # Ending the export to file from FanItemExport object
        self.exporter.finish_exporting()

        # Closing the opened output file
        self.file_handle.close()

    def process_item(self, item, spider):
        # passing the item to FanItemExporter object for expoting to file
        self.exporter.export_item(item)
        return item

Шаг 3

теперь, когда мы определили конвейер экспорта товара, мы должны зарегистрировать конвейер в . Мы также используем поле FILE_NAME С . В этом поле содержится имя выходного файла.

добавьте следующие строки в .

FILE_NAME = 'path/outputfile.ext'
ITEM_PIPELINES = {
    'project_name.pipelines.FanExportPipeline' : 600,
}

если ITEM_PIPELINES уже раскомментирован, затем добавьте следующую строку в ITEM_PIPELINES словарь.

'project_name.pipelines.FanExportPipeline' : 600,

этот путь, мы можем создать изготовленные на заказ трубопроводы экспорта деталя и использовать их в нашем проекте.