- 精通Scrapy網絡爬蟲
- 劉碩
- 857字
- 2020-11-28 14:59:40
4.3 Field元數據
在第2章中曾講到,一項數據由Spider提交給Scrapy引擎后,可能會被遞送給其他組件(ItemPipeline、Exporter)處理。假設想傳遞額外信息給處理數據的某個組件(例如,告訴該組件應以怎樣的方式處理數據),此時可以使用Field的元數據。請看下面的例子:
class ExampleItem(Item): x=Field(a='hello', b=[1, 2, 3]) #x有兩個元數據,a是個字符串,b是個列表 y=Field(a=lambda x: x**2) #y有一個元數據,a是個函數
訪問一個ExampleItem對象的fields屬性,將得到一個包含所有Field對象的字典:
>>> e = ExampleItem(x=100, y=200) >>> e.fields {'x': {'a': 'hello', 'b': [1, 2, 3]}, 'y': {'a': <function __main__.ExampleItem.<lambda>>}} >>> type(e.fields['x']) scrapy.item.Field >>> type(e.fields['y']) scrapy.item.Field
實際上,Field是Python字典的子類,可以通過鍵獲取Field對象中的元數據:
>>> issubclass(Field, dict) True >>>field_x=e.fields['x'] # 注意,不要混淆e.fields['x']和e['x'] >>> field_x {'a': 'hello', 'b': [1, 2, 3]} >>> field_x['a'] 'hello' >>> field_y = e.fields['y'] >>> field_y {'a': <function __main__.ExampleItem.<lambda>>} >>> field_y.get('a', lambda x: x) <function __main__.ExampleItem.<lambda>>
接下來,看一個應用Field元數據的實際例子。假設我們要把爬取到的書籍信息寫入csv文件,那每一項數據最終由Scrapy提供的CsvItemExporter寫入文件(數據導出在第7章詳細講解),在爬取過程中提取到的信息并不總是一個字符串,有時可能是一個字符串列表,例如:
>>> book['authors'] = [’李雷’, ’韓梅梅’, ’吉姆’]
但在寫入csv文件時,需要將列表內所有字符串串行化成一個字符串,串行化的方式有很多種,例如:
1.’李雷|韓梅梅|吉姆’ #'|'.join(book['authors']) 2.’李雷;韓梅梅;吉姆’ #'; '.join(book['authors']) 3. "[’李雷’,’韓梅梅’,’吉姆’]" #str(book['authors'])
我們可以通過authors字段的元數據告訴CsvItemExporter如何對authors字段串行化:
class BookItem(Item): ... authors = Field(serializer=lambda x: '|'.join(x)) ...
其中,元數據的鍵serializer是CsvItemExporter規定好的,它會用該鍵獲取元數據,即一個串行化函數對象,并使用這個串行化函數將authors字段串行化成一個字符串。以下是Scrapy源碼中的相關實現:
# exports.py class BaseItemExporter(object): ... def _get_serialized_fields(self, item, default_value=None, include_empty=None): ... 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 ... class CsvItemExporter(BaseItemExporter): ... def export_item(self, 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 serialize_field(self, field, name, value): serializer = field.get('serializer', self._join_if_needed) return serializer(value) ...
解釋上述代碼如下:
● 爬取到的每一項數據由export_item方法導出到文件,寫入文件之前,先調用_get_serialized_fields方法(在基類中實現)獲得數據中每個字段串行化的結果。
● 在_get_serialized_fields方法中調用serialize_field方法,獲取其中一個字段串行化的結果。
● 在serialize_field方法中獲取字段的元數據serializer,得到串行化函數(如果不存在,就使用默認的_join_if_needed函數),最終調用該函數對字段串行化,并將結果返回。
在實際應用中,我們可以仿照上面的例子靈活使用Field元數據。
- Google Flutter Mobile Development Quick Start Guide
- Learning ROS for Robotics Programming(Second Edition)
- Mobile Web Performance Optimization
- LabVIEW2018中文版 虛擬儀器程序設計自學手冊
- Oracle BAM 11gR1 Handbook
- Python編程:從入門到實踐
- JavaScript+jQuery網頁特效設計任務驅動教程
- Android系統下Java編程詳解
- 量子計算機編程:從入門到實踐
- 軟件設計模式(Java版)
- Internet of Things with Arduino Cookbook
- Oracle 11g寶典
- OpenACC并行編程實戰
- 深入解析WPF編程
- Go語言從入門到項目實戰(視頻版)