返回介绍

7.2 添加导出数据格式

发布于 2024-02-05 21:13:20 字数 4633 浏览 0 评论 0 收藏 0

在某些需求下,我们想要添加新的导出数据格式,此时需要实现新的Exporter类。下面先参考Scrapy内部的Exporter类是如何实现的,然后自行实现一个Exporter。

7.2.1 源码参考

Scrapy内部的Exporter类在scrapy.exporters模块中实现,以下是其中的代码片段:

class BaseItemExporter(object):
 def __init__(self, **kwargs):
   self._configure(kwargs)
 def _configure(self, options, dont_fail=False):
   self.encoding = options.pop('encoding', None)
   self.fields_to_export = options.pop('fields_to_export', None)
   self.export_empty_fields = options.pop('export_empty_fields', False)
   if not dont_fail and options:
    raise TypeError("Unexpected options: %s" % ', '.join(options.keys()))
 def export_item(self, item):
   raise NotImplementedError
 def serialize_field(self, field, name, value):
   serializer = field.get('serializer', lambda x: x)
   return serializer(value)
 def start_exporting(self):
   pass
 def finish_exporting(self):
   pass
 def _get_serialized_fields(self, item, default_value=None, include_empty=None):
  """Return the fields to export as an iterable of tuples
  (name, serialized_value)
  """
  if include_empty is None:
    include_empty = self.export_empty_fields
  if self.fields_to_export is None:
    if include_empty and not isinstance(item, dict):
      field_iter = six.iterkeys(item.fields)
    else:
      field_iter = six.iterkeys(item)
  else:
    if include_empty:
      field_iter = self.fields_to_export
    else:
      field_iter = (x for x in self.fields_to_export if x in item)
  for field_name in field_iter:
    if field_name in item:
      field = {} if isinstance(item, dict) else item.fields[field_name]
      value = self.serialize_field(field, field_name, item[field_name])
    else:
      value = default_value
    yield field_name, value
# json
class JsonItemExporter(BaseItemExporter):
 def __init__(self, file, **kwargs):
  self._configure(kwargs, dont_fail=True)
  self.file = file
  kwargs.setdefault('ensure_ascii', not self.encoding)
  self.encoder = ScrapyJSONEncoder(**kwargs)
  self.first_item = True
 def start_exporting(self):
  self.file.write(b"[\n")
 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))
  data = self.encoder.encode(itemdict)
  self.file.write(to_bytes(data, self.encoding))
# json lines
class JsonLinesItemExporter(BaseItemExporter):
 ...
# xml
class XmlItemExporter(BaseItemExporter):
 ...
# csv
class CsvItemExporter(BaseItemExporter):
 ...
...

其中的每一个Exporter都是BaseItemExporter的一个子类,BaseItemExporter定义了一些抽象接口待子类实现:

export_item(self, item)

负责导出爬取到的每一项数据,参数item为一项爬取到的数据,每个子类必须实现该方法。

start_exporting(self)

在导出开始时被调用,可在该方法中执行某些初始化工作。

finish_exporting(self)

在导出完成时被调用,可在该方法中执行某些清理工作。

以JsonItemExporter为例,其实现非常简单:

为了使最终导出结果是一个json中的列表,在start_exporting和finish_exporting方法中分别向文件写入b"[\n, b"\n]"。

在export_item方法中,调用self.encoder.encode方法将一项数据转换成json串(具体细节不再赘述),然后写入文件。

7.2.2 实现Exporter

接下来,我们参照JsonItemExporter的源码,在第1章example项目中实现一个能将数据以Excel格式导出的Exporter。

在项目中创建一个my_exporters.py(与settings.py同级目录),在其中实现ExcelItemExporter,代码如下:

from scrapy.exporters import BaseItemExporter
import xlwt
class ExcelItemExporter(BaseItemExporter):
 def __init__(self, file, **kwargs):
   self._configure(kwargs)
   self.file = file
   self.wbook = xlwt.Workbook()
   self.wsheet = self.wbook.add_sheet('scrapy')
   self.row = 0
 def finish_exporting(self):
   self.wbook.save(self.file)

 def export_item(self, item):
   fields = self._get_serialized_fields(item)
   for col, v in enumerate(x for _, x in fields):
    self.wsheet.write(self.row, col, v)
   self.row += 1

解释上述代码如下:

这里使用第三方库xlwt将数据写入Excel文件。

在构造器方法中创建Workbook对象和Worksheet对象,并初始化用来记录写入行坐标的self.row。

在export_item方法中调用基类的_get_serialized_fields方法,获得item所有字段的迭代器,然后调用self.wsheet.write方法将各字段写入Excel表格。

finish_exporting方法在所有数据都被写入Excel表格后被调用,在该方法中调用self.wbook.save方法将Excel表格写入Excel文件。

完成ExcelItemExporter后,在配置文件settings.py中添加如下代码:

FEED_EXPORTERS = {'excel': 'example.my_exporters.ExcelItemExporter'}

现在,可以使用ExcelItemExporter导出数据了,以-t excel为参数重新运行爬虫:

$ scrapy crawl books -t excel -o books.xls

图7-1所示为爬取完成后在Excel文件中观察到的结果。

图7-1

如上所示,我们成功地使用ExcelItemExporter将爬取到的数据存入了Excel文件中。

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据
    我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
    原文