Настраиваемые CSV-заголовки Scrapy для CsvItemExporter - PullRequest
4 голосов
/ 24 мая 2019

Я пытаюсь разобрать и преобразовать XML в CSV. Сложность заключается в том, что заголовки должны точно соответствовать терминам, указанным в документации стороннего анализатора CSV, и содержать пробелы между словами, т. Е. «Заголовок элемента», «Описание элемента» и т. Д.

Поскольку Предметы определены как переменные в items.py, я не могу создавать Предметы, содержащие пробелы, т.е.

Item title = scrapy.Field()

Я пытался добавить в settings.py:

FEED_EXPORT_FIELDS = ["Item title", "Item description"]

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

    class MySpider(XMLFeedSpider):
        name = 'example'
        allowed_domains = ['example.com']
        start_urls = ['http://example.com/feed.xml']
        itertag = 'item'

        def parse_node(self, response, node):
            item = FeedItem()
            item['id'] = node.xpath('//*[name()="g:id"]/text()').get()
            item['title'] = node.xpath('//*[name()="g:title"]/text()').get()
            item['description'] = node.xpath('//*[name()="g:description"]/text()').get()

            return item

Парсер работает нормально, я получаю все данные, которые мне нужны. Проблема только с заголовками CSV.

Есть ли способ легко добавить настраиваемые заголовки, которые не соответствуют именам элементов и могут содержать несколько слов?

Вывод, который я сейчас получаю:

id, title, description
12345, Lorem Ipsum, Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.
12346, Quick Fox, The quick brown fox jumps over the lazy dog.

Желаемый результат должен выглядеть следующим образом:

ID, Item title, Item description
12345, Lorem Ipsum, Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.
12346, Quick Fox, The quick brown fox jumps over the lazy dog.

Вход для тестирования:

<rss>
<channel>
  <title>Example</title>
  <link>http://www.example.com</link>
  <description>Description of Example.com</description>
        <item>
            <g:id>12345</g:id>
            <g:title>Lorem Ipsum</g:title>
            <g:description>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.</g:description>
        </item>
        <item>
            <g:id>12346</g:id>
            <g:title>Quick Fox</g:title>
            <g:description>The quick brown fox jumps over the lazy dog.</g:description>
        </item>
</channel>
</rss>

А это содержимое items.py:

import scrapy

class FeedItem(scrapy.Item):
    id = scrapy.Field()
    title = scrapy.Field()
    description = scrapy.Field()
    pass

Ответы [ 2 ]

1 голос
/ 24 мая 2019

Вы можете сделать свой собственный экспортер CSV! В идеале вы можете просто расширить текущий экспортер другим методом:

# exporters.py 
from scrapy.exporters import CsvItemExporter

class MyCsvItemExporter(CsvItemExporter):
    header_map = {
        'description': 'Item Description',
    }

    def _write_headers_and_set_fields_to_export(self, item):
        if not self.include_headers_line:
            return
        # this is the parent logic taken from parent class
        if not self.fields_to_export:
            if isinstance(item, dict):
                # for dicts try using fields of the first item
                self.fields_to_export = list(item.keys())
            else:
                # use fields declared in Item
                self.fields_to_export = list(item.fields.keys())
        headers = list(self._build_row(self.fields_to_export))

        # here we add our own extra mapping
        # map headers to our value
        headers = [self.header_map.get(header, header) for header in headers]
        self.csv_writer.writerow(headers)

А затем активируйте его в настройках:

FEED_EXPORTERS = {
    'csv': 'myproject.exporters.MyCsvItemExporter',
}
0 голосов
/ 24 мая 2019

Вы можете использовать встроенный словарь типа dict как элемент с необходимыми значениями заголовка csv в качестве ключа словаря:

    def parse_node(self, response, node):
        item = dict() #item = {}
        item['ID'] = node.xpath('//*[name()="g:id"]/text()').get()
        item['Item title'] = node.xpath('//*[name()="g:title"]/text()').get()
        item['Item description'] = node.xpath('//*[name()="g:description"]/text()').get()

        return item #yield item
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...