1、什么是爬虫
1.1 爬虫(Spider)的概念
爬虫用于爬取数据, 又称之为数据采集程序。
爬取的数据来源于网络,网络中的数据可以是由Web服务器(Nginx/Apache)、数据库服务器(MySQL、Redis)、索引库(ElastichSearch)、大数据(Hbase/Hive)、视频/图片库(FTP)、云存储等(OSS)提供的。
爬取的数据是公开的、非盈利的。
1.2 Python爬虫
2、爬虫与Web后端服务之间的关系
爬虫使用网络请求库,相当于客户端请求, Web后端服务根据请求响应数据。
爬虫即:
爬虫程序在发起请求前,需要伪造浏览器(UA伪装):
然后再向服务器发起请求, 响应200的成功率高很多。
3、Python爬虫技术的相关库
网络请求:
- urllib: 内置
- requests / urllib3 :第三方
- tornado client: 实现异步请求
- selenium(UI自动测试)/Splash(基于WebKit内核):动态js渲染
- appium(手机App 的爬虫或UI测试)
数据解析:
- re正则
- xpath
- bs4
- json:RESTful接口数据
数据存储:
- pymysql
- mongodb
- elasticsearch: ES搜索引擎 (Javascript:ECMAscript(ES脚本) + BOM + DOM)
多任务库:
- 多线程 (threading)、线程队列 queue
- 协程(asynio、 gevent/eventlet)
爬虫框架
- scrapy
- scrapy-redis 分布式(多机爬虫)
4、常见反爬虫的策略
- UA(User-Agent)策略
- 登录限制(cookie/Token)策略
- 请求频次(IP代理)策略
- 验证码(图片-云打码,文字或物件图片点选、滑块)策略
- 动态js(Selenium/Splash/api接口)策略
2.1、urllib库
2.1.1 urllib.request 模块
urlopen(url | request: Request, data=None) data是bytes类型
- urlopen(url, data=None)可以直接发起url的请求, 如果data不为空时,则默认是POST请求,反之为GET请求。
- urlopen()返回是response响应对象
urlretrieve(url, filename) 下载url的资源到指定的文件
build_opener(*handlder) 构造浏览器对象
- opener.open(url|request, data=None) 发起请求
Request 构造请求的类
-
可以使用这个类来定制一个请求对象,来模拟浏览器登录
-
Request 构造请求类:
Request(url, data=None,headers=None,method=None)
HTTPHandler HTTP协议请求处理器
ProxyHandler(proxies={‘http’: ‘http://proxy_ip:port’}) 代理处理
HTTPcookieProcessor(cookieJar())
- http.cookiejar.cookieJar 类
2.1.2 urllib.parse
url 解析
-
quote() 仅对中文字符串进行url编码(只针对一个汉字进行编码);
-
urlencode(query: dict) 将参数的字典中所有的values转成url编码,结果是key=value&key=value形式,即以 作为url编码类型,可以针对多个参数进行编码)。
【提示】
- query: dict 参数加冒号,表示参数的数据类型
- json上传数据时,Content-Type要设置为类型
- data 请求头的Content-Type默认类型是:
2.1.3 response
-
response.read()
读取的是二进制数据,需要进行转码
字节–>字符串,解码decode 【response.read().decode()】
字符串–>字节,编码encode
-
response.code/ response.status/response.getcode()
获取响应状态码
-
readline()
读取当前行的数据-文本
-
readlines()
读取所有行数据-文本 (按行读取字节数据,返回list列表[b’’,b’’])
-
geturl()
请求的url
-
headers/getheaders()/info()
获取响应头
2.1.4 解决SSL问题
解决Python低版本对SSL证书的支持
2.2、示例
spider01.py
需求:利用http://hao123.com网页测试相应方法
spider02.py
spider03.py
requests库也是一个网络请求库, 基于urllib和urllib3封装的便捷使用的网络请求库。
使用场景:
3.1 安装环境(库)
3.2 核心的函数
-
requests.request() 所有请求方法的基本方法
以下是request()方法的参数说明
-
method: str 指定请求方法, GET, POST, PUT, DELETe,OPTIONS,HEAD,
-
url: str 请求的资源接口(API),在RESTful规范中即是URI(统一资源标签识符)
-
params: dict , 用于GET请求的查询参数(Query String params);如:/s?wd=python3
-
data: dict , 用于POST/PUT/PATCH 请求的表单参数(Form Data) ;封装到body(请求体)中 请求头的Content-Type默认类型是:。借助urllib.parse.urlencode()方法序列化。
-
json: dict 用于上传json数据的参数, 封装到body(请求体)中,请求头的Content-Type默认设置为,借助json.dumps()将字典序列化,把对象序列化成json字符串。
-
files: dict, 结构 {‘name’: file-like-object | tuple}, 如果是tuple, 则有三种情况:
-
(‘filename’, file-like-object),file-like-object理解为open()方法返回Stream流对象
-
(‘filename’, file-like-object, content_type) ,content_type表示打开文件的
mimetype(image/png、image/gif、image/webp矢量图)
-
(‘filename’, file-like-object, content_type, custom-headers)
指定files用于上传文件, 一般使用post请求,默认请求头的为类型。
-
-
headers/cookies : dict
-
proxies: dict , 设置代理
-
auth: tuple , 用于授权的用户名和口令, 形式(‘username’, ‘pwd’)
-
-
requests.get() 发起GET请求, 查询数据
可用参数:
- url
- params 请求路径里带有参数时使用
- json
- headers/cookies/auth
-
requests.post() 发起POST请求, 上传/添加数据
可用参数:
- url
- data/files
- json
- headers/cookies/auth
-
requests.put() 发起PUT请求, 修改或更新数据
-
requests.patch() HTTP幂等性的问题,可能会出现重复处理, 不建议使用。用于更新数据
-
requests.delete() 发起DELETE请求,删除数据
3.3 requests.Response
以上的请求方法返回的对象类型是Response, 对象常用的属性如下:
-
status_code 响应状态码
-
url 请求的url
-
headers : dict 响应的头, 相对于urllib的响应对象的getheaders(),但不包含cookie。
-
cookies: 可迭代的对象,元素是cookie类对象(name, value, path)
-
text : 响应的文本信息
-
content: 响应的字节数据
-
encoding: 响应数据的编码字符集, 如utf-8, gbk, gb2312
-
json(): 如果响应数据类型为,则将响应的数据进行反序化成python的list或dict对象。
- 扩展-javascript的序列化和反序列化
-
JSON.stringify(obj) 序列化
-
JSON.parse(text) 反序列化
-
- 扩展-javascript的序列化和反序列化
字符的表示
- 任意一个字符, 除了换行
- 范围内的任意一个字符
- 字母、数字和下划线组成的任意的字符
量词(数量)表示
- 0或多个
- 1或多个
- 0 或 1 个
- n 个
- 至少n个
- n~m个
分组表示
-
普通的分组表示, 多个正则分组时, search().groups() 返回是元组
-
带有名称的分组, 多个正则分组时,search().groupdict()返回是字典, 字典的key即是分组名。
Python中的正则模块
- re.compile() 一次生成正则对象,可以多次匹配查询
- re.match(正则对象, 字符串)
- re.search()
- re.findall()
- re.sub()
- re.split()
4.1 示例
糗事百科糗图爬取:
5.1. 介绍
什么是BeatifulSoup BeautifulSoup,和lxml一样,是一个html的解析器主要功能也是解析和提取数据 官网
优缺点:
5.2. 使用
5.2.1. 数据解析原理
1、标签定位
2、提取标签、标签属性中存储的数据值
环境安装:
导入BeautifulSoup包:
创建对象(对象实例化):
5.2.2. 数据解析的方法和属性
-
soup.tagname 返回的是html中第一次出现的tagname标签
-
soup.find():
-
select:
-
获取标签之间的文本数据:
-
获取标签的属性值
5.2.3 案例
示例:
需求:爬取三国演义小说所有的章节标题和章节内容
后期示例:
xpath属于xml/html解析数据的一种方式, 基于元素(Element)的树形结构(Node > Element)。选择某一元素时,根据元素的路径选择,如 获取标签。
6.1. xpath解析原理:
6.2. 环境安装:
6.3. 实例化一个etree对象:
6.4. xpath(‘xpath表达式’)
-
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Hx41BC9a-1602569751032)(E:07-notespicture04-路径查询.png)]
6.5. 示例1:
需求:爬取58二手房中的房源信息和价格
示例2:
6.6 示例
6.6.1 要求:站长之家照片采集
6.6.2 代码优化
—> 脚本封装为函数并采集到下一页数据
6.6.3 古诗文网站数据采集
【提示】:
1、解析类型数据获取标签举例:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-P9dVyAhw-1602569751036)(E:07-notespicture06-古诗文采集标签举例.png)]
2、古诗文采集解析某一分类数据标签举例:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-VSEskUR9-1602569751039)(E:07-notespicture07-古诗文采集解析某一分类数据标签举例.png)]
6.6.4 协程版古诗文数据采集
7.1 cookie:
在爬虫中使用异步实现高性能的数据爬取操作
1. 进程和线程
-
multiprocessing模块(进程)
- Process 进程类
- Queue 进程间通信的队列
- put(item, timeout)
- item = get(timeout)
进程使用场景:
-
服务程序与客户程序分离,如:mysql服务和mysql客户端、Docker、Redis、ElasticSearch等服务都属于进程使用场景
-
服务框架中使用,如:scrapy、Django、Flask。
-
分离业务中使用,如:进程池的定时任务和计划编排等,Celery框架
-
使用场景图示:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-8uyxkhNQ-1602569751043)(E:07-notespicture08-进程使用场景.png)]
-
threading 模块(线程)
- Thread 线程类
- 线程间通信(访问对象)
- queue.Queue 线程队列
- 回调函数(主线程声明, 子线程调用函数)
2.进程
2.1 进程的生命周期
图示:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-58e83gBO-1602569751045)(E:07-notespicture11-进程的生命周期图示.png)]
2.2 进程间的通信
2.3 爬虫进程设计图示:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-7XzryDDS-1602569751047)(E:07-notespicture09-爬虫进程设计.png)]
2.4 进程队列
2.4.1 说明
使用管道和少量的锁/信号量实现的进程共享的队列 当进程首先将一个项目放到队列中时,启动一个将线程从缓冲区转移到管道中的Feeder线程
2.4.2 Queue对列的方法
2.4.3 晒了吗网站多任务数据爬取
2.5 进程管道 (半/全双工)
管道也叫无名管道,它是 UNIX 系统 IPC(进程间通信 (Inter-Process Communication) 的最古老形式
管道用来连接不同进程之间的数据流
2.5.1.1 半双工
2.5.1.1 全双工
3. 线程
3.1 线程的概念
3.2 线程与进程的关系
一个程序启动起来以后,至少有一个进程,这个进程至少有一个线程
3.2.1 功能
- 进程,能够完成多任务,比如 在一台电脑上能够同时运行多个QQ。
- 线程,能够完成多任务,比如 一个QQ中的多个聊天窗口。
3.2.2 定义的不同
- 进程是系统进行资源分配和调度的一个独立单位.
- 线程是进程的一个实体,是CPU调度和分派的基本单位,它是比进程更小的能独立运行的基本单位.线程自己基本上不拥有系统资源,只拥有一点在运行中必不可少的资源(如程序计数器,一组寄存器和栈),但是它可与同属一个进程的其他的线程共享进程所拥有的全部资源。
3.2.3 区别
-
一个程序至少有一个进程,一个进程至少有一个线程.
-
线程的划分尺度小于进程(资源比进程少),使得多线程程序的并发性高。
-
进程在执行过程中拥有独立的内存单元,而多个线程共享内存,从而极大地提高了程序的运行效率
-
线程不能够独立执行,必须依存在进程中
-
可以将进程理解为工厂中的一条流水线,而其中的线程就是这个流水线上的工人
优缺点
线程和进程在使用上各有优缺点:线程执行开销小,但不利于资源的管理和保护;而进程正相反。
例:
开4个进程 —> 一般有几个CPU就开几个进程(4核双线程就可以开8个进程),可以实现并行
开400个线程 —> 实现并发,一个CPU不断切换执行任务
3.3. 同步与异步
同步:即是指一个进程在执行某个请求的时候,若该请求需要一段时间才能返回信息,那么这个进程将会一直等待下去,直到收到返回信息才继续执行下去。
异步:与同步相反,即进程不需要一直等下去,而是继续执行下面的操作,不管其他进程的状态。 当有消息返回时系统会通知进行处理,这样可以提高执行的效率。
3.4. 串行与并发
-
CPU地位:
无论是串联、并行或并发,在用户看来都是同时运行的,不管是进程还是线程,都只是一个任务而已, 真正干活的是CPU,CPU来做这些任务,而一个cpu(单核)同一时刻只能执行一个任务
-
串行:
在执行多个任务时,一个任务接着一个任务执行,前一任务完成后,才能执行下一个任务。
-
并行:
多个任务同时运行,只有具备多个cpu才能实现并行,含有几个cpu,也就意味着在同一时刻可以执行几个任务
-
并发:
是伪并行,即看起来是同时运行的,实际上是单个CPU在多个程序之间来回的切换
3.5. 线程案例
3.5.1. 安全锁
3.5.2. 线程本地变量
理解:
ThreadLocal 变量,它本身是一个全局变量,但是每个线程却可以利用它来保存属于自己的私有数据,这些私有数据对其他线程也是不可见的
3.5.3. 线程条件变量
条件变量(Condition)
作用:
原理:
- 用法:
- 两个动作:
- 与互斥锁结合使用:
- 常用函数:
示例:
4. 协程
协程是线程的替代品, 区别在于线程由CPU调度, 协程由用户(程序)自己的调度的。
协程需要事件监听模型(事件循环器),它采用IO多路复用原理,在多个协程之间进行调度
4.1 协程的定义原理
4.2 协程的事件模型
协程的事件模型(IO异步模型):
4.3. 协程的三种方式
- 基于生成器 generator (过渡)
- yield
- send()
- Python3 之后引入了 asyncio模块
- @asyncio.coroutine 协程装饰器, 可以在函数上使用此装饰器,使得函数变成协程对象
- 在协程函数中,可以使用yield from 阻塞当前的协程,将执行的权限移交给 yield from 之后的协程对象。
- asyncio.get_event_loop() 获取事件循环模型对象, 等待所有的协程对象完成之后结束。
- Python3.5之后,引入两个关键字
- async 替代 @asyncio.coroutine
- await 替代 yield from
协程对象的运行方式:
4.3.1. 基于生成器
4.3.2. 引入asyncio模块
4.3.3. async和await
Selenium是驱动浏览器(chrome, firefox, IE)进行浏览器相关操作(打开url, 点击网页中按钮功连接、输入文本)
10.1.什么是selenium模块
-
基于浏览器自动化的一个模块。
-
支持通过各种driver(FirfoxDriver,IternetExplorerDriver,OperaDriver,ChromeDriver)驱动真实浏览器完成测试
selenium也是支持无界面浏览器操作的。比如说HtmlUnit和PhantomJs。
10.2. 为什么使用selenium
-
模拟浏览器功能,自动执行网页中的js代码,实现动态加载
-
页面渲染 在浏览器请求服务器的网页时, 执行页面的js,在js中将数据转成DOM元素(HTML标签)
-
UI自动测试
- 定位输入DOM节点
- 点击某一个DOM节点(Button/a标签)
10.3 使用selenium
安装环境:
下载一个浏览器的驱动程序(谷歌浏览器)
导入模块:
实例化一个浏览器对象
-
编写基于浏览器自动化的操作代码
-
发起请求:get(url)
-
标签定位:find系列的方法
-
标签交互:send_keys(‘xxx’)
-
执行js程序:excute_script(‘jsCode’)
-
前进,后退:back(),forward()
-
关闭浏览器:quit()
-
【总结】元素定位:
示例:
需求:打开淘宝搜索IPhone,再打开百度–>回退–>前进
10.4. selenium处理iframe
示例1:
示例2:
需求:模拟登陆qq空间
10.5. 交互
10.6. 页面异步ajax的解决办法
原因:
由于网页中有ajax的异步执行的js, 导致driver.get()之后查找元素报 NoSuchElementException异常
导包:
解决:
10.7. switch的用法
原因:
解决:
10.8. 获取浏览器的页签
退出:browser.quit()
案例:
登录邮箱(内嵌窗口)
10.9 无头浏览器
10.10 12306模拟登陆
10.10.1. 超级鹰验证码使用
11.1. 介绍
什么是scrapy:
Scrapy是一个为了爬取网站数据,提取结构性数据而编写的应用框架。 可以应用在包括数据挖掘,信息处理或存储历史数据等一系列的程序中。
官方网站:
11.2. scrapy框架的基本使用
-
创建一个工程:
-
cd xxxPro
在spiders子目录中创建一个爬虫文件
-
执行工程:
11.3. 框架组成
11.3.1. 五个核心
-
engine 引擎, 协调其它四个组件之间的联系,即与其它四个组件进行通信,也是scrapy框架的核心。自动运行,无需关注,会自动组织所有的请求对象,分发给下载器
-
spider 爬虫类, 爬虫程序的编写代码所在, 也是发起请求的开始的位置。spider发起的请求,经过engine转入到scheduler中。
请求成功之后的数据解析
-
scheduler 调度器, 调度所有的请求(优先级高,则会先执行)。当执行某一个请求时,由engine转入到downloader中。
-
donwloader 下载器, 实现请求任务的执行,从网络上请求数据,将请求到的数据封装成响应对象,并将响应的对象返回给engine。engine将数据响应的数据对象(以回调接口方式)回传给它的爬虫类对象进行解析。
-
itempipeline 数据管道, 当spider解析完成后,将数据经engine转入到此(数据管道)。再根据数据类型,进行数据处理(图片、文本)
scrapy框架逻辑图:
流程:
11.3.3. scrapy使用
- 创建项目命令
- scrapy startproject 项目名称
- 创建爬虫命令
- scrapy genspider 爬虫名 域名
- 启动爬虫命令
- scrapy crawl 爬虫名
- 调试爬虫命令
- scrapy shell url
- scrapy shell
- fetch(url)
目录结构:
11.3.3. 爬虫文件
解析函数:
-
parse_detail(self, response: Response)
-
解析数据的回调函数,response保存了下载的数据,可以在此函数内对其进行解析,通常使用xpath,parse()函数,如果有返回值,必须返回可迭代的对象
-
Response的类方法:
-
Request类
scrapy.http.Request
请求对象的属性:
-
11.3.4. 示例:
11.3.5. scrapy shell
终端调试工具:
11.4. scrapy 持久化存储
11.4.1 基于终端命令存储
11.4.2. 基于管道持久化存储
11.4.3. 示例:
spider文件—> qiubai.py
items.py 文件 —>在item类中定义相关的属性
pipeline.py文件
settings.py文件中开启管道
【扩展】:
11.4.4. 全站数据爬取
示例:spider.py文件
11.5. 请求传参
示例:boos.py文件
11.4. 图片数据 Imagepipeline
示例:
需求:爬取站长素材中的高清图片
1、爬虫脚本(解析数据)img.py
2、items.py 文件 —>在item类中定义相关的属性
3、在管道文件中自定制一个基于ImagesPipeLine的一个管道类
pipeline.py文件
4、在配置文件中:
settings.py文件
11.5. 中间件
11.5.1. 拦截请求:
middlewares.py
11.5.2. 拦截响应 :
需求:爬取网易新闻数据
wangyi.py文件
middleware.py文件
items.py文件
settings.py文件
11.5.3. 爬虫中间件
SpiderMiddleware
11.5.4. 下载中间件
11.6. 总结核心模块和类
crawlspider
CrawlSpider是一个类,它的父类就是scrapy.Spider,所以CrawlSpider不仅有Spider的功能,还有自己独有的功能
CrawlSpider可以定义规则,再解析html内容的时候,可以根据链接规则提取出指定的链接,然后再向这些链接发送请求,所以,如果有需要跟进链接的需求,就可以使用CrawlSpider来实现
12.1. 流程
#需求:爬取sun网站中的编号,新闻标题,新闻内容,标号
sun.py文件
items.py
pipeline.py
settings.py
示例:
day10 —> dm530项目
存储MondoDB
—>NoSQL仓库.xmind
movie.py
pipelines.py