Scrapy csv输出"随机"缺少字段

时间:2017-01-29 02:38:59

标签: python python-3.x csv scrapy

我的scrapy搜寻器正确读取所有字段,如调试输出所示:

2017-01-29 02:45:15 [scrapy.core.scraper] DEBUG: Scraped from <200 https://www.willhaben.at/iad/immobilien/mietwohnungen/niederoesterreich/krems-an-der-donau/altbauwohnung-wg-geeignet-donaublick-189058451/>
{'Heizung': 'Gasheizung', 'whCode': '189058451', 'Teilmöbliert / Möbliert': True, 'Wohnfläche': '105', 'Objekttyp': 'Zimmer/WG', 'Preis': 1050.0, 'Miete (inkl. MWSt)': 890.0, 'Stockwerk(e)': '2', 'Böden': 'Laminat', 'Bautyp': 'Altbau', 'Zustand': 'Sehr gut/gut', 'Einbauküche': True, 'Zimmer': 3.0, 'Miete (exkl. MWSt)': 810.0, 'Befristung': 'nein', 'Verfügbar': 'ab sofort', 'zipcode': 3500, 'Gesamtbelastung': 1150.0}

但是当我使用命令行选项

输出csv时
scrapy crawl mietwohnungen -o mietwohnungen.csv --logfile=mietwohnungen.log

缺少某些字段,因为输出文件中的相应行显示:

Keller,whCode,Garten,Zimmer,Terrasse,Wohnfläche,Parkplatz,Objekttyp,Befristung,zipcode,Preis
,189058451,,3.0,,105,,Zimmer/WG,nein,3500,1050.0

示例中缺少的字段为:Heizung, Teilmöbliert / Möbliert, Miete (inkl. MWSt), Stockwerk(e), Böden, Bautyp, Zustand, Einbauküche, Miete (exkl. MWSt), Verfügbar, Gesamtbelastung

这种情况发生时我抓了一些值。需要注意的一点是,并非每个页面都包含相同的字段,因此我会根据页面生成字段名称。我创建了一个包含所有字段的dict,最后是yield。这与DEBUG输出显示有效。但是,有些csv列似乎没有打印出来。

正如您所看到的,某些列是空白的,因为其他页面显然具有这些字段(在示例中&#39; Keller&#39;)。

如果我使用较小的列表进行刮取(例如,在保留结果中某些有问题的页面的同时优化我的初始搜索选择),则刮刀有效:

Heizung,Zimmer,Bautyp,Gesamtbelastung,Einbauküche,Miete (exkl. MWSt),Zustand,Miete (inkl. MWSt),zipcode,Teilmöbliert / Möbliert,Objekttyp,Stockwerk(e),Böden,Befristung,Wohnfläche,whCode,Preis,Verfügbar
Gasheizung,3.0,Altbau,1150.0,True,810.0,Sehr gut/gut,890.0,3500,True,Zimmer/WG,2,Laminat,nein,105,189058451,1050.0,ab sofort

我已经更改为python3以避免任何unicode字符串问题。

这是一个错误吗?这似乎只影响csv输出,如果输出到xml,则打印所有字段。

我不明白为什么它不能与完整列表一起使用。是手动编写csv导出器的唯一解决方案吗?

编辑:解决方案基于@ mizhgun&#39; s answer

我创建了一个写入csv输出的项目管道。迭代每个项目时,它存储唯一键的集合并最终写入csv文件。请务必在调用-o并将管道添加到scrapy crawl时删除settings.py选项:

pipelines.py

import csv
import logging

class CsvWriterPipeline(object):

    def open_spider(self, spider):
        self.file = open('mietwohnungen.csv', 'w', newline='')
        #if python < 3 use
        #self.file = open('mietwohnungen.csv', 'wb')
        self.items = []
        self.colnames = []

    def close_spider(self, spider):
        csvWriter = csv.DictWriter(self.file, fieldnames = self.colnames)#, delimiter=',')
        logging.info("HEADER: " + str(self.colnames))
        csvWriter.writeheader()
        for item in self.items:
            csvWriter.writerow(item)
        self.file.close()

    def process_item(self, item, spider):
        # add the new fields
        for f in item.keys():
            if f not in self.colnames:
                self.colnames.append(f)

        # add the item itself to the list
        self.items.append(item)
        return item

settings.py

ITEM_PIPELINES = {
    'willhaben.pipelines.CsvWriterPipeline': 300,
}

1 个答案:

答案 0 :(得分:2)

如果您将结果作为dict产生,则将从第一个产生的字典的键中填充CSV列:

def _write_headers_and_set_fields_to_export(self, item):
    if self.include_headers_line:
        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())
        row = list(self._build_row(self.fields_to_export))
        self.csv_writer.writerow(row)

因此,您应该使用显式定义的所有字段定义和填充Item,或者编写自定义CSVItemExporter