目录
5. requests模块高级
6. 高性能异步爬虫
7. selenium模块
8. scrapy框架
9. 增量式爬虫
本文代码在https://github.com/2765776613/Spider
5. requests模块高级
- 模拟登录:
- 爬取基于某些用户的用户信息
- 需求:对人人网进行模拟登录
- 点击登录按钮之后会发起一个post请求
- post请求中会携带登录之前录入的相关的登录信息(用户名,密码,验证码,…)
- 验证码:每次请求都会动态变化
- 需求:爬取当前用户的相关用户信息(个人主页中显示的用户信息)
- 直接使用requests.get(‘http://www.renren.com/973295482/profile’)没有请求到对应页面数据的原因:
- http/https协议特性:无状态
- 发起的第二次基于个人主页页面请求的时候,服务器端并不知道该次请求是基于登录状态下的请求
- **cookie **可以来解决此问题
- cookie用来让服务器端记录客户端的相关状态。
- 手动处理:通过抓包工具获取cookie值,将该值封装到headers中
- 自动处理:
- cookie值的来源是哪里?
- 模拟登陆post请求后,由服务器端创建。
- session会话对象:
- 作用:
- 可以进行请求的发送。
- 如果请求过程中产生了cookie,则该cookie会被自动存储/携带在该session对象中
- 作用:
- 步骤:
- 创建一个session对象:
requests.Session()
- 使用session对象进行模拟登录post请求的发送(cookie就会被存储在session中)
- session对象对个人主页对应的get请求进行发送(携带了cookie)
- 创建一个session对象:
- cookie值的来源是哪里?
- cookie用来让服务器端记录客户端的相关状态。
- 直接使用requests.get(‘http://www.renren.com/973295482/profile’)没有请求到对应页面数据的原因:
- 代理:
- 定义:指的就是代理服务器
- 作用:
- 破解封IP这种反爬机制(突破自身IP访问的限制)
- 隐藏自身真实IP
- 相关网站:
- 快代理
- 西刺代理
- www.goubanjia.com
- 代理ip的类型:
- http:应用到http协议对应的url中
- https:应用到https协议对应的url中
- 代理ip的匿名度:
- 透明:服务器知道该次请求使用了代理,也知道请求对应的真实ip
- 匿名:知道使用了代理,不知道真实ip
- 高匿:不知道使用了代理,也不知道真实ip
6. 高性能异步爬虫
- 目的:在爬虫中使用异步实现高性能的数据爬取操作
- 异步爬虫的方式:
- 多线程(或多进程):【不建议使用】
- 好处:可以为相关阻塞的操作单独开启线程或者进程,阻塞操作就可以异步执行
- 弊端:无法无限制的开启多线程或者多进程
- 线程池(或进程池):【适当使用】
- 好处:我们可以降低系统对进程或者线程创建和销毁的一个频率,从而很好的降低系统的开销
- 弊端:池中线程或进程的数量是有上限的。
- 单线程+异步协程:【推荐】
- 基本概念:
- event_loop:事件循环,相当于一个无限循环,我们可以把一些函数注册到这个事件循环上,当满足某些条件的时候,函数就会被循环执行
- coroutine:协程对象,我们可以将协程对象注册到事件循环中,它会被事件循环调用。我们可以使用async关键字来定义一个方法,这个方法在调用时不会立即被执行,而是返回一个协程对象。
- task:任务,它是对协程对象的进一步封装,包含了任务的各个状态
- future:代表将来执行或还没有执行的任务,实际上和task没有本质区别
- async:定义一个协程
- await:用来挂起阻塞方法的执行
- 基本概念:
- 多线程(或多进程):【不建议使用】
7. selenium模块
- selenium模块和爬虫之间具有怎样的关联?
- 便捷的获取网站中动态加载的数据
- 便捷的实现模拟登录
- 什么是selenium模块?
- 基于浏览器自动化的一个模块。
- selenium使用流程:
- 环境安装:
pip install selenium
- 下载一个浏览器的驱动程序
- 下载路径:
http://chromedriver.storage.googleapis.com/index.html
- 驱动程序和浏览器的映射关系:
https://blog.csdn.net/huilan_same/article/details/51896672
- 下载路径:
- 实例化一个浏览器对象
- 编写基于浏览器自动化的操作代码
- 发起请求:get(url)
- 标签定位:find系列的方法
- 标签交互:send_keys(‘xxx’)
- 执行js程序:excute_script(‘js代码’)
- 后退 前进:back() forward()
- 关闭浏览器:quit()
- 环境安装:
- 难点:
- selenium处理iframe
- 如果定位的标签存在与iframe标签之中,则必须使用
switch_to.frame(id)
来转换标签定位的作用域 - 动作链:
from selenium.webdriver import ActionChains
- 实例化一个动作链对象:
action = ActionChains(driver)
- click_and_hold(div):长按并点击的操作
- move_by_offset(x, y)
- perform():让动作链立即执行
- action.release():释放动作链对象
- 实例化一个动作链对象:
- 如果定位的标签存在与iframe标签之中,则必须使用
- selenium处理iframe
- 案例之12306模拟登录:
- 超级鹰
http://www.chaojiying.com/
- 注册:普通用户
- 登录:普通用户
- 题分充值
- 创建一个软件(id)
- 下载示例代码
- 编码流程:
- 使用selenium打开登录页面
- 需要对当前selenium打开的这张页面进行截图
- 对截取的图片局部区域(验证码图片)进行裁剪
- 好处:可以将验证码图片和模拟登录进行一一对应
- 使用超级鹰识别验证码图片(坐标)
- 超级鹰
8. scrapy框架
-
什么是框架?
- 就是一个集成了很多功能并且具有很强通用性的一个项目模板
-
如何学习框架?
- 专门学习框架封装的各种功能的详细用法
-
什么是scrapy?
- 爬虫中封装好的一个明星框架。功能:高性能的持久化存储,异步的数据下载,高性能的数据解析,分布式…
-
基本使用:
- 创建一个工程:
scrapy startproject xxxxPro
cd xxxxPro
【容易忘记】- 在spiders中创建一个爬虫文件
scrapy genspider spiderName www.xxx.com
- 执行工程:
scrapy crawl spiderName
- 创建一个工程:
-
scrapy数据解析:
div_list = response.xpath('//div[@class="col1 old-style-col1"]/div')
-
scrapy持久化存储:
- 基于终端指令:
- 要求:只可以将parse方法的返回值存储到本地的文本文件中
- 注意:持久化存储对应的文本文件的类型只能为:‘json’, ‘jsonlines’, ‘jl’, ‘csv’, ‘xml’,
‘marshal’, ‘pickle’ - 指令:
scrapy crawl xxx -o filePath
- 好处:简洁高效便捷
- 缺点:局限性比较大(数据只可以存储到指定后缀的文本文件中)
- 基于管道:
- 使用流程:
- 数据解析
- 在item类中定义相关的属性
- 将解析的数据封装存储到item类型的对象中
- 将item类型的对象提交给管道进行持久化存储的操作
yield item
- 在管道类的
process_item
方法中要将接受到的item对象中存储的数据进行持久化存储操作 - 在配置文件中开启管道
- 好处:通用性强
- 使用流程:
- 面试题:将爬取到的数据一份存储到本地一份存储到数据库,如何实现?
- 管道文件中的一个管道类对应的是将数据存储到一种平台中
- 爬虫文件提交的item只会给管道文件中第一个被执行的管道类接收
- process_item中的return item表示将item传递给下一个即将被执行的管道类
- 基于终端指令:
-
基于Spider的全站数据爬取
- 就是将网站中某板块下的全部页码对应的页面数据进行爬取
- 需求:爬取校花网中的照片的名称
- 实现方式:
- 将所有页面的url添加到start_urls列表【不推荐】
- 自行手动进行请求发送 【重要】
yield scrapy.Request(url, callback=self.parse)
: callback专门用于数据解析
-
五大核心组件
- 引擎(scrapy)
- 用来处理整个系统的数据流处理,触发事务(框架核心)
- 调度器(scheduler)
- 用来接收引擎发过来的请求,压入队列中,并在引擎再次请求的时候返回,可以想象成一个URL(抓取网页的网址或者说是调度器)的优先队列,由它来决定下一个要抓取的网址是什么,同时去除重复的网址
- 下载器(downloader)
- 用于下载网页内容,并将网页内容返回给引擎,引擎再返回给爬虫文件(下载器是建议在twisted这个高效的异步模型上的)
- 爬虫(spiders)
- 爬虫是主要干活的,用于从特定的网页中提取自己需要的信息,即所谓的实体(item),用户也可以从中提取出链接,让scrapy继续抓取下一个页面
- 项目管道(pipeline)
- 负责处理爬虫从网页中抽取的实体,主要的功能是持久化实体、验证实体的有效性、清除不需要的信息。当页面被爬虫解析后,将被发送到项目管道,并经过几个特定的次序处理数据
- 引擎(scrapy)
-
请求传参
- 使用场景:如果爬取解析的数据不在同一张页面中。(深度爬取)
- 需求:爬取boss的岗位名称,岗位描述
-
图片数据爬取之ImagesPipeline
- 基于scrapy爬取字符串类型的数据和爬取图片类型的数据区别?
- 字符串:只需要基于xpath进行解析且提交管道进行持久化存储
- 图片:xpath解析出图片src的属性值。单独的对图片地址发起请求获取图片二进制类型的数据
- ImagesPipeline:
- 只需要将img的src属性值进行解析,提交到管道,管道就会对图片的src进行请求发送获取图片的二进制类型的数据,且还会帮我们进行持久化存储
- 需求:爬取站长素材中的高清图片
- 使用流程:
- 数据解析(图片的地址)
- 将存储图片地址的item提交到自定义的管道类中
- 在管道文件中自定义一个基于ImagesPipeLine的一个管道类
- get_media_request
- file_path
- item_completed
- 在配置文件中:
- 指定图片存储的目录:IMAGES_STORE = ‘./imgs’
- 指定开启的管道:自定义的管道类
- 基于scrapy爬取字符串类型的数据和爬取图片类型的数据区别?
-
中间件:
- 下载中间件
- 位置:引擎和下载器之间
- 作用:批量拦截到整个工程中发起的所有请求和响应
- 拦截请求:
- UA伪装:
process_request
- 代理IP:
process_exception
最后一定要写上return request
- UA伪装:
- 拦截响应:
- 篡改响应数据,响应对象
- 需求:爬取网易新闻中的新闻数据 (新闻标题和对应的内容)
- 通过网易新闻的首页解析出五大板块对应的详情页url(没有动态加载)
- 每一个板块对应的新闻标题都是动态加载出来的(动态加载)
- 通过解析出每一条新闻详情页的url获取详情页的页面源码,解析出新闻内容
- 需求:爬取网易新闻中的新闻数据 (新闻标题和对应的内容)
- 篡改响应数据,响应对象
- 爬虫中间件
- 位置:引擎和爬虫之间
- 下载中间件
-
CrawlSpider:类,Spider的一个子类
-
全站数据爬取的方式
- 基于Spider:手动请求
- 基于CrawlSpider
-
CrawlSpider的使用:
- 创建一个工程
- cd xxx
- 创建爬虫文件(CrawlSpider)
scrapy genspider -t crawl xxx www.xxx.com
- 链接提取器:
- 作用:在起始url的页面中,根据指定规则(allow=‘正则’)进行指定链接的提取
- 规则解析器:
- 作用:将链接提取器提取到的链接进行指定规则(callback)的解析操
-
-
分布式爬虫:
-
概念:我们需要搭建一个分布式的集群,让其对一组资源进行分布联合爬取。
-
作用:提升爬取数据的效率
-
如何实现分布式?
-
安装一个scrapy-redis的组件
-
原生的scrapy是不可以实现分布式爬虫的,必须要让scrapy结合着scrapy-redis组件一起实现分布式爬虫
-
为什么原生的scrapy不可以实现分布式?
- 调度器不可以被分布式集群共享
- 管道不可以被分布式集群共享
-
scrapy-redis组件:
- 作用:可以给原生的scrapy框架提供可以被共享的管道和调度器
-
实现流程:
-
创建一个工程
-
创建一个基于CrawlSpider的爬虫文件
-
修改当前的爬虫文件:
- 导包:
from scrapy_redis.spiders import RedisCrawlSpider
- 将start_urls和allowed_domains进行注释
- 添加一个新属性:
redis_key = 'sun'
可以被共享的调度器队列的名称 - 编写数据解析相关的操作
- 将当前爬虫类的父类修改成RedisCrawlSpider
- 导包:
-
修改配置文件settings:
-
指定使用可以被共享的管道:
ITEM_PIPELINES = { 'scrapy_redis.pipelines.RedisPipeline': 400 }
-
指定调度器:
# 增加了一个去重容器类的配置, 作用使用Redis的set集合来存储请求的指纹数据, 从而实现请求去重的持久化 DUPEFILTER_CLASS = "scrapy_redis.dupefilter.RFPDupeFilter" # 使用scrapy-redis组件自己的调度器 SCHEDULER = "scrapy_redis.scheduler.Scheduler" # 配置调度器是否要持久化, 也就是当爬虫结束了, 要不要清空Redis中请求队列和去重指纹的set。如果是True, 就表示要持久化存储, 就不清空数据, 否则清空数据 SCHEDULER_PERSIST = True
-
指定redis服务器:
# REDIS_HOST = 'redis服务的ip地址'(注意不能是本机回环地址,此redis需要共用) REDIS_HOST = '192.168.0.103' REDIS_PORT = 6379
-
-
redis相关配置:
- 配置文件名称:
- linux或者mac下:redis.conf
- windows:redis.windows.conf
- 打开配置文件进行修改:
- 将
bind 127.0.0.1
进行注释 - 关闭保护模式:
protected-mode no
- 将
- 开启redis服务:
redis-server 配置文件
- 启动客户端:
redis-cli
- 配置文件名称:
-
执行工程
- scrapy runspider xxx.py
-
向调度器的队列中放入一个起始url
- 调度器的队列在redis的客户端中
lpush xxx www.xxx.com
xxx表示redis_key(调度器的队列名称)
- 调度器的队列在redis的客户端中
-
爬取到的数据存储在了redis的
proName:items
这个数据结构中
-
-
-
9. 增量式爬虫
- 概念:监测网站数据更新的情况,只会爬取网站最新更新出来的数据。
- 使用步骤:
- 指定一个起始url
- 基于CrawlSpider获取其他页码链接
- 基于Rule将其他页码链接进行请求
- 从每一个页码对应的页面源码中解析出每一个电影详情页的url
- 核心:检测电影详情页的url之前有没有请求过
- 将爬取过的电影详情页的url存储
- 存储到redis的set数据结构中
- 将爬取过的电影详情页的url存储
- 对详情页的url发起请求,然后解析出电影名称和简介
- 进行持久化存储