Scrapy从入门到精通(3)--使用Item封装数据
使用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封装数据相关推荐
- Excel数据分析从入门到精通(十五)数据透视表之动态仪表盘
Excel数据分析从入门到精通(十五)数据透视表之动态仪表盘 1.绘制销售额汇总情况 2.绘制种类销售额情况+种类销售额占比 种类销售额情况 种类销售占比 3.绘制地区销售额情况和地区销售额占比 地区 ...
- Excel数据分析从入门到精通(十五)数据透视表基础
Excel数据分析从入门到精通(十五)数据透视表 1.Excel透视表前言 2.Excel透视表的创建 3.Excel透视表的组成 4.Excel透视表的十大技巧 ①如何创建汇总行 ②如何展示百分比 ...
- 视频教程-赵强老师:大数据从入门到精通(15)Storm-大数据
赵强老师:大数据从入门到精通(15)Storm 毕业于清华大学,拥有超过13年的工作经验. Oracle认证讲师,拥有6年以上授课经验.精通Oracle数据库.中间(Weblogic)和大数据Hado ...
- Scrapy从入门到精通(4)--项目实战爬取图书网站信息
项目实战 url = http://books.toscrape.com 页面分析 scrapy shell U R L> scrapy shell URL>可以使用户在交互式命令行下操作 ...
- 音视频从入门到精通——FFmpeg分离出PCM数据实战
什么是PCM? PCM(Pulse Code Modulation,脉冲编码调制)音频数据是未经压缩的音频采样数据裸流,它是由模拟信号经过采样.量化.编码转换成的标准数字音频数据. 描述PCM数据的6 ...
- 图解AI数学基础:从入门到精通系列教程(要点速查清单·完结)
作者:韩信子@ShowMeAI 教程地址:https://www.showmeai.tech/tutorials/83 声明:版权所有,转载请联系平台与作者并注明出处 引言 本系列教程展开讲解AI所需 ...
- 大数据学习指南从入门到精通
目录 大数据学习指南从入门到精通 前言 一.大数据基础 二.大数据必学Java基础 三.ZooKeeper 四.大数据环境搭建 五.Hadoop 六.Hive 七.HBase 八.Kafka 九.Sc ...
- java框架 零基础从入门到精通的学习路线 附开源项目面经等(超全)
目录 前言 1. 学习路线 2. 学习方法 前言 这篇文章主要总结我之前所学过的框架以及学习路线 从实打实的零基础到框架再到项目 之后实习工作 也在这篇博客中记录我的学习笔记 以及在笔记中遇到的配置安 ...
- Scrapy框架入门
一.概述 Scrapy,Python开发的一个快速.高层次的屏幕抓取和web抓取框架,用于抓取web站点并从页面中提取结构化的数据. Scrapy用途广泛,可以用于数据挖掘.监测和自动化测试. 其最初 ...
最新文章
- poj2195(最大权完美匹配)
- P4779 【模板】单源最短路径(标准版)(dijkstra模板)
- android开发toast通知,Toast Notifications
- Hibernate程序性能优化的考虑要点
- pandas 读csv 报错 UnicodeDecodeError: 'utf-8' codec can't decode byte 0xca in position 0: invalid cont
- php获取本机root,通过PHP执行root命令
- 留言系统 php 防攻击,php 留言板防刷新
- 蓝桥杯笔记:DFS(深度优先搜索)解决问题
- motrix下载没速度_再见迅雷!高颜值没广告的下载神器Motrix体验
- 数字化审图时代批量生成PDF或者DWF利器SmartBatchPlot
- 漫画:什么是加密算法?
- python gamma函数_Python 不完全伽马函数
- Ubuntu截图快捷键
- lua工具库penlight--06数据(二)
- thinkphp5 自定义分页样式
- canvas画布调节字符间距
- 总结织梦CMS中的dede标签
- 基于Android的家庭医生app
- ae形状图层怎样合并路径?
- 微信小程序入门教程之四:API 使用