Scrapy一个开源和协做的框架,其最初是为了页面抓取 (更确切来讲, 网络抓取 )所设计的,使用它能够以快速、简单、可扩展的方式从网站中提取所需的数据。但目前Scrapy的用途十分普遍,可用于如数据挖掘、监测和自动化测试等领域,也能够应用在获取API所返回的数据(例如 Amazon Associates Web Services ) 或者通用的网络爬虫。css
Scrapy 是基于twisted框架开发而来,twisted是一个流行的事件驱动的python网络框架。所以Scrapy使用了一种非阻塞(又名异步)的代码来实现并发。总体架构大体以下html
一、scrapy的工做流程python
第一步:爬虫从spiders爬行器中发送request请求给engine引擎。web
第二部:引擎发送request请求给scheduler调度器,调度器从中调度请求,并要求下一个请求进来。ajax
第三部:调度程序将第一个请求返回给引擎。正则表达式
第四部:引擎将请求发送给下行加载程序downloader,经过下行加载中间件,而且准备下载网页。shell
第五步:一旦页面完成下载后,Downloader会生成一个响应(使用该页面)并将其发送到引擎,经过Downloader中间件到达downloader下载器数据库
第六步:引擎接收来自Downloader的响应,并将其发送给爬行器进行处理,经过爬行器中间件,到达爬行器浏览器
第七步:爬行器处理响应信息,并将处理后的结果经过爬行器中间件返回到引擎。网络
第八步:引擎将处理过的数据发送到项目管道,而后将处理过的请求发送到调度程序,并请求可能的下一个请求进行爬行。
总结:
一、引擎负责控制系统全部组件之间的数据流,并在某些动做发生时触发事件
二、调度器用来接受引擎发过来的请求, 压入队列中, 并在引擎再次请求的时候返回. 能够想像成一个URL的优先级队列, 由它来决定下一个要抓取的网址是什么, 同时去除重复的网址
三、下载器用于下载网页内容, 并将网页内容返回给EGINE,下载器是创建在twisted这个高效的异步模型上的
四、爬虫器SPIDERS是开发人员自定义的类,用来解析responses,而且提取items,或者发送新的请求
五、项目管道在items被提取后负责处理它们,主要包括清理、验证、持久化(好比存到数据库)等操做
六、下载器中间件位于Scrapy引擎和下载器之间,主要用来处理从EGINE传到DOWLOADER的请求request,已经从DOWNLOADER传到EGINE的响应response,你可用该中间件作如下几件事情
一、在发送到下载程序以前处理一个请求(即在剪贴簿发送请求到网站以前);
二、在将其传递给蜘蛛以前,更改接收到响应;
三、发送一个新的请求,而不是传递接收到的响应;
四、在不获取web页面的状况下对爬行器进行响应;
五、悄悄地放弃一些请求。
七、爬虫中间件
位于EGINE和SPIDERS之间,主要工做是处理SPIDERS的输入(即responses)和输出(即requests)
官网连接:https://docs.scrapy.org/en/latest/topics/architecture.html
#Windows平台 一、pip3 install wheel #安装后,便支持经过wheel文件安装软件,wheel文件官网:https://www.lfd.uci.edu/~gohlke/pythonlibs 3、pip3 install lxml 4、pip3 install pyopenssl 五、下载并安装pywin32:https://sourceforge.net/projects/pywin32/files/pywin32/ 六、下载twisted的wheel文件:http://www.lfd.uci.edu/~gohlke/pythonlibs/#twisted 七、执行pip3 install 下载目录\Twisted-17.9.0-cp36-cp36m-win_amd64.whl 8、pip3 install scrapy #Linux平台 一、pip3 install scrapy
#1 查看帮助 scrapy -h 或者是scrapy -l scrapy <command> -h #2 有两种命令:其中Project-only必须切到项目文件夹下才能执行这种命令是局部命令,而Global的命令则不须要,是属于全局命令 Global commands:全局命令 一、startproject #建立一个爬虫项目,至关于建立了个爬虫的总体框架,
scrapy startproject 项目名称 二、genspider #建立一个爬虫程序,能够在配置文件中将网址域名注释调,该网址域名的做用就是在网站的html中只容许爬该网址的数据
scrapy genspider 爬虫名称 须要爬的网址域名 三、settings #若是是在项目目录下,则获得的是该项目中settings的配置,不然不是,
scrapy settings --get=settings文件中的配置变量 四、runspider #运行一个独立的python文件,没必要建立项目,这个python文件能够是一个爬虫程序
scrapy runspider 爬虫文件的绝对路径 五、shell # 在交互式调试,如选择器规则正确与否都是在该交互式环境下测试的,至关于get下来数据后将数据封装到了个response对象内。
scrapy shell url地址
view(response);response.text;response.body; 六、fetch #独立于程单纯地爬取一个页面,能够拿到请求头
scrapy fetch url地址
scrapy fetch --header url地址 七、 view #下载完毕后直接弹出浏览器,以此能够分辨出哪些数据是ajax请求
scrapy view rul路径 #若是页面显示内容不全,不全的内容则是ajax请求实现的,以此快速定位问题 八、version #
scrapy version 查看scrapy的版本
scrapy version -v 查看scrapy所依赖的库版本
Project-only commands:局部命令,必须在项目目录下才能执行 一、crawl #运行爬虫,必须建立项目程序才行,确保配置文件settings中ROBOTSTXT_OBEY = False,机器人策略,关闭该策略后就不会受机器人策略的影响
scrapy crawl 爬虫项目文件名 #和以前的runspider方法相比该方法必须在项目目录下运行且受机器人策略的影响
scrapy crawl 爬虫项目文件名 --nolog #运行爬虫项目不打印日志
scrapy crawl 爬虫项目文件名 -a 参数名=参数值 #给爬虫项目传参,可是项目内部必须从新__int__方法来接受外部参数
scrapy crawl 爬虫项目文件名 -a 参数名=参数值 --nolog #运行爬虫项目不打印日志而且传参数给爬虫项目 二、check #检测项目(全部的爬虫程序)中有无语法错误
scrapy check 三、list #列出项目中所包含的爬虫名
scrapy list 四、edit #编辑器,通常不用 五、 parse # #以此能够验证咱们的回调函数是否正确,回调函数通常写在爬虫程序文件下
scrapy parse url地址 --callback 回调函数 六、bench #压力测试
scrapy bench #3 官网连接 https://docs.scrapy.org/en/latest/topics/commands.html
总结:在命令行的命令或者是参数都是不用加引号的,
爬虫项目的settings配置文件添加配置时都变量名必需要大写,不然不识别
project_name/
scrapy.cfg
project_name/
__init__.py items.py pipelines.py settings.py spiders/ __init__.py 爬虫1.py 爬虫2.py 爬虫3.py
文件说明:
注意:通常建立爬虫文件时,以网站域名命名
import scrapy class XiaoHuarSpider(scrapy.spiders.Spider): name = "xiaohuar" # 爬虫名称 ***** allowed_domains = ["xiaohuar.com"] # 容许爬取的域名 start_urls = [ "http://www.xiaohuar.com/hua/", # 其实URL地址,该url地址是程序默认建立的,若是须要爬取该地址外的其余地址数据就须要本身处理请求参数,从新请求方法 ] def parse(self, response): # 访问起始URL并获取结果后的回调函数
import sys,os sys.stdout=io.TextIOWrapper(sys.stdout.buffer,encoding='gb18030')
#在项目目录下新建:entrypoint.py from scrapy.cmdline import execute execute(['scrapy', 'crawl', 'xiaohua'])
强调:配置文件的选项必须是大写,如X='1'
# -*- coding: utf-8 -*- import scrapy from scrapy.linkextractors import LinkExtractor from scrapy.spiders import CrawlSpider, Rule class BaiduSpider(CrawlSpider): name = 'xiaohua' allowed_domains = ['www.xiaohuar.com'] start_urls = ['http://www.xiaohuar.com/v/'] # download_delay = 1 rules = ( Rule(LinkExtractor(allow=r'p\-\d\-\d+\.html$'), callback='parse_item',follow=True,), ) def parse_item(self, response): if url: print('======下载视频==============================', url) yield scrapy.Request(url,callback=self.save) def save(self,response): print('======保存视频==============================',response.url,len(response.body)) import time import hashlib m=hashlib.md5() m.update(str(time.time()).encode('utf-8')) m.update(response.url.encode('utf-8')) filename=r'E:\\mv\\%s.mp4' %m.hexdigest() with open(filename,'wb') as f: f.write(response.body)
https://docs.scrapy.org/en/latest/topics/spiders.html
response.selector.css()
response.selector.xpath()
可简写为
response.css()
response.xpath()
一、查找标签
response.css('div a ')#经过标签名查找标签的内容 response.xpath('//body/a') #开头的//表明从整篇文档中寻找,body以后的/表明body的儿子 response.xpath('//body//a') #开头的//表明从整篇文档中寻找,body以后的//表明body的子子孙孙
总结://与/的区别:儿子和后代的区别,可是获得的都是一个列表
二、查找标签下的内容(text方法)
response.css('div a::text')#先定位标签而后经过::的方式查找标签的内容
response.xpath('//body//a/text()') 三、查找标签下的内容
extract与extract_first:从selector对象中解出内容 response.xpath('//div/a/text()').extract() #获得的是个解析后的内容,是个列表形式 response.xpath('//div/a/text()').extract_first()#获得的是个解析后的内容,是个字符串形式
四、查找标签下的属性: response.xpath('//div/a/@href').extract_first() #获得的是标签的href属性,能够跟标签的任意属性xpath的属性加前缀@ response.css('div a::attr(href)').extract_first() 5、嵌套查找加混合查找 response.xpath('//div').css('a').xpath('@href').extract_first() 6、设置查找默认值 response.xpath('//div[@id="xxx"]').extract_first(default="not found")#为了防止查找不到匹配的标签而设置默认值 七、按照标签属性查找 response.xpath('//div[@id="images"]/a[@href="image3.html"]/text()').extract() #若是按照属性查找标签就必须加上中括号,再写匹配规则 response.css('#images a[@href="image3.html"]/text()').extract() 八、按照标签属性模糊查找 response.xpath('//a[contains(@href,"image")]/@href').extract()#若是按照标签属性模糊查找就必须加上contains()方法,而后再在里面写匹配规则,匹配规则用逗号隔开 response.css('a[href*="image"]::attr(href)').extract() response.xpath('//a[contains(@href,"image")]/img/@src').extract() response.css('a[href*="imag"] img::attr(src)').extract() response.xpath('//*[@href="image1.html"]') response.css('*[href="image1.html"]') 9、正则表达式查找 response.xpath('//a/text()').re(r'Name: (.*)') response.xpath('//a/text()').re_first(r'Name: (.*)') 十、xpath相对路径 >>> res=response.xpath('//a[contains(@href,"3")]')[0] >>> res.xpath('img') [<Selector xpath='img' data='<img src="image3_thumb.jpg">'>] >>> res.xpath('./img') [<Selector xpath='./img' data='<img src="image3_thumb.jpg">'>] >>> res.xpath('.//img') [<Selector xpath='.//img' data='<img src="image3_thumb.jpg">'>] >>> res.xpath('//img') #这就是从头开始扫描 十一、、带变量的xpath response.xpath('//div[@id=$xxx]/a/text()',xxx='images').extract_first()#带变量查找 response.xpath('//div[count(a)=$yyy]/@id',yyy=5).extract_first() #求有5个a标签的div的id