使用Item封装数据

前两篇博客介绍了从页面中提取数据的方法,现在用item封装爬取到的数据

Item和Field

Scrapy提供了Item和Field类,可以用他们自定义数据类,封装爬取到的数据

  • Item :自定义数据类(BookItem)的基类
  • Field:描述自定义数据类包含那些字段(name price)

自定义一个数据类,只需要继承Item,并创建一系列Field对象的类属性

from scrapy import Item,Field
class BookItem(Item)name = Field()price = Field()

Item支持字典接口,因此BookItem在使用上和Python字典类似

book1= BookItem(name = 'Needful Things',price = 45.0)
book1
{'name':'Needful Things','price':45.0}
book2 = BookItem()
book2
{}
book2['name'] = 'Life of Pi'
book2['price'] = 32.5
{'name':'Life of Pi','price':32.5}

访问BookItem对象中的字段与访问字典类似

book.get('price',60)
45.0
list(book.items())
[('price',45.0),('name','Needful Things')]

修改之前的BooskSpider,使用BookItem替代Python字典

class BooksSpider(scrapy.Spider):def parse(self,response):for sel in response.css('article.product_pod'):book = BookItem()book['name'] = sel.xpath('./h3/a/@title').extract_first()book['price'] = sel.css('p.price_color::text').extract_first()yield book

拓展Item子类

根据需求对已有的自定义数据类(Item子类)进行拓展。
例如:
example项目中又添加了一个新的Spider,它负责另一个网站爬取信息

#继承BookItem定义一个ForeigenBookItem类,在其中添加一个翻译字段
class ForeignBookItem(BookItem):translator = Field()book = ForeignBookItem()
book['name'] = ' 巴黎圣母院'
book['price'] = 200
book['translator'] = '陈景荣'

Field元数据

入门2中提到,数据由Spider交给Scrapy引擎后,可能会被传递给其他组件
(Item Pipeline Exporter)处理。可以使用Field的元数据传递额外的信息给处理数据的某个组件(例如告诉组件以何种方式处理数据)

class ExampleItem(Item):x = Field(a = 'hello',b = [1,2,3])y = Field(a = lambda x:x**2) #y有一个数据,a是个函数

访问一个ExampleItem对象的fields属性,将得到一个包含所有Fideli对象的字典

e = ExampleItem(x = 100,y = 200)
e.fields
{'x':{'a':'hello','b':[1,2,3]}}
{'y':{'a':<function_main_.ExampleItem.<lambda>>}}type(e.fields['y'])
scrapy.item.Field

实际上,Field是Python字典的子类,可以通过键值对获取Field对象中的元素:

issubclass(Field,dict)
True
field_x['a']
'hello'

应用Field元数据的实例:
假设要把爬取的书籍信息写入csv,每一项数据最终由Scrapy提供的CsvItemExporter写入文件,在爬取过程中,提取到的信息不一定总是一个字符串,有时可能是一个字符串列表

book['authors'] = ['李雷','韩梅梅','吉姆']

写入csv时,需要将列表内所有字符串串行化成一个字符串,
串行化的方式:

  • ’李雷|韩梅梅|吉姆‘ #’|‘.join(book[‘authors’])
  • ‘李雷;韩梅梅;吉姆’ #’;‘.join(book[‘authors’])
  • “[‘李雷’,’韩梅梅’,’吉姆’]”
    通过authors字段的元数据告诉CsvItemExporter如何对authors字段串行话:
class BookItem(Item);authors = Field(serializer = lambda x:'|'.join(x))


使用Item Pipeline处理数据

前面讲了提取数据以及封装数据的方法,现在讲如何对爬取的数据进行处理。
在Scrapy中,Item Pipeline是处理数据的组件,一个Item Pipeline就是一个包含特定的接口的类,通常只负责一种功能的数据处理,在一个项目中可存在多个,指定次序级连起来,形成一条数据处理流水线
Item Pipline的典型应用:

  • 清洗数据
  • 验证数据有效性
  • 过滤掉重复的数据
  • 将数据存入数据库

在(1)中,爬取到的书籍价格是以英镑为单位的,可以用Item Pipeline转换为人民币为大威德
实现Item Pipeline
在创建一个Scrapy时,会自动生成一个pipelines.py文件,它用来放置用户自定义的Item Pipeline

class PriceConverterPipeline(object):
#汇率
exchange_rate = 8.5309def process_item(self,item,spider):#提取item的price字段#去掉英镑符号,转换为floatprice = float(item['price'][1:])*self.exchange_rate#保留两位小数,赋值会item的price字段item['price'] = '¥%.2f%price'return itemy
  • 一个Item Pipeline不需要继承特定的基类,只需要实现某些特定的方法,process_item \ open_spider \ close_spider
  • 一个Item Pipeline必须实现一个process_item(item,spider)方法,该方法用来处理每一项由Spider获取到的数据:item(爬取到的一项数据(Item或者字典))。Spider(爬取此项数据的Spider对象)
    process_item是核心
  • 若process_item在处理某一项item时返回一项数据(item或者字典),返回的数据会传递给下一级Item Pipeline(若存在)继续处理
  • 若抛出异常(DropItem),该项的item会被抛弃,不再传递给后面的item处理。通常,在检测无效数据或过滤数据时,会DropItem

除了process_item还有三个常用方法,

  • open_spider(self,spider)打开时回调该方法,用于在开始处理数据之前完成某些初始化工作,链接数据库
  • close_spider(self,spider)关闭数据库
  • from_crawler(cls,crawer)创建对象时回调该方法,通过crawler.settings读取配置,根据配置创建Item Pipeline对象
    启用Item Pipeline
    Item Pipeline是可选组件,启用前需要在settings.py中进行配置:
ITEM_PIPELINE = {'example.piplines.PriceConverterPipeline':300}

ITEM_PIPELINE是一个字典,把想要启用的Item Pipeline添加到这个字典中,其中每一项的键是每一个Item Pipeline类的导入路径,0~1000表示次序,数值小的在前。

ITEM Pipeline案例
1.去掉重复数据

from scrapy.exceptions import DropItem
class DuplicatesPipline(object):def__init__(self):self.book_set = set()def process_item(self,item,spider):name = item['name']if name in self.book_set:raise DropItem("Duplicate book found:%s"%item)self.book_set.add(name)return item

在settings.py中启用DuplicatesPipline:

ITEM_PIPELINES = {'example.pipeline.DuplicatesPipline':350}

翻阅爬虫的log信息可以找到重复项

[scrapy.core.scraper]WATNING:Dropped:Duplicate book found:
{'name':'The Star-Touched Queen','price':'¥275.5'}

2.将数据存入MongoliaDB

from scrapy.item import Item
import pymongoclass MongoDBPipeline(object):DB_URL = 'mongodb://locathost:27017/'DB_NAME = 'scrapy_data'def open_spider(self,spider):self.client = pymongodb.MongoClient(self.DB_URL)self.db = self.client[self.DB_NAME]def close_spider(self,spider):self.client.close()
#process_item实现数据库的写入操作,使用self.db和spider.name获取一个集合(collection),然后将数据插入集合中,集合对象insert_one 方法需转入一个字典对象(不能传入Item对象),插入前先判断,不是字典先转换成字典def process_item(self,item,spider):collection = self.db[spider.name]post = dict(item)if isinstance(item,Item)else itemcollection.insert_one(post)return item

使用LinkExtract提取链接

此处链接为页面中包含的链接,两种提取方式

  • Selector 把链接当做数据正常提取,少量时足够
  • LinkExtract:专门提取链接的类,提取大量链接
    (1)中的例子用了第一种方法,先用CSS选择器选中包含下一页链接的a元素并获取href属性,然后调用response.urljoin方法计算出绝对url地址,最后request对象提交
def parse(self,response):
#下一页的链接在ul.page>li.next>a里面next_url = response.css('ul.pager li.next a::attr(href)').extract_first()if next_url:next_url = response.urljoin(next_url)yield scrapy.Request(next_url,callback = self.parse)

使用LinkExtractor方式

#导入linkextractor它位于LinkExtractor模块
from scrapy.linkextractors import LinkExtractor
class BooksSpider(scrapy.Spider):def parse(self,response):
#创建一个LinkExtractor对象,传递给restrict_css参数一个css选择表达式,描述下一页链接所在区域le = LinkExtractor(restrict_css='ul.pager li.next')#根据描述提取区域,在response对象所包含的页面中提取链接,返回url列表links = le.extract_links(response)if links:next_url = link[0].urlyield#由于下一页链接只有一个,用link[0]获取link对象,link属性便是链接页面的绝对url(无需再调用response.urljoin方法),构造response对象并提交scrapy.Request(next_url,callback=self.parseyyy)

描述提起规则
特殊情况:linkExtractor构造器的所有参数都为默认值,构造参数时不传递任何参数(使用默认值),就提取页面中所有链接。

from scrapy.linkextractors import LinkExtractor
le = LinkExtractor()
links = le.extract_links(response1)
[link.url for link in links]

LinkExtractor构造器中的各个参数

  • allow
#接受一个正则表达式,提取绝对url与正则表达式匹配的链接,参数为空
#就提取全部链接
le = LinkExtractor(allow = pattern)
  • deny
#接受一个正则表达式,与allow相反,排除绝对url与正则表达式匹配的链接
le = LinkExtractor(deny = pattern)
  • allow_domains
#接受一个域名或一个域名列表,提取到指定域的链接。
le = LinkExtractor(allow_domains = domains)
  • deny_domains
#接受一个域名或一个域名列表,与allow_domains相反,排除到指定的链接
le = LinkExtractor(deny_domains='github.com')
  • restrict_xpaths
#接受一个XPath表达式或一个XPath表达式列表,提取XPath表达式选中区域下的链接。
le = LinkExtractor(restrict_xpath = '///div[@id="top"]')
  • restruct_css
#接受一个CSS表达式或一个CSS表达式列表,提取CSS选择器选中区域的链接
le = LinkExtractor(restrict_css='div#bottom')
  • tags
#接受一个标签,提取指定标签内的链接。默认['a','area'].
  • attrs
#接受一个属性,提取属性内的链接 ['href']
le = LinkExtractor(tag = 'script',attrs = 'src')
  • process_value
#接受一个形如func(value)的回调函数。若传递了该参数,LinkExtractor将用该函数对每一个链接处理
le  = LinkExtractor(process_value = process)


使用Exporter导出数据

Exproter(导出器)支持文件格式

  • json
  • json Line
  • csv
  • xml
  • Pickle
  • Marshal

指定如何导出数据

  • 文件路径
  • 格式

两种指定方式
1.通过命令行

scrapy crawl books -o books.csv

-o:指定路径(后面跟的文件格式也可以指定格式)
-t :指定格式(可省略 根据-o后面的格式而定)

scrapy crawl books -t csv -o books1.data

以-t参数中的csv为键,在配置字典FEED_EXPORTERS中搜索Exporter,
FEED_EXPORTERS组成:

  • 默认配置文件中的FEED_EXPORTERS_BASE(内部支持导出格式)
  • 用户配置文件FEED_EXPORTERS(用户指定导出格式)

    添加新的导出格式(实现新的Exporter),可在配置文件settings.py中定义

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

指定文件路径时,可以使用%(name)s和%(time)s两个特殊变量:

  • %(name)s:会被替换为Spider的名字
  • %(time)s:会被替换为文件创建时间

使用配置文件会更加方便

  • FEED_URL
#导出文件路径
FEED_URL = 'export_data/%(name)s.data'
  • FEED_FORMAT
#导出文件格式
FEED_FORMAT = 'csv'
  • FEED_EXPORT_ENCONDING
#导出文件编码(默认json使用数字编码,其他使用utf-8)
FEED_EXPORT_FIELDS = 'gbk'
  • FEED_EXPORT_FIELDS
#导出数据包含的字段(默认导出所有字段)并指定次序
FEED_EXPORT_FIELDS = ['name','author','price']
  • FEED_EXPORTERS
#用户自定义Exporter字典,添加新的导出数据格式时使用
FEED_EXPORTERS = {'excel':'my_project.my_exporters.ExcelItemExporter'}

添加导出数据格式
某系情况下,需要添加新的导出数据格式,此时需要实现新的Exporter类
每一个Exporter都是BaseItemExporter的子类,如 jsonItemExporter
BaseItemExporter定义了一些借口待子类实现

  • export_item(self,item)
负责导出爬取到的每一项数据,参数item为一项爬取到的数据,每个子类必须实现该方法
  • start_expoorting(self)
导出开始时被调用,可在该方法中执行某些初始化工作
  • finish_exporting(self)
导出完成时被调用,执行某些清理工作

实例:实现excel导出
在项目中创建一个my_exporters.py(与settings.py同级目录),在其中实现ExcelItemExporter

from scrapy.exporters import BaseItemExporter
import xlwt
#使用第三方库xlwt将数据写入excle
class ExcelItemExporter(BaseItemExporter):def__init__(self,file,**kwarges):self._configure(kwargs)self.file = file#创建Workbook对象和Worksheet对象,并初始化用来记录写入航坐标的self.rowself.wbook = xlwt.Workbook()self.wsheet = self.wbook.add_sheet('scrapy')self.row = 0#finish_exporting在所有数据都被写入Excel表格后被调用,在该方法中用sefl.wbook.save方法将excle写入def finish_exporting(self):self.wbook.save(self.file)def export_item(self,item):files = self._get_serialized_fields(item)for col,v in enumerate(x for _,x in files):self.wsheet.write(self.row,col,v)self.row += 1

完成ExcelItemExporter后,在配置文件settings.py中添加

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

可以使用excel导出数据了

scrapy crawl books -t excle -o book.xls

Scrapy从入门到精通(3)--使用Item封装数据相关推荐

  1. Excel数据分析从入门到精通(十五)数据透视表之动态仪表盘

    Excel数据分析从入门到精通(十五)数据透视表之动态仪表盘 1.绘制销售额汇总情况 2.绘制种类销售额情况+种类销售额占比 种类销售额情况 种类销售占比 3.绘制地区销售额情况和地区销售额占比 地区 ...

  2. Excel数据分析从入门到精通(十五)数据透视表基础

    Excel数据分析从入门到精通(十五)数据透视表 1.Excel透视表前言 2.Excel透视表的创建 3.Excel透视表的组成 4.Excel透视表的十大技巧 ①如何创建汇总行 ②如何展示百分比 ...

  3. 视频教程-赵强老师:大数据从入门到精通(15)Storm-大数据

    赵强老师:大数据从入门到精通(15)Storm 毕业于清华大学,拥有超过13年的工作经验. Oracle认证讲师,拥有6年以上授课经验.精通Oracle数据库.中间(Weblogic)和大数据Hado ...

  4. Scrapy从入门到精通(4)--项目实战爬取图书网站信息

    项目实战 url = http://books.toscrape.com 页面分析 scrapy shell U R L> scrapy shell URL>可以使用户在交互式命令行下操作 ...

  5. 音视频从入门到精通——FFmpeg分离出PCM数据实战

    什么是PCM? PCM(Pulse Code Modulation,脉冲编码调制)音频数据是未经压缩的音频采样数据裸流,它是由模拟信号经过采样.量化.编码转换成的标准数字音频数据. 描述PCM数据的6 ...

  6. 图解AI数学基础:从入门到精通系列教程(要点速查清单·完结)

    作者:韩信子@ShowMeAI 教程地址:https://www.showmeai.tech/tutorials/83 声明:版权所有,转载请联系平台与作者并注明出处 引言 本系列教程展开讲解AI所需 ...

  7. 大数据学习指南从入门到精通

    目录 大数据学习指南从入门到精通 前言 一.大数据基础 二.大数据必学Java基础 三.ZooKeeper 四.大数据环境搭建 五.Hadoop 六.Hive 七.HBase 八.Kafka 九.Sc ...

  8. java框架 零基础从入门到精通的学习路线 附开源项目面经等(超全)

    目录 前言 1. 学习路线 2. 学习方法 前言 这篇文章主要总结我之前所学过的框架以及学习路线 从实打实的零基础到框架再到项目 之后实习工作 也在这篇博客中记录我的学习笔记 以及在笔记中遇到的配置安 ...

  9. Scrapy框架入门

    一.概述 Scrapy,Python开发的一个快速.高层次的屏幕抓取和web抓取框架,用于抓取web站点并从页面中提取结构化的数据. Scrapy用途广泛,可以用于数据挖掘.监测和自动化测试. 其最初 ...

最新文章

  1. poj2195(最大权完美匹配)
  2. P4779 【模板】单源最短路径(标准版)(dijkstra模板)
  3. android开发toast通知,Toast Notifications
  4. Hibernate程序性能优化的考虑要点
  5. pandas 读csv 报错 UnicodeDecodeError: 'utf-8' codec can't decode byte 0xca in position 0: invalid cont
  6. php获取本机root,通过PHP执行root命令
  7. 留言系统 php 防攻击,php 留言板防刷新
  8. 蓝桥杯笔记:DFS(深度优先搜索)解决问题
  9. motrix下载没速度_再见迅雷!高颜值没广告的下载神器Motrix体验
  10. 数字化审图时代批量生成PDF或者DWF利器SmartBatchPlot
  11. 漫画:什么是加密算法?
  12. python gamma函数_Python 不完全伽马函数
  13. Ubuntu截图快捷键
  14. lua工具库penlight--06数据(二)
  15. thinkphp5 自定义分页样式
  16. canvas画布调节字符间距
  17. 总结织梦CMS中的dede标签
  18. 基于Android的家庭医生app
  19. ae形状图层怎样合并路径?
  20. 微信小程序入门教程之四:API 使用

热门文章

  1. 阿里数据大拿的10年经验总结:做好数据库与数据仓库,BI与报表就成功一半
  2. March 27th Tuesday (三月  二十七日 火曜日)
  3. 点播 构造自己的播放器 用户调用获取视频播放地址接口
  4. 南京java开发应届生工资,技术总监都拍手叫好
  5. lisp标定高程_基于Auto Lisp的局部高程点批量检查与修改技术
  6. tkinter-place布局详解
  7. 发展认知神经科学 | 基于可解释的人工智能模型分析婴儿的fNIRS数据
  8. 如何将AVI格式的视频转换为MP4?用嗨格式试试看
  9. 线性代数笔记27——对称矩阵及正定性
  10. UE4 设置基础的车辆动力学