爬虫知识整理

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/haiyu94/article/details/79582784

目录

  1. HTML相关技术
  2. HTTP协议
  3. 宽度与深度抓取的比较
  4. 不重复抓取策略及BloomFilter
  5. 网站结构分析
  6. 网页内容解析
  7. 动态网页的解析
  8. 网站登录
  9. 多线程与多进程
  10. 分布式
  11. 应对网站的反爬技术

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
  • 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方法来部分匹配
    andor运算符可以判断两个条件同时成立或其中一个成立
  • 正则表达式
    常用规则:

这里写图片描述

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实现一个多线程爬虫

  1. 创建一个线程池 threads = []
  2. 确认url队列线程安全Queue Deque
  3. 从队列中取出url,分配一个线程开始爬取pop()、get() threading.Thread
  4. 若果线程池满了,循环等待,直到线程结束 t.is_alive()
  5. 从线程池移除已经完成下载的线程, thread.remove(t)
  6. 如果当前级别的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定义的行为去文明抓取
  • 模拟登陆

参考资料:小象学院《分布式爬虫实战》

猜你喜欢

转载自blog.csdn.net/haiyu94/article/details/79582784