Scrapy爬虫的入门到精通
http://scrapy-chs.readthedocs.io/zh_CN/latest/intro/tutorial.html#id5*
参考书籍 《精通Scrapy网络爬虫》
1.1爬虫的定义和工作概述
网络爬虫指的是在互联网上进行自动爬取网站内容的信息得程序,也被称作网络蜘蛛和网络机器人
基本得爬取流程为:
1.2 Scrapy简介及安装
简介:
Scrapy使用python语言基于Twisted框架编写得开源得网络爬虫框架,目前支持python2.7及python3.4+
安装
pip install scrapy //安装中如果系统提示缺乏依赖文件 pip install wheel //这是一个Twisted的依赖 pip install C:\Users\10338\Downloads\Twisted-17.9.0-cp36-cp36m-win_amd64.whl
1.3编写第一个Scrapy爬虫
需求:爬取网上的信息
创建项目
利用shell使用命令行进行创建
//scrapy startproject 项目名称 scrapy startproject book_spider
from scrapy import cmdline cmdline.execute("scrapy crawl LG_Spider -o LG_Spider.csv".split())
编写代码(在pycharm中添加scrapy工程)
import scrapy class BooksSpider(scrapy.Spider): #定义一个爬虫 name = "books" #定义爬虫的起点 start_urls = ['http://books.toscrape.com/'] def parse(self, response): #提取数据 #获取每一本书的信息都在标签 class=“b-all-content cf” #利用CSS的方法找到所有的元素,并一次迭代 for book in response.css('article.product_pod'): book_name = book.xpath('./h3/a/@title').extract_first() book_price = book.xpath('p.price_color::text').extract_first() yield {'book_name':book_name, 'book_price':book_price, } #提取链接 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)
extract.frist()返回字符串 extract 返回数组
name 属性:在一个scrapy中可能存在多个爬虫,name属性是爬虫的唯一的区分。
start_urls属性:爬虫要从某个页面开始爬取,也就是起始抓取点。
parse:一个页面抓取成功后,Scrapy会回掉一个我们指定的页面解析函数(默认的就是parse方法 )。
attr()jQuery。返回被选元素的属性值
1.34 运行爬虫
scrapy crawl books -o books.csv
获取的信息将会保存在books.csv的文件中。
2 编写Spider
2.1scrapy框架的结构机工作原理
引擎(scrapy)
用来整理整个系统的数据流处理。触发事件
调度器(Scheduler)
用来接受引擎发过来的请求,压入队列,并在引擎再次请求的时候返回,可以认为是一个URL的优先队列,由他来决定下一个要抓取的网址是什么,同时去除重复的网址。
下载器(Downloader)
用于下载网页内容,并将网页的内容返回给spider下载器是建立在twisted这个高效的异步模型上的
爬虫(spiders)
爬虫(工农阶级)主要干活的,用于从intenet爬取信息,也就所谓的实体。用户也可以从中提取出链接,让spider继续爬取下一个网页
项目管道(pipline)
负责处理爬虫从网页中抽取的实体,主要的功能是持久化实体,验证实体的有效性,清除不需要的信息,当页面页面爬虫解析后,将被发送到项目管道,并经过几个特定的次序的处理数据。
下载器中间件(Dowloader Middlewares)
位于Scrapy引擎和下载器之间框架,主要用处处理Scrapy引擎于下载器之间的请求和响应
爬虫中间件(Spider Middlewares)
介于Scrapy引擎和Spider之间的框架,主要是处理Scrapy引擎与Spider之间的请求和响应
调度中间值(Scheduler MIddewares)
介于Scrapy引擎和调度器之间的框架,从Scrapy引擎发送到调度的请求和响应
scrapy的工作流程
1.引擎从调度器上去取出一个链接(URL)用于接下来的爬取
2.引擎把URL封装成一个请求(request)传给下载器
3.下载器把资源下载下来,并封装成应答包(response)
4.爬虫解析response
5.解析出实体(Item),则交给实体管道进行进一步的处理
6.解析出的是链接(URL),则把URL交给调度器等待抓取
2.2 Request和Response
2.2.1 Request
request(url[,callback,method='GET',headers,boday,cookies,meta,encoding='utf-8',priority=0,dont_filter =false,errback])
~url :请求地址
~callback:页面解析函数,callback类型,request对象请求的页面下载 完成后,有该参数指定的页面解析被调用,未被调用时spider默认调用parse方法。
~method:HTTP的请求方法,默认为GET方法。
~headers:HTTP请求的头部字典,dict类型,例如{‘A':'a','B':'b'}如果内部某项的值为NONE,就表明不发送该项的头部,例如:{‘C’:None},禁止发送C
~body:HTTP请求的正文,bytes或str类型
~cookies:信息字典,dict类型
~meta:request的元数据字典,meta标签永远位于head元素的内部。头部的元信息——用来描述信息的结构,语法,用途及用法等等‘。
~encoding:编码格式。
~priority:设置请求的优先级。
~dont_filter:默认情况下值为False,值个更改为True可以请求避免被过滤,强制下载。
~errback:错误返回。
import scrapy request = scrapy.Request('地址') request = scrapy.Request('地址',callback=self.parseItem)
2.2.2Response对象
页面下载完成后,搞一个Response的子类对象出来,子类有TextResponse、HtmlResponse、XmlResponse,由于通常都是搞网页玩,所以一般使用HtmlResponse,注意TextResponse是HtmlResponse和XmlResponse的父类。
~url:HTTP响应的url地址,str类型。
~status:HTTP响应的状态码。
~headers:HTTP响应的头,dict类型。
~body:HTTP响应正文,bytes里类型
~text:文本形式正文向应。
~encoding:编码格式。
~request :产生该HTTP响应的Request的对象。
~meta:即response.request.meta,构造Request对象时可以取出response.meta信息。
~selector: Selector对象 用于在response中提取数据(选择器)、
~Xpath(query):使用xpath在response中提取数据,实际上是response.selector.xpath方法的快捷方式。
~css(query):使用CSS选择器在response中数据提取。实际为response.selector.css方法的快捷方式。
~urljoin:用于构造绝对url.当传入url参数四一个相对的地址时,根据response.url计算出相应的绝对的url.
常用的方法为:css xpath 进行数据的提取,利用urljoin进行构造绝对的url.
2.3Spider的开发流程
开发的四个步骤:
1.继承scrapy.Spider
2.为Spider取名
3.设置起始爬取点。
4.实现页面解析函数。
2.3.1继承scrapy.Spider
Scrapy框架提供了一个Spider基类,。
在Spider基类中实现了:
1.供Scrapy引擎调用的接口
2.供用户使用的实用工具函数
3。供用户访问的属性。
2.3.2为spider命名
一个项目中可以实现多个spider,name属性时区分这些工作的小爬爬的唯一属性。在执行scrapy crawl时就会用到这个标识了
2.3.3设定起始爬取点
Spider爬去的起始网页,start_urls 通常是一个列表,其中放入所有得爬取点url。
2.3.4实现页面解析函数
页面解析函数,也就是构造Request对象时通过callback参数指定的回掉函数(或者parse方法)。需要完成的工作:
1.使用选择器提取页面中的数据,数据封装(Item或dict)提交给Scrapy引擎
2.使用选择器或者LinkExtractor提取页面中的链接,用其构造新的request对象并提交给Scrapy引擎
3 Selector对象
常用的处理HTML页面解析的模块
~BeatifulSoup
~LXML
Scrapy结合了两者实现了Selector类,使用先通过Xpath或者CSS选择器选中页面下的数据,然后提取
3.1.1创建对象
创建Selector对象时,可将页面的HTML文档字符串传递给Selector构造器的方法的text参数数;也可以利用Response对象构造Selector对象将其传递给Selector构造器方法的response参数。
3.1.2选中数据
利用Xpath和css方法
由于Selenium使用xpath定位时采用遍历页面的方式,在性能上采用CSS选择器的方式更优。xpath虽然性能指标比差,但是在了浏览器中有比较好的插件支持,定位元素比较方便,对于性能要求严格的可以交替使用。
Xpath:
xpath使用路径表达式在xml文档中进行导航
xpath包含一个标准的函数库
xpath是XSLT(将xsl转换,xsl是可扩展样式表语言)中的主要元素
xpath是一个W3C标准(web的技术标准)
在xpath中,有七种类型的节点:元素、属性、文本、命名空间、处理指令、注释一级文档(根节点)。XML文档是被作为树来对待的,树的根被称为文档节点或者根节点。
xpath和css方法返回一个SelectorList对象,其中包含每个被选中部分对应的Selector对象,SelelctorList支持列表接口,可以使用for语句访问其中的每一个Selector对象:
for sel in selector_list: print(sel.xpath('./text()'))
selector_list对象也有xpath和css方法,调用他们的行为是:以接受到的参数分别调用其中每一个Selector对象的xpath和CSS方法,并将其所有的结果收到一个新的SelectorLiist对象返回给用户eg:
>>>selector_list.xpath('./text()') [<Selector xpath='./text()'data='hello world'>,<Selector xpath='./text()'data='Hello world'>]
3.1.3 提取数据
调用Selector和SelectorList对象的方法:extract()、re()、extract_first()、re_first()(后两个为SelectorList专有)
1.extract()方法
调用Selector对象的extract方法将返回选中内容的Unicode字符串,与SelectorList对象的xpath和css类似, SelectorList对象的extract方法内部会调用其每个Selector对象的extract方法,并把所有的结果收集到一个列表返回给用户.
2.extract_first()
该方法放回其中第一个Selector对象调用extract方法的结果。在selectorList对象只包含一个Selector对象时调用该方法,直接提取出Unicode字符串而不是列表。
3.re和re_first
利用正则表达式提取内容的某部分,可以使用re方法,re_first方法同样返回其中的第一个Selector对象调用re方法的结果。
3.2 Response内置Selector
其实在应用过程中,几乎不需要手动创建Selector对象,在第一次访问一个Response对象的selector属性时,Response对象内部会以自身为参数自动创建Selector对象,并将该Selector对象缓存,方便下次使用。
知识点补充:@propety 属性修饰
例子:
class Student(object): def __init__(self,name;score): self.name = name self.score = score @property def score(self): return self.__score @score.setter def score(self,score): if score < 0 or score > 1000: raise ValueError('invaid score') self.__score = score
注意啦:第一个Score(self)是get 方法,用@property装饰,第二个score(self,score)是set方法,用@score.setter装饰,@score.setter是前一个@property装饰后的副厂品。
score属性设置。
>>> s = Student('Bob', 59) >>> s.score = 60 >>> print s.score 60 >>> s.score = 1000 Traceback (most recent call last): ... ValueError: invalid score
3.3Xpath
XPath也就是XML路径语言(XML Path Language)
Xpath的常用基本语法
3.3.1基础语法
表达式 | 描述 |
---|---|
/ | 选中文档的根(root) |
. | 选中当前节点 |
.. | 选中当前节点的父节点 |
ELEMENT | 选中子节点中所有ELEMENT元素节点 |
//ELEMENT | 选中后代节点中所有ELEMENT元素节点 |
* | 选中所有元素的子节点、 |
text() | 选中所有文本子节点 |
@ATTR | 选中名字为ATTR的属性节点 |
@* | 选中所有属性节点 |
[谓语] | 谓语用来查找某个特定的节点或者包含某个特定值得节点 |
<html> <head> <base href='http://example.com/'/> <title>Example website</title> </head> <body> <div id='images'> <a href='image1.html'>Name:Image 1<br/><img src='image1.jpg'></a> <a href='image1.html'>Name:Image 2<br/><img src='image2.jpg'></a> <a href='image1.html'>Name:Image 3<br/><img src='image3.jpg'></a> <a href='image1.html'>Name:Image 4<br/><img src='image4.jpg'></a> <a href='image1.html'>Name:Image 5<br/><img src='image5.jpg'></a> <a href='image1.html'>Name:Image 6<br/><img src='image6.jpg'></a> </div> </body> </html>
from scrapy.selector import Selector from scrapy.http import HtmlResponse response = HtmlResponse(url = 'http://www.example.com',body=body.encoding='utf8') response.xpath('/html') response.xpath('/html/head') response.xpath('/html/body/div/a') response.xpath('//a')
3.3.2常用语法
这部分内容查阅填充
xpath提供许多函数,例如数字、字符串、时间、日期、统计等等。
string(arg)返回参数的字字符串值。
3.4 CSS选择器
CSS即层样式表器,其选择器是一种来确定HTML文档某部分位置的语言。CSS使用起来比xpath简单,但是不如xpath功能强。
实际上在使用CSS方法时,python库将cssselect将CSS选择器表达式翻译成xpath表达式然后调用Selector对象的Xpath方法。
CSS选择器
表达式 | 描述 | 例子 |
---|---|---|
* | 选中所有元素 | * |
E | 选中E元素 | p |
E1,E2 | 选中E1,E2元素 | div,pre |
E1>E2 | 选中E1后代元素中的E2元素 | div p |
E1+E2 | 选中E1兄弟元素中的E2元素 | p+strong |
.CLASS | 选中CLASS属性包含CLASS的元素 | .info |
#ID | 选中id属性为ID的元素 | #main |
[ATTR] | 选中包含ATTR属性的元素 | [href] |
[ATTR=VALUE] | 选中包含ATTR属性且值为VALUE的元素 | [method=post] |
[ATTR~=VALUE] | 选中ATTR属性且值包含Value的元素 | [class~=clearfix] |
E:nth-child(n) E:nth-last-child(n) | 选中E元素,且该元素必须是其父元素的(倒数)第n个子元素 | a:ntn-child(1) a:nth-last-child(2) |
E:first-child E:last-child | 选中E元素且该元素必须是其父元素的(倒数)第一个子元素 | a:first-child a:last-child |
E:empty | 选中没有子元素的E元素 | div:empy |
E:text | 选中E元素的文本节点(Text Node) |
第4章 使用Item进行数据封装
4.1Item和Field
Item基类:自定义数据类(支持字典的接口)
field类:用来描述自定义数据类包含哪些字段
自定义一个数据类,只需要继承Item,并创建一系列的Field对象的类属性
对字段赋值时,如果是内部没有的字段,这时会抛出异常。
实际上Field是Python字典的子类,可以通过键获取Field对象中的元数据
改写之前的代码
from scrapy import Item,Field class BookSpiderItem(scrapy.Item): name = Field() price = Field()
修改之前的BooksSpider,使用BookItem替代Python字典
from ..Item import BookSpiderItem class BooksSPider(scrapy.Spider): def parse(self,response): for sel in response.css('article.product_pod'): book = BookSpiderItem() book['name'] = sel.xpath('./h3/a/@title').extract_first() book['price'] = sel.css('p.price_color::text').extract_frist() yield book
4.2拓展Item子类
在ltem中添加新的字段利用 Field()类的属性。
4.3field元数据
一项数据由Spider提交给Scrapy引擎后,可能会提交给其他组件进行处理(Item Pipline Exporter)处理,假设想传递额外的信息给处理数据的某个组件(例如,高手组件应该如何处理数据),此时可以使用Field的元数据。
第五章 使用Item Pipeline处理数据
进行数据处理,一个项目中可以启用多个Item Pipeline ,它的典型应用
清洗数据
验证数据的有效性
过滤重复的数据
将数据存入数据库
5.1实现 Item pipeline
项目创建时会生成一个pipelines.py的文件,
(1)一个Iltem Pipleine 不需要继承特定基类、只需要实现某些特定的方法,例如 process-_Iitem open_spider close_spider
(2)一个item Pipeline 必须实现一个process_item(item,spider)方法,该方法用来处理每一项由spider爬取的数据,其中每两个参数
Item 爬取到的一项数据(Item或字典)。
Spider 爬取此项数据的spider对象。
(3)如果process_item在处理某项item返回了一项数据(Item或字典),返回的数据会递送给下一极Item pipeline继续处理。
(4)如果process_Item在处理某项item时抛出(raise)一个Droptem异常(scarpy.exceptions.DropItem),该项Item会被抛弃,不再递送给后面的Item pipeline 继续处理,也不会导出到文件,通常,我们再检测到无效数据或过滤数据时我们会抛出DropItem异常。
(5)open_spider(self,spider)
Spider打开时(处理数据之前)回调该方法,通常该方法用于再开始处理数据之前完成某些初始化工作,如链接数据库
(6)close_spider(self,Spider)
Spider关闭时(处理数据后)回调该方法,通常该方法用于处理完所有数据之后完成清理工作,如关闭数据库。
(7)from_crawlwer(cls,crawler)
创建Item Pipeline 对象时回调该类方法,通常在该方法中通过crawler.settings读取配置,根据配置创建Item pipeline对象。
5.2启用 Item pipeline
在scrapy中。想要启用某个Item Pipleine 需要在配置文件settings.py中进行配置:
ITEM_PIPELINES = { 'example.piplines.priceConverPipeline':300, }
ITEM_PIPELINES是一个字典。我们把想要启用的Item Pipeline添加到这个字典中,值为0~1000的数字,数字越小越先执行。
实现
class PriceConveterPipeline(object): exchange_rate = 8.5209 def process_item(self,item,spider): price = float(item['price'][1:])*self.exchange_rate item['price']='¥%.2f'%price
代码解释Item Pipeline不需要继承特定的基类。只需要实现某些特定的方法例如process_item、oepn_spider、close_spider.
上述的实现方法很简单将书籍的英镑价格转换为浮点数乘以汇率并保留两位小数,然后赋值给item中的price字段,最后返回被处理过的item。
可以看出,process_item在处理某项item时返回了一项数据(Item或者字典),返回的数据会递送给下一级的process_item(如果有)继续处理
5.3例子
过滤重复的数据,处理重复的数据,代码如下:
from scrapy.exceptions import DropItem class DuplicationPipeline(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
增加构造器的方法,在其中初始化用于对书名去重的集合。
在process_item 方法中,先取出item的name字段,检查书名是否已经在集合book_set中,如果存在,就是重复数据,抛出DropItemy异常,将item抛弃,否则将item的name字段存入集合返回item.
5.4将数据存入MongoDB
把数据存放到某种数据库中,可以通过实现Item Pipeline完成
例子:
from scrapy.item import Item import pymongo class MongoDBPipeline(object): DB_URI = 'mongodb://loaclhost:27017/' DB_NAME = 'scrapy_data' def open_spieder(self,spider): self.client = pymongo.MongoClient(self.DB_URI) self.db = self.client[self.DB_NAME] def close_spider(self,spider): self.client.close() def process_item(self,item,spider): collection = self.db[spider.name] post = dict(item)if isinstance(item,item)else item collection.insert_one(post) return item
代码解释:
在类属性中定义两个常量:DB_URI 数据库的URI地址
DB_NAME 数据库的名字
spider爬取时数据库的连接只需要执行一次,应该在开始数据处理之前连接数据库,并且在处理完数据库之后关闭数据库实现open_spider(spider)和close_spider(spider)。
在process_item中实现MongoDB数据库的写入,使用self.db和spider.name获取集合collection,然后将数据插入集合,集合的insert_one方法需要传入一个字典对象,不能时item对象,因此在使用前对item的类型进行判断,如果时item对象就转换为字典。
在settings.py文件中启用MongoDBPipelien:
ITEM_PIPELINES = { 'example.pipelines.PriceConverterPipeline':300 'example.pipelines.MongoDBPipline':400 }
第六章 使用LinkExtractor提取链接
在爬取时,页面中会存放很多的其他网页的链接信息,有时我们需要提取这些信息,一般使用的提取方法有Selector和LinkExtractor两种方法
1.Selector 因为链接也是页面中的数据,所以使用提取数据相同的方法就可以了,在提取少量的数据的时候,链接的提取方法比较简单,使用Selector也就是足够了。
2.LinkExtractor scarpy提供了一个专门的用于提取链接的类LinkExtractor,在提取大量链接或提取规则比较复杂时,使用Link Extractor比较方便。
class BooksSpider(scrapy.SPider): def parse(self,reponse): #提取链接 #下一页的url信息在ul.pager>li>a里面 next_url = response.css('ul.pager.li.next.a::attr(href)').extract_first() if next_url: #如果找到下一页的绝对路径构造新的response对象 next_url = response.urljoin(next_url) yield scrapy.Request(next_url,callback=self.parse)
6.1使用Link Extractor
from scrapy.linkExtractors import LinkExtractor class BooksSpider(scarpy.Spider): def parse(self,reponse): le = LinkExtractor(restrict_css='ul.pager li.next') links = le.extract_links(reponse) if links: next_url = links[0].url yield scrapy.Request(next_url,callback=self.parse)
导入LinkExtractor,它位于scrapy.linkExtractors模块
创建一个linkExtarctor对象,使用一个或者多个构造器参数描述提取规则,这里传递给restrict_css参数一个CSS选择器表达方式。他描述出下一页链接所在的区域下。
调用LinkExtarctor对象的extract_Links方法传入一个Response对象,该方法依靠创建的对象时所描述的提取规则在Response对象所包含的页面中提取链接,最终返回一个列表,其中每个元素都是一个Link对象,也就是提取到的一个链接,最终返回一个列表,每个元素都是一个Link对象。
由于页面的提取一页的下一个链接只有一个,因此用Links[0]获取到的信息,因此用Links[0]获取Link对象,Link对象的url属性便是链接页面的绝对URL地址(无须再调用response.urljoin方法),在用Request构造并进行提交。
6.2 描述提取规则
学习使用LinkExtractor的构造器参数描述提取规则
<<<<<<!--example.html> <html> <body> <div di="top"> <a class="internal"herf="/intro/install.html">Installation guide</a> <a class="internal"herf="/intro/install.html">Tutorial</a> <a class="internal"herf="/intro/install.html">Examples</a> </div> <div> <p>下面时一些站外链接</p> <a href="http://stackoverflow.com/tags/scrapy/info">StackOverflow</a> <a href="http;//github.com/scrapy/scrapy">Fork on</a> </div> </body> </html>
<html> <head> <script type='text/javascript'src='/js/app1.js/'/> <script type='text/javascript'src='/js/app2.js/'/> </head> <body> <a href="/home.html">主页</a> <a href="javascript:goToPage('/doc.html');return false">文档</a> <a href="javascript:goToPage('/example.html');return false">案例</a> </body> </html>
使用以上两个HTML文本构造两个Response对象
from scrapy.http import HtmlResponse html1 = open('example.html1').read() html2 = open('example.html2').read() reponse1 = HtmlResponse(url='http://example.com',body=html,encoding='utf8') reponse2 = HtmlResponse(url='http://example.com',body=html,encoding='utf8') #构造Html文本的两个Response对象
注意:LinkExtractor构造器所有参数都拥有默认值,在不做说明的情况下,就会使用默认值。
from scrapy,linkextractor import LinkExtractor le = LinkExtractor() links = le.extract_links(reponse1) print([link.url for link in links])
LinkExtractor的参数:
——allow 接受一个正则表达式或者一个正则表达式的列表,提取绝对的url与正则表达式匹配的链家,如果该参数为空,就提取全部链接。
#提取页面example.html中的路径以/info开始的 from scrapy.linkExtractors import LinkExtractor pattern = '/info/.+\.html$' le = LinkExtractor(allow=patten) links = le.extract_links(response1) print(link.url for link in links)
——deny 接受一个正则表达式或者一个正则表达式的列表,与allow相反,排除绝对和url匹配的链接
#提取example.html1中是所有站外链接排除站内链接 from scrapy.linkExtractors import LinkExtractor from urllib.parse import urlparse pattern = patten = '^'+urlparse(reponse1.url).geturl() print(pattern)
——allow_domains 接受一个域名或一个域名的列表,提取到指定域的链接
#提取页面example1.html中所有到GitHub和stackoverflow.com这两个网址的链接 from scrapy.linkextractors import LinkExtarcot domains = ['github.com','stackoverflow.com'] le = LinkExtractor(allow_domains=domains) links = le.extract_links(reponse1) print([link.url link in links])
——deny_domains 接受一个域名或者一个域名列表,与allow_domains相反,排除到指定域的链接
#提取页面example,html中除了GitHub.com域以外的链接 from scrapy.linkextractors import LinkExtractor le = LinkExtractor(deny_domains='github.com') links = le.extract_links(response1) print([link.url for link in links])
——restrict_xpaths 接受一个Xpath表达式或一个Xpath的列表,提取Xpath表达式中区域下的链接
#提取页面example.html中<div id="top">元素下的链接: from scrapy.linkextractors import LinkExtractor le = LinkExtractor(restrict_xpath='//div[@id="top"]') links = le.extract_links(response) print([link.url for link in links])
——restrict_css 接受一个CSS表达式或者一个CSS的列表 ,提取CSS表达式下的区域链接
#提取页面的example.html中<div id="botton">元素下链接 from scrapy.linkextractors import LinkExtractor le = LinkExtractor(restrict_css='div#bottom') links = le.extract_links(response1) print([link.url for link in links])
——tags 接收一个标签(字符串)或一个标签列表,提取指定的标签内的链接默认为['a','area']
——attrs 接收一个属性(字符串)或一个属性列表,提取指定属性内的链接,默认为['href']
#提取页面example2.hml中引用JavaScript文件链接 from scrapy.linkextractors import LinkExtractor le = LinkExtractor(tags='script',attrs='sec')
——process_value 接收形如func(value)的回调函数。如果使用了该函数,LinkExtractor将回调该函数,对提取的每一个链接(如a的harf)进行处理,回调函数正常情况下应返回一个字符串,也就是处理结果,想要抛弃所处理的链接时,返回None。
import re def process(value): m = re.search("javascript:goTopage\('(.*?))'",value) if m: value = m.group() return value from scrapy.linkextractors import LinkExtractor le = LinkExtractor(process_value=porcess) links = le.extract_link(response2) print([link.url for link in links])
第七章 使用Exporter导出数据
scrapy中有负责导出数据的组建被叫做Exporter(导出器),scrapy中有多个导出器,每个都对应一种数据格式的导出,支持的数据如下
(1)JSON ——JsonItemExporter
(2)JSON Lines ——JsonLinesItemExporter
(3)CSV ——CsItemExpoter
(4)XML——XmlItemEporter
(5)Pickle——PickleItemExporter
(6)Marshal——MarshalExpotrer
7.1指定如何导出数据
在进行数据导出时,我们需要向Scapy提供,导出文件的路径和导出的数据格式,就是在说要将什么人样的人,从那个地方喊出来。
可以通过命令行参数指定或配置文件指定
在运行scrapy crawl命令时可以通过-o 和-t 参数指定导出文件路径以及导出文件的数据的格式。
scrapy crawl books -o books.csv
其中的 -o books.csv就指定了文档的导出路径,虽然没有使用-t参数指定导出的数据格式,但是Scrapy爬虫通过文件后缀名推断出我们以csv的格式将数据导出,同样的,如果将数据改为-o books.json就会与以json的格式将数据导出。需要明确指定导出路径时使用-t参数。
scrapy crawl books -t csv -o book1.data scrapy crawl books -t json -o book2.data scrapy crawl books -t xml -o book3.data
在配置字典FEED_EXPORTERS中搜索Exporter,PEED_EXPORTERS的内容合并而成,默认配置文件中的FRRD_EXPORTERS_BASE,用户配置文件中的FEED_EXPORTERS。
前者包含内部支持的导出数据格式,后者包含导出用户自定义的导出数据格式。如果用户添加了新的导出数据格式(即实现了新的exporter),可以在配置问价settings.py中定义FEED_EXPORTERS例如:
FEED_EXPORTERS={'excel':'my_project.my_exporters.ExcellemExporter'}
在指定文件路径时,还可以使用%(name)s和%(time)s两个特殊变量,%(name)s会被替换成Spider的名字,%(time)s会被替换为件创建时间。
配置文件,看下如何在配置文件中导出数据,
FEED_URL 导出路径
FEED_URL= 'exporter_data/%(name)s.data'
FEED_FORMAT 导出格式
FEED_FORMAT= 'csv'
FEED_EXPORT_ENCODING 导出文件编码,注意在默认情况下json文件使用数字编码,其他的使用utf-8编码
FEED_EXPORT_ENCODING = 'gbk'
FEED_EXPORT_FILEDS 导出数据包含的字段,默认情况下导出所有字段,并指定次序
FEED_EXPORT_FILEDSv={'name','author','price'}
FEED_EXPORTERS 用户自定义数据格式
FEED_EXPORTERS= {'excel':'my_project.my_exporters.ExcelItemExporter'}
7.2实现Exporter
exporter_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串,然后写入文件。
#在项目中创建一个my_exportes.py(与settings.py同级目录),在其中实现ExcelItemExporter from scrapy.linkexporters 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): filed = self._get_serialized_fileds(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。
在exporter_item方法中调用基类的_get_serialized_fileds方法,获得item所有字段的迭代器,然后调用self.wsheet.write方法将各字段写入excel表格。
finish_exporting方法在所有数据都被写入Excel表格被调用,在该方法中调用self.wbook.save方法将Excel表格写入Excel文件
完成数据导出的编写之后子啊settings.py文件中添加配置
FEED_EXPORTERS = {'excle':'example.my_exporters.ExecelitemExporter'}
利用命令行运行爬虫
scrapy crawl books -t excel -o books.xls
第八章 项目练习
需求:爬取网址“http://books.toscrape.com/”网址的书籍信息。信息包括:书名‘、价格、评价星级、评价数量、书籍编码和库存量。详细源码见GitHub最后将爬取到的数据输出到book.csv文档中。
第九章 下载文件和爬取图片信息
在scrapy中提供了两个Item Pipeline,专门用来下载文件和图片Files Pipeline 和ImagesPipeline,可以将这两个Item Pipeline看做是特殊的下载器,用户通过item的一个特殊字段将要下载的文件信息或图片信息的url传递给他们,他们会自动将文件或图片下载到本地,并将下载的结果信息存入item的另一个字段,以便用户在导出文件中查阅。
FilePipeline使用方法:
1.在配置文件中启用FilesPipeline,通常将其置于其他的Item Pipeline之前
ITEM_PIPELINS = {'scarpy pipelines.files.FilesPipeline'}
2.在配置文件中使用FIFLES_STORE 指定文件下载的目录。例如
FILE_PIPELINS = {'/home/lxs/Dowload/scrapy'}
3.在spider中解析一个包含文件下载链接的页面时将所有需要下载的文的url的地址收集到一个列表,赋值给item的file_url字段(item['file_url'])。FIlePipeline在处理每一项Item时,会读取item['file_urls'],对其中每一个url进行下载。
class DownloadBookSpider(scrapy.Spider): pass def parse(response): item = {} #下载列表 item['file_urls'] = [] for url in response.xpath('//a@href').extract(): download_url = response.urljoin(url) #将url填入列表 item['file_urls'].append(download_url) yield item
当 FilePipeLine 下载完item['file_urls']中的所有的文件之后,会将各文件的下载结果信息收集到一个列表,赋值各给item的files字段(item[files]).下载结果包括:Path 文件下载到本地的相对路径,checksum 文件的检验和,url 文件的url地址。
``