在scrapy中修改CSV导出
我好像漏掉了一些很简单的东西。我想做的就是在CSV导出器中使用;
作为分隔符,而不是,
。
我知道CSV导出器会把一些参数传给csv写入器,但我就是搞不清楚怎么把这个分隔符传过去。
我这样调用我的爬虫:
scrapy crawl spidername --set FEED_URI=output.csv --set FEED_FORMAT=csv
3 个回答
-1
我也试过这个方法,也能奏效:
第一步: 修改 C:\Python27\Lib\site-packages\scrapy\exporters.py
文件的第21行,改成:
__all__ = ['BaseItemExporter', 'PprintItemExporter', 'PickleItemExporter',
'CsvItemExporter', 'TxtItemExporter', 'XmlItemExporter',
'JsonLinesItemExporter', 'JsonItemExporter', 'MarshalItemExporter']
这一步是把 'TxtItemExporter'
加到原来的 __all__
列表里。
第二步: 在 C:\Python27\Lib\site-packages\scrapy\exporters.py
文件里添加一个新类,叫做 TxtItemExporter:
class TxtItemExporter(BaseItemExporter):
def __init__(self, file, include_headers_line=True, join_multivalued=',', **kwargs):
self._configure(kwargs, dont_fail=True)
if not self.encoding:
self.encoding = 'utf-8'
self.include_headers_line = include_headers_line
self.stream = io.TextIOWrapper(
file,
line_buffering=False,
write_through=True,
encoding=self.encoding
) if six.PY3 else file
self.csv_writer = csv.writer(self.stream, delimiter='\t', **kwargs)
self._headers_not_written = True
self._join_multivalued = join_multivalued
def serialize_field(self, field, name, value):
serializer = field.get('serializer', self._join_if_needed)
return serializer(value)
def _join_if_needed(self, value):
if isinstance(value, (list, tuple)):
try:
return self._join_multivalued.join(value)
except TypeError: # list in value may not contain strings
pass
return value
def export_item(self, item):
if self._headers_not_written:
self._headers_not_written = False
self._write_headers_and_set_fields_to_export(item)
fields = self._get_serialized_fields(item, default_value='',
include_empty=True)
values = list(self._build_row(x for _, x in fields))
self.csv_writer.writerow(values)
def _build_row(self, values):
for s in values:
try:
yield to_native_str(s, self.encoding)
except TypeError:
yield s
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)
这个新类是从 CsvItemExporter 复制过来的,只是在 csv.writer()
里加了 delimiter='\t'
。
第三步: 在 settings.py
文件里添加以下设置:
FEED_EXPORTERS = {
'txt': 'scrapy.contrib.exporter.TxtItemExporter',
}
FEED_FORMAT = 'txt'
FEED_URI = "your_output_file.txt"
第四步: 运行 scrapy crawl your_spider
,然后你就可以在你的爬虫项目目录里找到输出的 txt 文件了。
2
scraper/exporters.py
from scrapy.exporters import CsvItemExporter
from scraper.settings import CSV_SEP
class CsvCustomSeperator(CsvItemExporter):
def __init__(self, *args, **kwargs):
kwargs['encoding'] = 'utf-8'
kwargs['delimiter'] = CSV_SEP
super(CsvCustomSeperator, self).__init__(*args, **kwargs)
scraper/settings.py
CSV_SEP = '|'
FEED_EXPORTERS = {
'csv': 'scraper.exporters.CsvCustomSeperator'
}
在终端中
$ scrapy crawl spider -o file.csv -s CSV_SEP=<delimiter>
13
在 contrib/feedexport.py
文件中,
class FeedExporter(object):
...
def open_spider(self, spider):
file = TemporaryFile(prefix='feed-')
exp = self._get_exporter(file) # <-- this is where the exporter is instantiated
exp.start_exporting()
self.slots[spider] = SpiderSlot(file, exp)
def _get_exporter(self, *a, **kw):
return self.exporters[self.format](*a, **kw) # <-- not passed in :(
你需要自己创建一个,这里有个例子:
from scrapy.conf import settings
from scrapy.contrib.exporter import CsvItemExporter
class CsvOptionRespectingItemExporter(CsvItemExporter):
def __init__(self, *args, **kwargs):
delimiter = settings.get('CSV_DELIMITER', ',')
kwargs['delimiter'] = delimiter
super(CsvOptionRespectingItemExporter, self).__init__(*args, **kwargs)
在你爬虫目录的 settings.py
文件中,添加以下内容:
FEED_EXPORTERS = {
'csv': 'importable.path.to.CsvOptionRespectingItemExporter',
}
现在,你可以按照下面的方式运行你的爬虫:
scrapy crawl spidername --set FEED_URI=output.csv --set FEED_FORMAT=csv --set CSV_DELIMITER=';'
希望这对你有帮助。