Scrapy源码分析-持久化导出数据类Item Exporters(五)
来源:互联网 发布:单片机io口输出电压 编辑:程序博客网 时间:2024/06/07 13:41
当你抓取了你要的数据(Items),你希望能合适的保存爬取到的数据,或者说,生成一个带有爬取数据的”输出文件”(通常叫做”输出feed”),来供其他系统使用。
Scrapy自带了Feed输出,并且支持多种序列化格式(serialization format)及存储方式(storage backends)。而Feed输出使用到了 ItemExporters。
如果你是想单纯的将数据输出或存入文件,那直接可以用Scrapy提供的现成类。如果想要知道Item Exporters是怎么工作的或需要自定义功能,就需要深入了解Item Exporters的运行机制。
为了使用 Item Exporter,你必须对 Item Exporter 及其参数 (args) 实例化。每个 Item Exporter 需要不同的参数 。在实例化了 exporter 之后,你必须:
- 调用方法start_exporting()以标识过程的开始。
- 对要导出的每个item调用export_item() 方法。
- 最后调用finish_exporting()表示过程的结束
BaseItemExporter
- classscrapy.contrib.exporter.BaseItemExporter(fields_to_export=None, export_empty_fields=False,encoding='utf-8')
这是一个对所有 Item Exporters 的(抽象)父类。它对所有(具体) Item Exporters 提供基本属性,如定义export什么fields, 是否export空fields, 或是否进行编码。
你可以在构造器中设置它们不同的属性值: fields_to_export , export_empty_fields, encoding.
首先在初始化方法__init__(self , **kwargs)中调用_configure(kwargs)方法,提取并设置运行需要的属性。
调用start_exporting(self)方法,为处理item做预处理工作。
当有item到来时,调用export_item(self, item)处理。
处理完所有item后,调用finish_exporting(self)扫尾。
此外还涉及到转码,序列化,分析item的方法。
# 所有Item Exporters的抽象父类,定义了exporter的基本属性 class BaseItemExporter(object): def __init__(self, **kwargs): self._configure(kwargs) def _configure(self, options, dont_fail=False): #在子类中调用,读取需要export的field给fields_to_export, # None表示export所有fields. 默认值为None. self.fields_to_export = options.pop('fields_to_export', None) #是否在输出数据中包含为空的item fields. 默认值是 False. 一些 exporters (例如 CsvItemExporter) 会忽略此属性并输出所有fields. self.export_empty_fields = options.pop('export_empty_fields', False) #Encoding 属性将用于编码 unicode 值. (仅用于序列化字符串).其他值类型将不变的传递到指定的序列化库. self.encoding = options.pop('encoding', 'utf-8') if not dont_fail and options: raise TypeError("Unexpected options: %s" % ', '.join(options.keys())) #必须在子类中实现。接受一个item,并输出 def export_item(self, item): raise NotImplementedError #返回给定field的序列化值。默认使用field中指定的serializer作为序列化函数。如果没有指定serializer且没有指定使用unicode编码到str,返回原值 #你可以覆盖此方法来控制序列化或输出指定的field. #@param field : 要序列化的field的对象 #@param name : field的名字 #@param value :field的值 def serialize_field(self, field, name, value): serializer = field.get('serializer', self._to_str_if_unicode) return serializer(value) #表示exporting过程的开始. 一些exporters用于产生需要的头元素(例如 XmlItemExporter). 在实现exporting_item前必须调用此方法. def start_exporting(self): pass #表示exporting过程的结束. 一些exporters用于产生需要的尾元素 (例如 XmlItemExporter). 在完成exporting item后必须调用此方法 def finish_exporting(self): pass def _to_str_if_unicode(self, value): return value.encode(self.encoding) if isinstance(value, unicode) else value #需要在子类中的export_item调用,读取item,并返回每个filed的键值迭代对象 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: field_iter = item.fields.iterkeys() else: field_iter = item.iterkeys() else: if include_empty: field_iter = self.fields_to_export else: nonempty_fields = set(item.keys()) field_iter = (x for x in self.fields_to_export if x in nonempty_fields) for field_name in field_iter: if field_name in item: field = item.fields[field_name] value = self.serialize_field(field, field_name, item[field_name]) else: value = default_value yield field_name, value
以BaseItemExporterScrapy为父类,Scrapy提供了多个Item Exporters子类来创建不同的输出格式,如XML,CSV或JSON格式。
JsonItemExporter
- classscrapy.contrib.exporter.JsonItemExporter(file, **kwargs)
输出 JSON 文件格式, 所有对象将写进一个对象的列表. 此构造器额外的关键字参数将传给BaseItemExporter 构造器, 其余的将传给 JSONEncoder 构造器, 以此来定制 exporter.
参数: file – 文件类.JSON 是一个简单而有弹性的格式, 但对大量数据的扩展性不是很好,因为这里会将整个对象放入内存. 如果你要JSON既强大又简单,可以考虑 JsonLinesItemExporter , 或把输出对象分为多个块.
class JsonLinesItemExporter(BaseItemExporter): #指定了输出文件,以及BaseItemExporter所需要的属性。 #ScrapyJSONEncoder提供了将字典类型的数据转换为Json格式数据的方法 def __init__(self, file, **kwargs): self._configure(kwargs, dont_fail=True) self.file = file self.encoder = ScrapyJSONEncoder(**kwargs) #将转化为字典类型的item写入指定的文件中 #self.file即执行文件的句柄 #这里的file已经在pipeline中打开。 def export_item(self, item): itemdict = dict(self._get_serialized_fields(item)) self.file.write(self.encoder.encode(itemdict) + '\n')
JsonLinesItemExporter
- classscrapy.contrib.exporter.JsonLinesItemExporter(file, **kwargs)
输出 JSON 文件格式, 每行写一个 JSON-encoded 项. 此构造器额外的关键字参数将传给BaseItemExporter 构造器, 其余的将传给 JSONEncoder 构造器, 以此来定制 exporter.
参数: file – 文件类.
#创建Json格式的Exporter#与JsonLinesItemExporter不同的是该类会把所有的item封装成数组写入文件,整个json文件就是一个数组。class JsonItemExporter(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("[") 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))
XmlItemExporter
- classscrapy.contrib.exporter.XmlItemExporter(file, item_element='item', root_element='items',**kwargs)
以XML格式 exports Items 到指定的文件类.
参数: - file – 文件类.
- root_element (str) – XML 根元素名.
- item_element (str) – XML item 的元素名.
构造器额外的关键字参数将传给 BaseItemExporter 构造器.
#创建XML格式的Exporterclass XmlItemExporter(BaseItemExporter): #需要指定根元素和item元素名 def __init__(self, file, **kwargs): self.item_element = kwargs.pop('item_element', 'item') self.root_element = kwargs.pop('root_element', 'items') self._configure(kwargs) self.xg = XMLGenerator(file, encoding=self.encoding) def start_exporting(self): self.xg.startDocument() self.xg.startElement(self.root_element, {}) def export_item(self, item): self.xg.startElement(self.item_element, {}) for name, value in self._get_serialized_fields(item, default_value=''): self._export_xml_field(name, value) self.xg.endElement(self.item_element) def finish_exporting(self): self.xg.endElement(self.root_element) self.xg.endDocument() def _export_xml_field(self, name, serialized_value): self.xg.startElement(name, {}) if hasattr(serialized_value, 'items'): for subname, value in serialized_value.items(): self._export_xml_field(subname, value) elif hasattr(serialized_value, '__iter__'): for value in serialized_value: self._export_xml_field('value', value) else: self._xg_characters(serialized_value) self.xg.endElement(name) # Workaround for http://bugs.python.org/issue17606 # Before Python 2.7.4 xml.sax.saxutils required bytes; # since 2.7.4 it requires unicode. The bug is likely to be # fixed in 2.7.6, but 2.7.6 will still support unicode, # and Python 3.x will require unicode, so ">= 2.7.4" should be fine. if sys.version_info[:3] >= (2, 7, 4): def _xg_characters(self, serialized_value): if not isinstance(serialized_value, unicode): serialized_value = serialized_value.decode(self.encoding) return self.xg.characters(serialized_value) else: def _xg_characters(self, serialized_value): return self.xg.characters(serialized_value)
还有CsvItemExporter , PickleItemExporter, MarshalItemExporter,PprintItemExporter,PythonItemExporter等。Scrapy提供这些Item Exporter基本大同小异,代码也不难,这里不再一一列出。有兴趣的可以私下交流。
- Scrapy源码分析-持久化导出数据类Item Exporters(五)
- Scrapy源码分析-Item Pipeline中文文档(四)
- scrapy源码分析(五)--------------execute函数分析
- nsq源码分析(3):nsqd之数据持久化
- NHibernate源码分析之三(续):数据持久化
- 分布式文件系统KFS源码阅读与分析(二):MetaServer元数据持久化
- nsq源码分析(3):nsqd之数据持久化2
- Redis源码解析(五):redis之持久化
- hibernate持久化类&持久化对象(五)
- Scrapy源码分析(二):Setting相关类定义
- Flume源码分析—数据流转框架分析(五)
- Scrapy系列教程(2)------Item(结构化数据存储结构)
- MyBatis数据持久化(五)数据源配置优化
- Android五种数据存储(数据持久化)方式
- scrapy源码分析(六)---------------CrawlProcess
- scrapy源码分析(七)------------ Crawler
- scrapy源码分析(八)--------ExecutionEngine
- scrapy源码分析(九)-----------Scheduler
- 13_机构:欧元本周将走高的三大理由
- 14_交易推荐之趋势追踪——美元/日元
- <C/C++基础>九度OJ题目1000--1049解题练习(二)
- 只需添加更多的列
- JAVA读取外部资源的方法
- Scrapy源码分析-持久化导出数据类Item Exporters(五)
- C++ Primer中文本查询示例Query的实现
- 转换为二进制
- sql入门经典学习
- Unity调试
- 日志薄java实现
- IOCP
- 数量的变量
- CSS字体大小: em与px、pt、百分比之间的对比