目录
- HTML相关技术
- HTTP协议
- 宽度与深度抓取的比较
- 不重复抓取策略及BloomFilter
- 网站结构分析
- 网页内容解析
- 动态网页的解析
- 网站登录
- 多线程与多进程
- 分布式
- 应对网站的反爬技术
1.HTML相关技术
- HTML:超文本标记语言,浏览器根据HTML语言规范来解析网页内容
- tag:
<a><tr><p>
a用于标记外链,tr、p用来对内容进行定位抽取 - id、class也可以用于定位元素
- DOM树是将网页的内容表示成类似树的形式,方便网页数据的分析和提取
- Javascript 运行在前端的编程语言,典型应用为动态网页数据、内容的加载和呈现,在网络请求时常用的技术是AJAX,专门用来异步请求数据
2.HTTP协议
2.1 TCP/IP & OSI
首先复习一下常见的TCP/IP的四层协议和OSI的七层协议,如下图所示
- 物理层:电器连接
- 数据链路层:交换机,STP,帧中继
- 网络层:路由器,IP协议
- 传输层:TCP,UDP协议
- 会话层:建立通信连接,网络拨号
- 表示层:每次连接只处理一个请求
- 应用层:HTTP、FTP
- 无连接:每次连接只处理一个请求
- 无状态:每次连接、传输都是独立的
2.2 HTTP HEADER
下图是REQUEST的一个HEADER示例
由于HTTP是一个请求-响应模式的典型范例,是有keep-alive功能使客户端到服务器端的链接持续有效,当出现对服务器的后继请求是,keep-alive功能避免了建立或者重新建立链接。
2.3HTTP响应状态码
- 2XX:成功
- 3XX:跳转
- 300: 存在多个可用的资源
- 301:重定向
- 302:重定向
- 304:请求的资源未更新,丢弃
- 4XX:客户端错误
- 400:客户端请求有语法错误,不能被服务器所理解
解决方法:检查请求的参数或者路径是否正确 - 401:请求未经授权,这个状态码必须和www-Authenticate报头域一起使用
解决方法:尝试重新登录 - 403:服务器决绝服务
解决方法:(1)如果是需要登录的网站,尝试重新登录(2)可能是网站的反爬政策导致IP被封,通过暂停爬取,增加爬虫等待时间,更改网络IP - 404:请求资源不存在
解决方法:直接丢弃该URL
- 400:客户端请求有语法错误,不能被服务器所理解
- 5XX:解决方法:丢弃对用url,计数,出现多次连续情况时,报错,爬虫停止
- 500:服务器发生错误
- 503:当前不能处理客户端的请求,一段时间后可恢复正常
3.宽度与深度抓取的比较
- 宽度优先策略如下图所示:
上图的爬取顺序是ABCDEFGXYZHIJK
宽度优先就是从起始页面开始,先对同一页面中的其他URL进行抓取,然后再对该层次网页所指向的下一层次网页进行抓取。其优点是可以实现并行抓取,提高抓取速度。 - 深度优先策略如下图所示:
上图的顺序是ABCDEFGH
深度优先策略从起始页开始,一个URL一个URL跟踪下去,处理完这条线路之后再转入下一个起始页,继续跟踪链接。其优点是设计简单。 - 策略选择
深度限制于宽度优先相结合
4. 不重复抓取策略及BloomFilter
4.1常用的记录抓取历史的方法
- 将访问郭的URL保存到数据库, 此方法效率较低
- 用HashSet将访问过测URL保存起来,时间代价为O(1),但是会消耗内存
- URL经过MD5或SHA-1等单向哈希后再保存到HashSet或数据库
- Bit-Map方法,建立一个BitSet,将每个URL经过一个哈希函数映射到某一位
- Bloom Filter:使用多个哈希函数,创建一个m位的BitSet
4.2如何有效记录抓取历史
- 多数情况不需要压缩,尤其是网页数量少的情况
- 网页数量大的情况下,使用BloomFilter压缩
- 重点是计算碰撞概率,确定存储空间阈值
- 使用分布式系统,将散列映射到多台主机的内存
5.网站结构分析
利用sitmap来分析网站结构和估算目标网页的规模
- 利用sitemap中的信息,直接对目标网页进行抓取
- 对网站目录结构进行分析,大多数网站都会存在明确的top-down的分类的目录结构,可以进入特定的目录进行抓取。在特定目录下,url尤其固定的构成形式,我们可以对其根据相关信息构造url
6. 网页内容解析
- xpath
基本语法
=
符号要求属性完全匹配,可以用contains方法来部分匹配
and
和or
运算符可以判断两个条件同时成立或其中一个成立 - 正则表达式
常用规则:
7. 动态网页的解析
7.1动态网页的使用场景
- 单页模式:不需要外部跳转的页面
- 页面交互:页面有很多用户交互接口
- 内容及模块丰富:网页内容多,一次加载对服务器压力大,用户也往往不会全部查看内容
7.2解析动态网页的方法
- 分析网页加载过程中的请求内容,查看是否有新请求url,如果有,可以分析该url的构造规律,自行构造url,这种方法在分析url的时候虽然比较耗时,但是对提高爬虫效率缺很有效
使用Phantomjs和selenium webdriver,可以将网页中的动态部分全部加载出来再进行爬取,但是受网速影响较大,效率不是很高
Phantomjs:一种基于Webkit的Headless的web引擎
selenium:一个自动化的Web测试工具
Phantomjs常用基本设置:
selenium通过浏览器的驱动,支持大量的HTML及JavaScript的操作,常用的可以包括:
selenium在退出时必须调用driver.close()
和driver.quit()
退出Phantomjs, 否则Phantomjs会一直在后台运行占用资源。
8. 网站登录
8.1 Phantomjs + selenium
(1)设置User-Agent
from selenium.webdriver.common.desired_capabilities import DesiredCapabilities
user_agent = ("Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.36")
dcap = dict(DesiredCapabilities.PHANTOMJS)
dcap["phantomjs.page.settings.userAgent"] = user_agent
driver = webdriver.PhantomJS(desired_capabilities=dcap)
(2)输入用户名与密码,找到相应的表单位置,通过send_keys()来传递value
driver.find_element_by_id('loginname').send_keys(username)
driver.find_element_by_name('password').send_keys(password)
8.2 表单登录
8.2.1 HTML提交数据
(1) form表单:由浏览器实现POST方法
<form>
<input type="text" name="username">
</form>
(2) ajax请求:基于ajax技术,异步发送http请求并获得返回数据,然后利用JavaScript对网页进行处理
$.(ajax){
}
8.2.2 登录过程
(1)根据chrome inspector 里面检查到的参数,来设置登录方式
- 最常用的是x-www-form-urlencoded 和json方式,两种方式知识body的编码不同
- 如果是form-data,按照form-data的方式组合body
- body部分经常需要按照特定的方式编码,比如base64,或者MD5
- 对于非常复杂的登录协议,利用pantomjs+selenium登录
(2)request = urllib2.Request(url, data, headers= loginheaders)
- url:访问地址
- data:body的部分
- headers=loginheaders是HTTP请求的HEADER数据
8.2.3获取并设置cookie
登录的主要目的就是为了获取cookie,登录成功,HEADER就会设置cookie相关的信息,再后续的请求中继续使用该cookie。但是有时会遇到网页登录后返回302的情况,此时urllib2的response会丢失set-cookie的信息,导致登录不成功,这时需要自动处理cookie,一般可以使用以下插件:
- urllib2可以绑定一系列的处理对象handler,提供额外的功能支持
- 使用CookieJar
9. 多线程与多进程
9.1实现一个多线程爬虫
- 创建一个线程池 threads = []
- 确认url队列线程安全Queue Deque
- 从队列中取出url,分配一个线程开始爬取pop()、get() threading.Thread
- 若果线程池满了,循环等待,直到线程结束 t.is_alive()
- 从线程池移除已经完成下载的线程, thread.remove(t)
- 如果当前级别的url已经遍历完成,t.join()函数等待所有现场结束,然后开始下一级爬取
9.1.1优势
- 有效利用CPU时间
- 极大减小下载出错、阻塞对抓取速度的影响,整体上提高下载的速度
- 对于没有反爬虫限制的网站,下载速度可以多倍增加
9.1.2局限
- 对于有反爬的网站,速度提升有限
- 提高了复杂度,对编码要求更高
- 线程越多,每个线程获得的时间就越少,同时线程切换更频繁也带来了额外开销
- 线程之间资源竞争更激烈
9.2实现一个多进程爬虫
(1)C/S模式
1. 一个服务进程,入队及出队URL。入队需检查是否已经下载
2. 监控目前的爬取状态、进度
3. 多个爬虫进程,从服务进程获取URL,并将新的URL返回给服务进程
4. 使用Socket来做IPC
(2)数据库模式
1. 使用数据库来读写爬取列表
2. 多个爬取进程,URL的获取与增加都通过数据库操作
9.2.1目的
- 控制线程数量
- 对线程进行隔离,减少资源竞争
- 某些环境下,在单机上利用多个IP来伪装
9.2.2局限
- 不能突破网络瓶颈
- 单机单IP的情况下,变得没有意义
- 数据交换的代价更大
10. 分布式
分布式爬虫系统
11. 应对网站的反爬技术
11.1网站如何发现爬虫
- 单一IP非常规的访问频次
- 单一IP非常规的数据流量
- 大量重复简单的网站浏览行为
- 只下载网页,没有后续的js,css请求
- 通过一些陷阱来发现爬虫,例如一些用过css对用户隐藏的链接,只有爬虫才会访问
11.2如何应对反爬技术
- 多主机策略
- 降低访问频次
- 变换IP或者代理服务器
- 把爬虫放到访问频繁的主站IP的子网下
- 频繁改变自己的User-Agent
- 探测陷阱
- 如果使用规则来批量爬取,需要对规则进行组合
- 如果可能,按照Robots.txt定义的行为去文明抓取
- 模拟登陆
参考资料:小象学院《分布式爬虫实战》