1. scrapy的概念
Scrapy是一个Python编写的开源网络爬虫框架。它是一个被设计用于爬取网络数据、提取结构性数据的框架。
Scrapy 使用了异步网络框架,可以加快下载速度。
Scrapy文档地址
2. scrapy框架的作用
少量的代码,就能够快速的抓取
3. scrapy的工作流程
3.1 回顾之前的爬虫流程
3.2 上面的流程可以改写为
3.3 scrapy的流程
其流程可以描述如下:
- 若解析出来数据,构造items对象,交由引擎进行数据提取,步骤5
- 若解析出来是新的url,则步骤4
- 图中中文是为了方便理解后加上去的
- 图中绿色线条的表示数据的传递
- 注意图中中间件的位置,决定了其作用
- 注意其中引擎的位置,所有的模块之前相互独立,只和引擎进行交互
3.4 scrapy的三个内置对象
- request请求对象:由url method post_data headers等构成
- response响应对象:由url body status headers等构成
- item数据对象:本质是个字典
3.5 scrapy中每个模块的具体作用
- 爬虫中间件和下载中间件只是运行逻辑的位置不同,作用是重复的:如替换UA等
- scrapy的概念:Scrapy是一个为了爬取网站数据,提取结构性数据而编写的应用框架
- scrapy框架的运行流程以及数据传递过程:
- 若解析出来数据,构造items对象,交由引擎进行数据提取,步骤5
- 若解析出来是新的url,则步骤4
- 爬虫提取数据—>引擎—>管道处理和保存数据
引擎(engine):负责数据和信号在不同模块间的传递
调度器(scheduler):实现一个队列,存放引擎发过来的request请求对象
下载器(downloader):发送引擎发过来的request请求,获取响应,并将响应交给引擎
爬虫(spider):处理引擎发过来的response,提取数据,提取url,并交给引擎
管道(pipeline):处理引擎传递过来的数据,比如存储
下载中间件(downloader middleware):可以自定义的下载扩展,比如设置代理ip
爬虫中间件(spider middleware):可以自定义request请求和进行response过滤,与下载中间件作用重复
1 安装scrapy
命令:
sudo apt-get install scrapy
或者:
pip/pip3 install scrapy
2 scrapy项目开发流程
- 创建项目:
scrapy startproject mySpider - 生成一个爬虫:
scrapy genspider itcast itcast.cn - 提取数据:
根据网站结构在spider中实现数据采集相关内容 - 保存数据:
使用pipeline进行数据后续处理和保存
3. 创建项目
通过命令将scrapy项目的的文件生成出来,后续步骤都是在项目文件中进行相关操作,下面以抓取传智师资库来学习scrapy的入门使用:http://www.itcast.cn/channel/teacher.shtml
创建scrapy项目的命令:
scrapy startproject <项目名字>
示例:
scrapy startproject myspider
4. 创建爬虫
通过命令创建出爬虫文件,爬虫文件为主要的代码作业文件,通常一个网站的爬取动作都会在爬虫文件中进行编写。
命令:
在项目路径下执行:
scrapy genspider <爬虫名字> <允许爬取的域名>
爬虫名字: 作为爬虫运行时的参数
允许爬取的域名: 为对于爬虫设置的爬取范围,设置之后用于过滤要爬取的url,如果爬取的url与允许的域不通则被过滤掉。
示例:
5. 完善爬虫
在上一步生成出来的爬虫文件中编写指定网站的数据采集操作,实现数据提取
1.修改起始url–start_urls
2.检查修改允许的域名–allowed_domains
3.在parse()中实现爬取逻辑
5.1 在/myspider/myspider/spiders/itcast.py中修改内容如下:
补充:
- scrapy.Spider爬虫类中必须有名为parse的解析
- 如果网站结构层次比较复杂,也可以自定义其他解析函数
- 在解析函数中提取的url地址如果要发送请求,则必须属于allowed_domains范围内,但是start_urls中的url地址不受这个限制,在后续的会学习如何在解析函数中构造发送请求
- 启动爬虫的时候注意启动的位置,是在项目路径下启动
- parse()函数中使用yield返回数据,注意:解析函数中的yield能够传递的对象只能是:baseItem, Request, dict, None
5.2 定位元素以及提取数据、属性值的方法
解析并获取scrapy爬虫中的数据: 利用xpath规则字符串进行定位和提取
- response.xpath方法的返回结果是一个类似list的类型,其中包含的是selector对象,操作和列表一样,但是有一些额外的方法
- 额外方法extract():返回一个包含有字符串的列表
- 额外方法extract_first():返回列表中的第一个字符串,列表为空没有返回None
5.3 response响应对象的常用属性
- response.url:当前响应的url地址
- response.request.url:当前响应对应的请求的url地址
- response.headers:响应头
- response.requests.headers:当前响应的请求头
- response.body:响应体,也就是html代码,byte类型
- response.status:响应状态码
6 保存数据
利用管道pipeline来处理(保存)数据
6.1 在pipelines.py文件中定义对数据的操作
- 定义一个管道类
- 重写管道类的process_item方法
- process_item方法处理完item之后必须返回给引擎
6.2 在settings.py配置启用管道
配置项中键为使用的管道类,管道类使用.进行分割,第一个为项目目录,第二个为文件,第三个为定义的管道类。
配置项中值为管道的使用顺序,设置的数值约小越优先执行,该值一般设置为1000以内。如:
启用成功
保存到文件中
itcast.json
7. 运行scrapy
命令:在项目目录下执行scrapy crawl <爬虫名字>
示例:scrapy crawl itcast
命令:关闭日志并在项目目录下执行scrapy crawl <爬虫名字> --nolog
示例:scrapy crawl itcast --nolog
- scrapy的安装:pip install scrapy
- 创建scrapy的项目: scrapy startproject myspider
- 创建scrapy爬虫:在项目目录下执行 scrapy genspider itcast itcast.cn
- 运行scrapy爬虫:在项目目录下执行 scrapy crawl itcast
- 解析并获取scrapy爬虫中的数据:
- response.xpath方法的返回结果是一个类似list的类型,其中包含的是selector对象,操作和列表一样,但是有一些额外的方法
- extract() 返回一个包含有字符串的列表
- extract_first() 返回列表中的第一个字符串,列表为空返回None,不为空返回列表第一个元素
- scrapy管道的基本使用:
- 完善pipelines.py中的process_item函数
- 在settings.py中设置开启pipeline
- response响应对象的常用属性
- response.url:当前响应的url地址
- response.request.url:当前响应对应的请求的url地址
- response.headers:响应头
- response.requests.headers:当前响应的请求头
- response.body:响应体,也就是html代码,byte类型
- response.status:响应状态码
1. 数据建模
通常在做项目的过程中,在items.py中进行数据建模
1.1 为什么建模
- 定义item即提前规划好哪些字段需要抓,防止手误,因为定义好之后,在运行过程中,系统会自动检查
- 配合注释一起可以清晰的知道要抓取哪些字段,没有定义的字段不能抓取,在目标字段少的时候可以使用字典代替
- 使用scrapy的一些特定组件需要Item做支持,如scrapy的ImagesPipeline管道类,百度搜索了解更多
1.2 如何建模
在items.py文件中定义要提取的字段:
1.3 如何使用模板类
模板类定义以后需要在爬虫中导入并且实例化,之后的使用方法和使用字典相同
Myspider/Myspider/spiders/itcast.py:
完整版:
通过item保存的数据无法像dict进行json序列化,会出现以下错误
解决办法:在pipelines.py中将item对象转换为dict(scrapy中可以直接将item对象转换为dict)
注意:
- from myspider.items import MyspiderItem这一行代码中 注意item的正确导入路径,忽略pycharm标记的错误
- python中的导入路径要诀:从哪里开始运行,就从哪里开始导入
tips: 导入类时
1.4 开发流程总结
- 创建项目
scrapy startproject 项目名 - 明确目标
在items.py文件中进行建模 - 创建爬虫
3.1 创建爬虫
scrapy genspider 爬虫名 允许的域
3.2 完成爬虫
修改start_urls
检查修改allowed_domains
编写解析方法 - 保存数据
在pipelines.py文件中定义对数据处理的管道
在settings.py文件中注册启用管道
2. 翻页请求的思路
对于要提取如下图中所有页面上的数据该怎么办?
requests模块是实现翻页请求:
- 找到的URL地址
- 调用requests.get(url)
scrapy实现翻页的思路:
- 找到下一页的url地址
- 构造url地址的请求对象,传递给引擎
3. 构造Request对象,并发送请求
3.1 实现方法
- 确定url地址
- 构造请求,scrapy.Request(url,callback)
- callback:指定解析函数名称,表示该请求返回的响应使用哪一个函数进行解析
- 把请求交给引擎:yield scrapy.Request(url,callback)
3.2 网易招聘爬虫
实现网易招聘的页面翻页请求的招聘信息爬取
地址:https://hr.163.com/position/list.do
- 获取首页的数据
- 寻找下一页的地址,进行翻页,获取数据
实现流程
-
创建项目
scrapy startproject 项目名 -
明确目标
在items.py文件中进行建模 -
创建爬虫
3.1 创建爬虫
scrapy genspider 爬虫名 允许的域3.2 完成爬虫
修改start_urls
检查修改allowed_domains
编写解析方法 -
保存数据
在pipelines.py文件中定义对数据处理的管道在settings.py文件中注册启用管道
-
运行结果
- 可以在settings中设置ROBOTS协议
- 可以在settings中设置User-Agent:
3.3 代码实现
翻页实现–在爬虫文件的parse方法中:
3.4 scrapy.Request的更多参数
参数解释
- 中括号[]里的参数为可选参数
- callback:表示当前的url的响应交给哪个函数去处理,若不设置,默认使用parse()解析
- meta:实现数据在不同的解析函数中传递,meta默认带有部分数据,比如下载延迟,请求深度等,常用于解析分散在不同页面中的数据
- dont_filter:默认为False,会过滤请求的url地址,即请求过的url地址不会继续被请求,对需要重复请求的url地址可以把它设置为Ture,比如贴吧的翻页请求,页面的数据总是在变化;start_urls中的地址会被反复请求,否则程序不会启动
- method:指定POST或GET请求
- headers:接收一个字典,其中不包括cookies
- cookies:接收一个字典,专门放置cookies
- body:接收json字符串,为POST的数据,发送payload_post请求时使用(在下一章节中会介绍post请求)
4. meta参数的使用
meta的作用:meta可以实现数据在不同的解析函数中的传递
在爬虫文件的parse方法中,提取详情页增加之前callback指定的parse_detail函数:
对网易招聘的spider中的parse方法进行修改
对items.py进行修改
run
特别注意
- meta参数是一个字典
- meta字典中有一个固定的键,表示代理ip,关于代理ip的使用将在scrapy的下载中间件的中进行介绍
- 完善并使用Item数据类:
- 在items.py中完善要爬取的字段
- 在爬虫文件中先导入Item
- 实力化Item对象后,像字典一样直接使用
- 构造Request对象,并发送请求:
- 导入scrapy.Request类
- 在解析函数中提取url
- yield scrapy.Request(url, callback=self.parse_detail, meta={})
- 利用meta参数在不同的解析函数中传递数据:
- 通过前一个解析函数 yield scrapy.Request(url, callback=self.xxx, meta={}) 来传递meta
- 在self.xxx函数中 response.meta.get(‘key’, ‘’) 或 response.meta[‘key’] 的方式取出传递的数据
1. 模拟登陆的方法
1.1 requests模块实现模拟登陆
- 直接携带cookies请求页面
- 找url地址,发送post请求存储cookie
1.2 selenium模拟登陆
- 找到对应的input标签,输入文本点击登陆
1.3 scrapy的模拟登陆
- 直接携带cookies
- 找url地址,发送post请求存储cookie
2. scrapy携带cookies直接获取需要登陆后的页面
应用场景
- cookie过期时间很长,常见于一些不规范的网站
- 能在cookie过期之前把所有的数据拿到
- 配合其他程序使用,比如其使用selenium把登陆之后的cookie获取到保存到本地,scrapy发送请求之前先读取本地cookie
2.1 实现:重构scrapy的starte_rquests方法
scrapy中start_url是通过start_requests来进行处理的,其实现代码如下
所以对应的,如果start_url地址中的url是需要登录后才能访问的url地址,则需要重写start_request方法并在其中手动添加上cookie
2.2 携带cookies登陆github
测试账号 noobpythoner zhoudawei123
- scrapy中cookie不能够放在headers中,在构造请求的时候有专门的cookies参数,能够接受字典形式的coookie
- 若
在中设置ROBOTS协议、USER_AGENT
USER_AGENT:
修改如下:
ROBOTS协议:
修改如下:
3. scrapy.Request发送post请求
我们知道可以通过scrapy.Request()指定method、body参数来发送post请求;但是通常使用scrapy.FormRequest()来发送post请求
3.1 发送post请求
注意:scrapy.FormRequest()能够发送表单和ajax请求, 参考阅读
3.1.1 思路分析
-
找到post的url地址:点击登录按钮进行抓包,然后定位url地址为https://github.com/session
点击sign in,勾选preserve log,找到session
-
找到请求体的规律:分析post请求的请求体,其中包含的参数均在前一次的响应中
其中token,timestamp,timestamp_secret,是需要在前一次响应中获取的参数,返回login页面
xpath提取value
- 否登录成功:通过请求个人主页,观察是否包含用户名 若出现如下报错,解决方法:
3.1.2 代码实现如下:
小技巧
在settings.py中通过设置cookieS_DEBUG=True 能够在终端看到cookie的传递传递过程
scrapy list 终端中查看当前项目中爬虫
- start_urls中的url地址是交给start_request处理的,如有必要,可以重写start_request函数
- 直接携带cookie登陆:cookie只能传递给cookies参数接收
- scrapy.Request()发送post请求
1. pipeline中常用的方法:
- process_item(self,item,spider):
- 管道类中必须有的函数
- 实现对item数据的处理
- 必须return item
- open_spider(self, spider): 在爬虫开启的时候仅执行一次
- close_spider(self, spider): 在爬虫关闭的时候仅执行一次
2. 管道文件的修改
在wangyi项目中,新建job2爬虫
查看当前爬虫
修改items.py
job.py
job2.py
多个爬虫存在同一个项目中,会使用同一个管道进行保存,发生文件覆盖
原来 pipelines.py
修改pipelines.py
修改settings.py
此时运行任何一个爬虫,两个管道均会写入内容,若要不同爬虫运行时,分别输入不同管道中,spider参数就可以派上用场了
修改 pipelines.py
此时,运行不同爬虫时候,会存入预定义好的对应的管道中
写入mongoDB数据库方式,修改pipelines.py代码
需要先开启mongodb数据库
并在mongodb数据库中查看
pipelines.py
由于未通过spiders对象进行筛选,因此运行任何一个爬虫都会将数据写入该数据库中
思考:在settings中能够开启多个管道,为什么需要开启多个?
- 不同的pipeline可以处理不同爬虫的数据,通过spider.name属性来区分
- 不同的pipeline能够对一个或多个爬虫进行不同的数据处理的操作,比如一个进行数据清洗,一个进行数据的保存
- 同一个管道类也可以处理不同爬虫的数据,通过spider.name属性来区分
4. pipeline使用注意点
- 使用之前需要在settings中开启
- pipeline在setting中键表示位置(即pipeline在项目中的位置可以自定义),值表示距离引擎的远近,越近数据会越先经过:权重值小的优先执行,该值一般设置为1000以内。
- 有多个pipeline的时候,process_item的方法必须return item,否则后一个pipeline取到的数据为None值
- pipeline中process_item的方法必须有,否则item没有办法接受和处理
- process_item方法接受item和spider,其中spider表示当前传递item过来的spider
- open_spider(spider) :能够在爬虫开启的时候执行一次
- close_spider(spider) :能够在爬虫关闭的时候执行一次
- 上述俩个方法经常用于爬虫和数据库的交互,在爬虫开启的时候建立和数据库的连接,在爬虫关闭的时候断开和数据库的连接
- 管道能够实现数据的清洗和保存,能够定义多个管道实现不同的功能,其中有个三个方法
- process_item(self,item,spider):实现对item数据的处理
- open_spider(self, spider): 在爬虫开启的时候仅执行一次
- close_spider(self, spider): 在爬虫关闭的时候仅执行一次
scrapy 爬取腾讯招聘信息
crawlspider类
CrawlSpider规则提取
1 crawlspider是什么
回顾之前的代码中,我们有很大一部分时间在寻找下一页的url地址或者是内容的url地址上面,这个过程能更简单一些么?
scrawlspider经常用于数据在一个页面上进行采集的情况,若数据在多个页面上采集时,通常使用spider类
思路:
- 从response中提取所有的满足规则的url地址
- 自动的构造自己requests请求,发送给引擎
对应的crawlspider就可以实现上述需求,能够匹配满足条件的url地址,组装成Reuqest对象后自动发送给引擎,同时能够指定callback函数
即:crawlspider爬虫可以按照规则自动获取连接
2 创建crawlspider爬虫并观察爬虫内的默认内容
2.1 创建crawlspider爬虫:
2.2 spider中默认生成的内容如下:
2.3 观察跟普通的scrapy.spider的区别
在crawlspider爬虫中,没有parse函数
重点在rules中:
- rules是一个元组或者是列表,包含的是Rule对象
- Rule表示规则,其中包含linkExtractor,callback和follow等参数
- linkExtractor:连接提取器,可以通过正则或者是xpath来进行url地址的匹配
- callback :表示经过连接提取器提取出来的url地址响应的回调函数,可以没有,没有表示响应不会进行回调函数的处理
- follow:连接提取器提取的url地址对应的响应是否还会继续被rules中的规则进行提取,True表示会,Flase表示不会
3. crawlspider网易招聘爬虫
通过crawlspider爬取网易招聘的详情页的招聘信息
url:https://hr.163.com/position/list.do
- 定义一个规则,来进行列表页翻页,follow需要设置为True
- 定义一个规则,实现从列表页进入详情页,并且指定回调函数
- 在详情页提取数据
注意:连接提取器linkExtractor中的allow对应的正则表达式匹配的是href属性的值
4 crawlspider使用的注意点:
- 除了用命令创建一个crawlspider的模板,页可以手动创建
- crawlspider中不能再有以parse为名的数据提取方法,该方法被crawlspider用来实现基础url提取等功能
- Rule对象中linkExtractor为固定参数,其他callback、follow为可选参数
- 不指定callback且follow为True的情况下,满足rules中规则的url还会被继续提取和请求
- 如果一个被提取的url满足多个Rule,那么会从rules中选择一个满足匹配条件的Rule执行
5 了解crawlspider其他知识点
-
链接提取器linkExtractor的更多常见参数
- allow: 满足括号中的’re’表达式的url会被提取,如果为空,则全部匹配
- deny: 满足括号中的’re’表达式的url不会被提取,优先级高于allow
- allow_domains: 会被提取的链接的domains(url范围),如:
- deny_domains: 不会被提取的链接的domains(url范围)
- restrict_xpaths: 使用xpath规则进行匹配,和allow共同过滤url,即xpath满足的范围内的url地址会被提取,如:
-
Rule常见参数
- linkExtractor: 链接提取器,可以通过正则或者是xpath来进行url地址的匹配
- callback: 表示经过连接提取器提取出来的url地址响应的回调函数,可以没有,没有表示响应不会进行回调函数的处理
- follow: 连接提取器提取的url地址对应的响应是否还会继续被rules中的规则进行提取,默认True表示会,Flase表示不会
- process_links: 当链接提取器linkExtractor获取到链接列表的时候调用该参数指定的方法,这个自定义方法可以用来过滤url,且这个方法执行后才会执行callback指定的方法
总结
- crawlspider的作用:crawlspider可以按照规则自动获取连接
- crawlspider爬虫的创建:scrapy genspider -t crawl tencent hr.tencent.com
- crawlspider中rules的使用:
- rules是一个元组或者是列表,包含的是Rule对象
- Rule表示规则,其中包含linkExtractor,callback和follow等参数
- linkExtractor:连接提取器,可以通过正则或者是xpath来进行url地址的匹配
- callback :表示经过连接提取器提取出来的url地址响应的回调函数,可以没有,没有表示响应不会进行回调函数的处理
- follow:连接提取器提取的url地址对应的响应是否还会继续被rules中的规则进行提取,True表示会,Flase表示不会
- 完成网易招聘爬虫crawlspider版本
1. scrapy中间件的分类和作用
1.1 scrapy中间件的分类
根据scrapy运行流程中所在位置不同分为:
- 下载中间件
- 爬虫中间件
1.2 scrapy中间的作用:预处理request和response对象
- 对header以及cookie进行更换和处理
- 使用代理ip等
- 对请求进行定制化操作,
但在scrapy默认的情况下 两种中间件都在middlewares.py一个文件中
爬虫中间件使用方法和下载中间件相同,且功能重复,通常使用下载中间件
2. 下载中间件的使用方法:
Downloader Middlewares默认的方法:
- 在middleware.py中定义中间件类
- 在中间件类中重写请求或者响应方法
- 当每个request通过下载中间件时,该方法被调用。
- 返回None值:没有return也是返回None,该request对象传递给下载器,或通过引擎传递给其他权重低的process_request方法。(如果所有下载器中间件都返回为None,则请求最终被交给下载器处理)
- 返回Response对象:不再请求,把response返回给引擎(将响应交给spider进行解析)
- 返回Request对象:把request对象通过引擎交给调度器,此时将不通过其他权重低的process_request方法(如果返回为请求,则将请求交给调度器)
process_response(self, request, response, spider):
- 当下载器完成http请求,传递响应给引擎的时候调用
- 返回Resposne:通过引擎交给爬虫处理或交给权重更低的其他下载中间件的process_response方法(将响应交给spider进行解析)
- 返回Request对象:通过引擎交给调取器继续请求,此时将不通过其他权重低的process_request方法(如果返回为请求,则将请求交给调度器)
- 在settings.py中配置开启中间件,权重值越小越优先执行
爬取豆瓣电影top250信息
- 编写item.py
定位xpath
编写spiders/movie.py
修改settings.py
再次运行
获取下一页标签xpath
翻至最后一页检查终止条件
翻页并终止逻辑
完善数据提取部分
为了导入方便,先mark Sources root
手误点到excluded 解决办法
获取详情页面数据
编写管道piplines.py
settings.py开启管道
movi.json
3. 定义实现随机User-Agent的下载中间件
3.1 在settings中添加UA的列表
3.2 在middlewares.py中完善代码
3.3 在settings中设置开启自定义的下载中间件,设置方法同管道
开启并修改中间件
运行爬虫观察现象
4. 代理ip的使用
4.1 思路分析
- 代理添加的位置:request.meta中增加字段
- 获取一个代理ip,赋值给
- 代理池中随机选择代理ip
- 代理ip的webapi发送请求获取一个代理ip
4.2 具体实现
settings.py中
免费代理ip:
收费代理ip:
http基本认证1
http基本认证2
两种同时存在
settings.py中注册
4.3 检测代理ip是否可用
在使用了代理ip的情况下可以在下载中间件的process_response()方法中处理代理ip的使用情况,如果该代理ip不能使用可以替换其他代理ip
在settings.py中开启该中间件
5. 在中间件中使用selenium
以github登陆为例
5.1 完成爬虫代码
5.2 在middlewares.py中使用selenium
配置文件中设置开启该中间件后,运行爬虫可以在日志信息中看到selenium相关内容
5.3 爬取AQI 天气信息历史数据
选择一个城市,观察会发现该页面数据为动态渲染,scrapy直接发送响应获取不到渲染后的数据,因此需要在中间件中使用selenium进行动态渲染后,获取网页源码作为新响应
选择某一个月
- items.py
获取所有城市url
在城市详情页面获取所有日期对应url
或者通过右侧提取
对所要提取的详情页面进行数据提取
- 解析数据
spiders/aqi.py
- 管道 和 中间件
pipelines.py 和 middlewares.py
middleware.py
若出现如下错误:
Selenium打开后数据不加载解决办法
- 运行
中间件的使用:
- 完善中间件代码:
- 当每个request通过下载中间件时,该方法被调用。
- 返回None值:没有return也是返回None,该request对象传递给下载器,或通过引擎传递给其他权重低的process_request方法
- 返回Response对象:不再请求,把response返回给引擎
- 返回Request对象:把request对象通过引擎交给调度器,此时将不通过其他权重低的process_request方法
process_response(self, request, response, spider):
- 当下载器完成http请求,传递响应给引擎的时候调用
- 返回Resposne:通过引擎交给爬虫处理或交给权重更低的其他下载中间件的process_response方法+
- 返回Request对象:通过引擎交给调取器继续请求,此时将不通过其他权重低的process_request方法
-
需要在settings.py中开启中间件
middlewares.py
1. 分布式是什么
简单的说分布式就是不同的节点(服务器,ip不同)共同完成一个任务
特点:
加快运行速度,需要的资源(硬件&网络)依然还是原有的
单个节点的稳定性不影响整个系统的稳定性
2. scrapy_redis的概念
scrapy_redis是scrapy框架的基于redis的分布式组件
3. scrapy_redis的作用
Scrapy_redis在scrapy的基础上实现了更多,更强大的功能,具体体现在:
通过持久化请求队列和请求的指纹集合来实现:
- 断点续爬
- 分布式快速抓取
4. scrapy_redis的工作流程
4.1 回顾scrapy的流程
4.2 scrapy_redis的流程
-
在scrapy_redis中,所有的待抓取的request对象和去重的request对象指纹都存在所有的服务器公用的redis中
-
所有的服务器中的scrapy进程公用同一个redis中的request对象的队列
-
所有的request对象存入redis前,都会通过该redis中的request指纹集合进行判断,之前是否已经存入过
-
在默认情况下所有的数据会保存在redis中
具体流程如下:
scarpy_redis的分布式工作原理
- 在scrapy_redis中,所有的待抓取的对象和去重的指纹都存在公用的redis中
- 所有的服务器公用同一redis中的请求对象的队列
- 所有的request对象存入redis前,都会通过请求对象的指纹进行判断,之前是否已经存入过
1. 下载github的demo代码
-
clone github scrapy-redis源码文件
-
安装scrapy_redis
-
研究项目自带的demo
2. 观察dmoz文件
在domz爬虫文件中,实现方式就是之前的类型的爬虫
但是在settings.py中多了以下内容,这几行表示中重新实现的了去重的类,以及调度器,并且使用管道类
3. 运行dmoz爬虫,观察现象
- 首先我们需要添加redis的地址,程序才能够使用redis
- 我们执行domz的爬虫,会发现redis中多了一下三个键:
- 中止进程后再次运行dmoz爬虫
继续执行程序,会发现程序在前一次的基础之上继续往后执行,所以domz爬虫是一个基于url地址的增量式的爬虫
4. scrapy_redis的原理分析
我们从settings.py中的三个配置来进行分析
分别是:
- RedisPipeline # 管道类
- RFPDupeFilter # 指纹去重类
- Scheduler # 调度器类
- SCHEDULER_PERSIST # 是否持久化请求队列和指纹集合
4.1 Scrapy_redis之RedisPipeline
RedisPipeline中观察process_item,进行数据的保存,存入了redis中
4.2 Scrapy_redis之RFPDupeFilter
RFPDupeFilter 实现了对request对象的加密
4.3 Scrapy_redis之Scheduler
scrapy_redis调度器的实现了决定什么时候把request对象加入带抓取的队列,同时把请求过的request对象过滤掉
filter(function, iterable)
filter(None, iterable) - 过滤非空数据
filter 在python3中返回一个过滤器对象,python2中返回一个列表
4.4 由此可以总结出request对象入队的条件
- request的指纹不在集合中
- request的dont_filter为True,即不过滤
- start_urls中的url地址会入队,因为他们默认是不过滤
4.5 实现单机断点续爬
改写网易招聘爬虫,该爬虫就是一个经典的基于url地址的增量式爬虫
5. 实现分布式爬虫
5.1 分析demo中代码
打开example-project项目中的myspider_redis.py文件
通过观察代码:
- 继承自父类为RedisSpider
- 增加了一个redis_key的键,没有start_urls,因为分布式中,如果每台电脑都请求一次start_url就会重复
- 多了方法,该方法不是必须的,可以手动指定allow_domains
- 启动方法:
- 在每个节点正确的目录下执行,使该节点的scrapy_redis爬虫程序就位
- 在共用的redis中 ,使全部节点真正的开始运行
- settings.py中关键的配置
5.2 动手实现分布式爬虫
京东图书
页面分析
在response的源码分析发现,价格未存在网页中
search后找到mgets接口url
在抓包中查找接口
headers中找到对应url
分析该url,并删除无影响参数,并使用在线工具编解码分析
通过单个id进行查找
价格获取根据data-sku,拼接
编写普通爬虫
1.创建项目
2.确定爬取数据
items.py
- 创建并编写爬虫
图书详情页面
获取评论comment,同价格方法,找到GetCommentsCount 获取评论方法
过滤url 后找到评论所在 scrapy解决重定向问题
book.py
其中,详情页面和评论页面需要selenium渲染;
comment需要对GetCommentsCount页面发送请求,获取comment;
且会遇到 重定向问题;
注意:extract() ->list,extract_first() ->str 类型
middlewares.py
- 保存数据
pipelines.py
- 运行普通scrapy爬虫
修改为分布式爬虫
- 改造爬虫
1. 导入类
2. 继承类
3. 注销start_urls & allowed_domains
4. 设置redis_key,获取start_urls
5. 设置__ init __()获取允许的域
spiders/books.py - 改造配置文件
1. copy配置参数
settings.py
redis中有密码 需要认证 window下使用redis
存入url
- 运行爬虫
-
scrapy_redis的含义和能够实现的功能
- scrapy是框架
- scrapy_redis是scrapy的组件
- scrapy_redis能够实现断点续爬和分布式爬虫
- 使用场景:数据量大、需求时间紧
-
scrapy_redis流程和实现原理
- 在scrapy框架流程的基础上,把存储request对象放到了redis的有序集合中,利用该有序集合实现了请求队列
- 并对request对象生成指纹对象,也存储到同一redis的集合中,利用request指纹避免发送重复的请求
-
request对象进入队列的条件
- request的指纹不在集合中
- request的dont_filter为True,即不过滤
-
request指纹的实现
- 请求方法
- 排序后的请求地址
- 排序并处理过的请求体或空字符串
- 用hashlib.sha1()对以上内容进行加密
-
scarpy_redis实现增量式爬虫、布式爬虫
- 对setting进行如下设置
- DUPEFILTER_CLASS = “scrapy_redis.dupefilter.RFPDupeFilter”
- SCHEDULER = “scrapy_redis.scheduler.Scheduler”
- SCHEDULER_PERSIST = True
- ITEM_PIPELINES = {‘scrapy_redis.pipelines.RedisPipeline’: 400,}
- REDIS_URL = “redis://127.0.0.1:6379” # 请正确配置REDIS_URL
- 爬虫文件中的爬虫类继承RedisSpider类
- 爬虫类中redis_key替代了start_urls
- 启动方式不同
- 通过启动爬虫后,向redis_key放入一个或多个起始url(lpush或rpush都可以),才能够让scrapy_redis爬虫运行
- 除了以上差异点以外,scrapy_redis爬虫和scrapy爬虫的使用方法都是一样的
- 对setting进行如下设置
1. 什么是scrapy_splash?
scrapy_splash是scrapy的一个组件
- scrapy-splash加载js数据是基于Splash来实现的。
- Splash是一个Javascript渲染服务。它是一个实现了HTTP API的轻量级浏览器,Splash是用Python和Lua语言实现的,基于Twisted和QT等模块构建。
- 使用scrapy-splash最终拿到的response相当于是在浏览器全部渲染完成以后的网页源代码。
splash官方文档 https://splash.readthedocs.io/en/stable/
2. scrapy_splash的作用
scrapy-splash能够模拟浏览器加载js,并返回js运行后的数据
3. scrapy_splash的环境安装
3.1 使用splash的docker镜像
splash的dockerfile https://github.com/scrapinghub/splash/blob/master/Dockerfile
观察发现splash依赖环境略微复杂,所以我们可以直接使用splash的docker镜像
如果不使用docker镜像请参考 splash官方文档 安装相应的依赖环境
3.1.1 安装并启动docker服务
linux安装参考 https://blog.csdn.net/sanpic/article/details/81984683
windows splash
如果遇到以下错误下载并安装
next step
docker run -p 8050:8050 scrapinghub/splash
3.1.2 获取splash的镜像
在正确安装docker的基础上pull取splash的镜像
3.1.3 验证是否安装成功
运行splash的docker服务,并通过浏览器访问8050端口验证安装是否成功
-
前台运行
-
后台运行
访问 http://127.0.0.1:8050 看到如下截图内容则表示成功
3.1.4 解决获取镜像超时:修改docker的镜像源
以ubuntu18.04为例
- 创建并编辑docker的配置文件
- 写入国内docker-cn.com的镜像地址配置后保存退出
-
重启电脑或docker服务后重新获取splash镜像
-
这时如果还慢,请使用手机热点
3.1.5 关闭splash服务
需要先关闭容器后,再删除容器
3.2 在python虚拟环境中安装scrapy-splash包
4. 在scrapy中使用splash
以baidu为例
4.1 创建项目创建爬虫
4.2 完善settings.py配置文件
在settings.py文件中添加splash的配置以及修改robots协议
4.3 不使用splash
在spiders/no_splash.py中完善
4.4 使用splash
在spiders/with_splash.py中完善
4.5 分别运行俩个爬虫,并观察现象
4.5.1 分别运行俩个爬虫
4.5.2 观察获取的俩个html文件
不使用splash
使用splash
4.6 结论
- splash类似selenium,能够像浏览器一样访问请求对象中的url地址
- 能够按照该url对应的响应内容依次发送请求
- 并将多次请求对应的多次响应内容进行渲染
- 最终返回渲染后的response响应对象
5. 了解更多
关于splash https://www.cnblogs.com/zhangxinqi/p/9279014.html
关于scrapy_splash(截屏,get_cookies等) https://www.e-learn.cn/content/qita/800748
-
scrapy_splash组件的作用
- splash类似selenium,能够像浏览器一样访问请求对象中的url地址
- 能够按照该url对应的响应内容依次发送请求
- 并将多次请求对应的多次响应内容进行渲染
- 最终返回渲染后的response响应对象
-
scrapy_splash组件的使用
- 需要splash服务作为支撑
- 构造的request对象变为splash.SplashRequest
- 以下载中间件的形式使用
- 需要scrapy_splash特定配置
-
scrapy_splash的特定配置
1. 了解scrapy的日志信息
2. scrapy的常用配置
-
ROBOTSTXT_OBEY 是否遵守robots协议,默认是遵守
- 关于robots协议
- 在百度搜索中,不能搜索到淘宝网中某一个具体的商品的详情页面,这就是robots协议在起作用
- Robots协议:网站通过Robots协议告诉搜索引擎哪些页面可以抓取,哪些页面不能抓取,但它仅仅是互联网中的一般约定
- 例如:淘宝的robots协议
- 关于robots协议
-
USER_AGENT 设置ua
-
DEFAULT_REQUEST_HEADERS 设置默认请求头,这里加入了USER_AGENT将不起作用
-
ITEM_PIPELINES 管道,左位置右权重:权重值越小,越优先执行
-
SPIDER_MIDDLEWARES 爬虫中间件,设置过程和管道相同
-
DOWNLOADER_MIDDLEWARES 下载中间件,设置过程和管道相同
-
cookieS_ENABLED 默认为True表示开启cookie传递功能,即每次请求带上前一次的cookie,做状态保持
-
cookieS_DEBUG 默认为False表示日志中不显示cookie的传递过程
-
LOG_LEVEL 默认为DEBUG,控制日志的等级,无默认设置,需要在settings.py中手动设置(DEBUG,WARINING,INFO,ERROR,CRITICAL,从左至右日志等级逐渐增高,设置WARNING时,WARNING及更高级别日志INFO…CRITICAL将被输出)
- LOG_LEVEL = “WARNING” (一般设置为INFO和WARNING)
-
LOG_FILE 设置log日志文件的保存路径,如果设置该参数,日志信息将写入文件,终端将不再显示,且受到LOG_LEVEL日志等级的限制
- LOG_FILE = “https://blog.csdn.net/sinat_28015305/article/details/test.log”
3. scrapy_redis配置
- DUPEFILTER_CLASS = “scrapy_redis.dupefilter.RFPDupeFilter” # 指纹生成以及去重类
- SCHEDULER = “scrapy_redis.scheduler.Scheduler” # 调度器类
- SCHEDULER_PERSIST = True # 持久化请求队列和指纹集合
- ITEM_PIPELINES = {‘scrapy_redis.pipelines.RedisPipeline’: 400} # 数据存入redis的管道
- redis无密码
REDIS_URL = “redis://host:port” # redis的url - redis 存在密码
REDIS_HOST = redis的url
REDIS_PORT = 6379
REDIS_PARAMS = {
‘password’: ‘123456’,
}
4. scrapy_splash配置
5. scrapy_redis和scrapy_splash配合使用的配置
5.1 原理
- scrapy-redis中配置了”DUPEFILTER_CLASS” : “scrapy_redis.dupefilter.RFPDupeFilter”,与scrapy-splash配置的DUPEFILTER_CLASS = ‘scrapy_splash.SplashAwareDupeFilter’ 相冲突!
- 查看了scrapy_splash.SplashAwareDupeFilter源码后,发现他继承了scrapy.dupefilter.RFPDupeFilter,并重写了request_fingerprint()方法。
- 比较scrapy.dupefilter.RFPDupeFilter和scrapy_redis.dupefilter.RFPDupeFilter中的request_fingerprint()方法后,发现是一样的,因此重写了一个SplashAwareDupeFilter,继承scrapy_redis.dupefilter.RFPDupeFilter,其他代码不变。
5.2 重写dupefilter去重类,并在settings.py中使用
5.2.1 重写去重类
5.2.2 scrapy_redis和scrapy_splash配合使用的配置
- scrapy_redis分布式爬虫在业务逻辑结束后并不能够自动退出
- 重写的dupefilter去重类可以自定义位置,也须在配置文件中写入相应的路径
6. 了解scrapy的其他配置
- CONCURRENT_REQUESTS 设置并发请求的数量,默认是16个
- DOWNLOAD_DELAY 下载延迟,默认无延迟,单位为秒
- 其他设置参考:https://www.jianshu.com/p/df9c0d1e9087
- 了解scrapy的日志信息
- 掌握scrapy的常用配置
- 掌握scrapy_redis配置
- 了解scrapy_splash配置
- 了解scrapy_redis和scrapy_splash配合使用的配置
1. scrapyd的介绍
scrapyd是一个用于部署和运行scrapy爬虫的程序,它允许你通过JSON API来部署爬虫项目和控制爬虫运行,scrapyd是一个守护进程,监听爬虫的运行和请求,然后启动进程来执行它们
所谓json api本质就是post请求的webapi
2. scrapyd的安装
scrapyd服务:
scrapyd客户端:
3. 启动scrapyd服务
-
在scrapy项目路径下 启动scrapyd的命令: 或
-
启动之后就可以打开本地运行的scrapyd,浏览器中访问本地6800端口可以查看scrapyd的监控界面
- 点击job可以查看任务监控界面
4. scrapy项目部署
4.1 配置需要部署的项目
编辑需要部署的项目的scrapy.cfg文件(需要将哪一个爬虫部署到scrapyd中,就配置该项目的该文件)
4.2 部署项目到scrapyd
同样在scrapy项目路径下执行:
部署成功之后就可以看到部署的项目
4.3 管理scrapy项目
- 启动项目:
- 关闭爬虫:
注意;curl是命令行工具,如果没有则需要额外安装
4.4 使用requests模块控制scrapy项目
5. 了解scrapyd的其他webapi
- curl http://localhost:6800/listprojects.json (列出项目)
- curl http://localhost:6800/listspiders.json?project=myspider (列出爬虫)
- curl http://localhost:6800/listjobs.json?project=myspider (列出job)
- curl http://localhost:6800/cancel.json -d project=myspider -d job=tencent (终止爬虫,该功能会有延时或不能终止爬虫的情况,此时可用kill -9杀进程的方式中止)
- scrapyd还有其他webapi,百度搜索了解更多
小结
- 在scrapy项目路径下执行或,启动scrapyd服务;或以后台进程方式启动
- 部署scrapy爬虫项目
- 启动爬虫项目中的一个爬虫
1.Gerapy介绍:
Gerapy 是一款 分布式爬虫管理框架,支持 Python 3,基于 Scrapy、Scrapyd、Scrapyd-Client、Scrapy-Redis、Scrapyd-API、Scrapy-Splash、Jinjia2、Django、Vue.js 开发,Gerapy 可以帮助我们:
- 更方便地控制爬虫运行
- 更直观地查看爬虫状态
- 更实时地查看爬取结果
- 更简单地实现项目部署
- 更统一地实现主机管理
2.Gerapy的安装
1.执行如下命令,等待安装完毕
pip3 install gerapy
2.验证gerapy是否安装成功
在终端中执行 gerapy 会出现如下信息
“”"
Usage:
gerapy init [–folder=]
gerapy migrate
gerapy createsuperuser
gerapy runserver [host:port]
“”"
3.Gerapy配置启动
1.新建一个项目
gerapy init
执行完该命令之后会在当前目录下生成一个gerapy文件夹,进入该文件夹,会找到一个名为projects的文件夹
2.对数据库进行初始化(在gerapy目录中操作),执行如下命令
gerapy migrate
对数据库初始化之后会生成一个SQLite数据库,数据库保存主机配置信息和部署版本等
3.启动 gerapy服务
gerapy runserver
此时启动gerapy服务的这台机器的8000端口上开启了Gerapy服务,在浏览器中输入http://localhost:8000就能进入Gerapy管理界面,在管理界面就可以进行主机管理和界面管理
4.通过Gerapy配置管理scrapy项目
-
配置主机
1.添加scrapyd主机
需要添加 IP、端口,以及名称,点击创建即可完成添加,点击返回即可看到当前添加的 Scrapyd 服务列表,创建成功后,我们可以在列表中查看已经添加的服务
2.执行爬虫,就点击调度.然后运行. (前提是: 我们配置的scrapyd中,已经发布了爬虫.)
-
配置Projects
1.我们可以将scarpy项目直接放到 /gerapy/projects下.
2.可以在gerapy后台看到有个项目
3.点击部署点击部署按钮进行打包和部署,在右下角我们可以输入打包时的描述信息,类似于 Git 的 commit 信息,然后点击打包按钮,即可发现 Gerapy 会提示打包成功,同时在左侧显示打包的结果和打包名称。
4.选择一个站点,点击右侧部署,将该项目部署到该站点上
5.成功部署之后会显示描述和部署时间
6.来到clients界面,找到部署该项目的节点,点击调度
7.在该节点中的项目列表中找到项目,点击右侧run运行项目
补充:
我们仅仅使用scrapyd是可以调用scrapy进行爬虫. 只是需要使用命令行开启爬虫
curl http://127.0.0.1:6800/schedule.json -d project=工程名 -d spider=爬虫名
使用Greapy就是为了将使用命令行开启爬虫变成 “小手一点”. 我们在gerapy中配置了scrapyd后,不需要使用命令行,可以通过图形化界面直接开启爬虫.
小结
- 了解 什么是Gerapy
- 掌握 Gerapy的安装
- 掌握 Gerapy配置启动
- 掌握 通过Gerapy配置管理scrapy项目
2.1 环境安装
以win10为例
2.1.1 安装node.js
- 点击进入 https://nodejs.org/zh-cn/
- 点击下载安装包
- 双击安装包,然后同样一路狂点下一步
- 安装完成后在cmd终端中输入 ,显示版本号则表示安装成功
2.1.2 安装java JDK
- 点击进入官网下载页面 https://www.oracle.com/technetwork/java/javase/downloads/jdk8-downloads-2133151.html
- 注意下载位置,点击同意协议,下载相应的版本
- 双击安装包,然后同样一路狂点下一步
!!!注意安装位置,默认是C:Program FilesJava,尽量不要修改。
-
添加环境变量
-
CLASSPATH
注意上边最开始有个点
-
JAVA_HOME
-
Path
在cmd终端中输入java和javac不报异常,说明安装成功
-
2.1.3 安装android SDK
- 进入网站 https://www.androiddevtools.cn/
地址2 - 依次点击AndroidSDK工具>>SDK Tools>>会跳转到以下界面,Windows建议选择.exe后缀
- 下载后安装
注意此处,点击第一项,为所有用户安装
如果不小心关闭了,或者没有自动打开上边的界面,点击安装目录下的SDK Mansger.exe文件,同样可以打开,已经自动打开的忽略此步。
下载完成后,你的sdk文件夹下,应该是这样的
-
安装环境变量
-
ANDROID_HOME
-
Path
-
2.1.4 安装Appium
- 需要科学上网 http://appium.io/(chrome)
- 点击下载并安装
2.1.5 安装夜神模拟器
- 下载并安装夜神模拟器 https://www.yeshen.com/
- 首先,下载完成后不要忙着打开夜神模拟器,先确保你的电脑Hyper-V是关闭的,否则启动模拟器时部分电脑会蓝屏重启。
- 把安卓sdk中的adb.exe复制两份,其中一个改名为nox_adb.exe后,放到夜神模拟器安装目录的bin目录下覆盖原文件
2.2 联调测试环境
2.2.1 开启并设置夜神安卓模拟器
2.2.2 adb命令建立连接
-
在夜神模拟器安装路径下的bin目录下执行cmd进入终端
-
输入 后,出现提示
-
再输入 后,出现提示
-
最后再次输入后,出现提示
2.2.3 开启Appium并配置运行
-
获取app包名和进程名
-
打开夜神模拟器中的浏览器
-
在adb连接正确的情况下,在夜神模拟器安装目录的bin目录下的cmd中输入
-
进入adb shell后输入
-
就是app包名
-
就是进程名
-
- 启动Appium,点击start server
- 点击放大镜进入并输入测试配置
-
配置参数的来源
-
platformName 系统名
-
platformVersion 系统版本
-
deviceName 手机型号
-
appPackage app的包名
-
appActivity app的进程名
-
- 关闭夜神模拟器中的浏览器,点击右下角的start session查看运行结果
2.2.4 干的漂亮!环境搭建成功
以控制抖音app滑动并获取抖音短视频发布者昵称和点赞数等信息为例
2.1 安装appium-python-client模块并启动已安装好的环境
2.1.1 安装appium-python-client模块
在window的虚拟环境下执行
2.1.2 启动夜神模拟器,进入夜神模拟器所在的安装路径的bin目录下,进入cmd终端,使用adb命令建立adb server和模拟器的连接
2.1.3 启动appium-desktop,点击start server启动appium服务
2.1.4 利用上一小节所学习的内容获取Desired Capabilities参数
- 获取模拟设备的型号
- 打开设置——关于平板电脑
- 查看型号,获取模拟设备的型号
- 获取app包名称 以及 app进程名
- 打开模拟器中的抖音短视频app
- 在adb连接正确的情况下,在夜神模拟器安装目录的bin目录下的cmd中输入
- 进入adb shell后输入
- ``com.ss.android.ugc.aweme`就是app包名
- 就是进程名 注意前边有个点.
2.2 初始化以及获取移动设备分辨率
完成代码如下,并运行代码查看效果:如果模拟器中抖音app被启动,并打印出模拟设备的分辨率则成功
-
移动设备分辨率
-
driver.get_window_size()[‘width’]
-
driver.get_window_size()[‘height’]
-
2.3 定位元素以及提取文本的方法
2.3.1 点击appium desktop右上角的放大镜图标
如图填写配置,并点击start session
2.3.2 定位界面的使用方法如下图所示
2.3.3 点击短视频的作者名字,查看并获取该元素的id
2.3.4 在python使用代码通过元素id获取该元素的文本内容
实例化appium driver对象后添加如下代码,运行并查看效果
-
定位元素及获取其文本内容的方法
- driver.find_element_by_id(元素的id).text
- driver.find_element_by_xpath(定位元素的xpath规则).text
2.4 控制抖音app滑动
2.4.1 appium滑动的函数
从(start_x, start_y)滑动到(end_x, end_y)
- driver.swipe(start_x, start_y, end_x, end_y)
2.4.2 控制抖音app滑动的代码实现
2.5 整理并完成自动滑动的代码
至此,可以参考爬虫5.0课程项目库,使用fiddler等抓包工具,利用appium+mitmproxy+wget等python模块自动获取抖音视频文件
2.6 关于模拟式移动端爬虫的参考阅读
-
https://zhuanlan.zhihu.com/appium
-
https://github.com/butomo1989/docker-android
-
https://blog.csdn.net/weixin_42620645/article/details/83828863
-
https://blog.csdn.net/weixin_39211232/article/details/83410130#Android_16
- 以上就是本篇文章【爬虫(三)-笔记】的全部内容了,欢迎阅览 ! 文章地址:http://syank.xrbh.cn/quote/2793.html 行业 资讯 企业新闻 行情 企业黄页 同类资讯 网站地图 返回首页 迅博思语资讯移动站 http://kaire.xrbh.cn/ , 查看更多