定向智能爬虫架构解决方案

随着互联网信息的不断发展,信息数据的挖掘技术也不断的发展。网络爬虫技术也随之得到了巨大的发展。而对于内容型驱动的网站来说反扒是一件必不可少的事情。很多网站用 Jquery 加壳、登录验证、限制单位 IP 每秒请求次数来阻止爬虫窃取数据。所以爬虫的智能性也受到越来大的挑战。由此得出一个适应现国内爬虫架构的解决方案。

引言

目录

1、——————URL 深度优先策略的再优化
2、——————模拟浏览器内核使抓取更强大
3、——————适应失效代理 ip 的管理优化

4、——————URL 上下文使开发业务逻辑更加简单
5、——————多线程的控制
6、——————任务的定时问题
7、——————dump 出错页面将使调试更加方便
8、——————抓取 log 解决中断抓

9、——————爬虫的 jvm 参数优化
10、—————–建立在 hadoop 基础上实现分布式

1、URL 深度优先策略的再优化

深度优先搜索策略。这种策略的主要思想是,从根节点出发找出叶子节点,以此类推。在一个网页中,选择一个超链接,被链接的网页将执行深度优先搜索,形成单独的一条搜索链。当没有其他超链接时,搜索结束。然而这种自动化 URL 深度自定义并不能达到业务要求的最佳优先状态。

我们来看传统 URL 队列模型。图中有一个入口 URL“A”解析得到三个跟进 URL“B”。传统的抓取顺序如飞机图标标注。每个子入口 URL 顺序抓取得到“C”。问题出来了。假如需要抓取信息就在 C 那么第一个 C1 出来就可去抓取 C1 的信息了。为什么要迟迟等到 B 抓取完了才能开始抓取 C 呢。而且如果根据 URL 多深度大的话下级 URL 越积越多。这是对内存的巨大的浪费,所以爬虫容易内存溢出问题也在这里体现了一个方面。

最佳的优化效果得到了一组“B”URL 后递归抓取完每个 B 及下面的子 URL”C”。这样就不会产生当前还处理不了但有消耗内存巨大的跟进 URL 堆积问题。优化后如图。

2、模拟浏览器内核使抓取更强大

网页上需要内容都是 JS 动态加载的。有的甚至是 jquery 加载后 html 源码根本无法看到信息数据。解决这种问题唯一的办法是让爬虫自己变成一个没有界面的浏览器。现在 java 有现成的浏览器驱动库 htmlunit 可以模拟浏览器,也可以调用现成的火狐、谷歌内核。Python 有 pyv8 的 JS 引擎、QtWebKit 等组件。有了这些组件我们封装一个爬虫带 js 调用和模拟登陆的就很简单了。

模拟浏览器架构:

1、因为浏览器内核消耗内存较大,需要封装一个内核池 WebDriberPool 来管理所有的内核,统一创建和关闭。

2、下载器必须对外提供设置 JS 代码的接口

3、当下载网页时需要执行 JS 自动执行先前设置好的 JS 代码

4、当爬行模式为代理 IP 模式的时候自动向 IP 管理取得 IP

3、适应失效代理 ip 的管理优化

对于普通的网站来说我们可能只要设置请求头 User-Agent 就可以轻易绕过网站服务器的反扒机制。但是对于大型网站可就没这么简单了。它们会通过通过网站流量统计系统和日志分析或者限制 IP 每秒请求次数来识别爬虫。但是它们怎么防也防不了代理 IP 的自动轮换访问。目前国内基本不存在所谓的”高匿代理 IP”。一些代理 IP 供应商的失效率也是很高的。几乎找不到永久有效的代理 IP。既然没有,何必苦苦寻找。为什么不去适应这种代理 IP 失效是常态的现状。我们现在可以就提出几点代理 IP 管理架构上的需求。

假如我们已经购买了某家代理 IP,并供应商提高 API 提取方式。

1 需要代理 IP 网络缓冲池

2 需要代理本地缓存池,用以缓存有效 IP

3 当爬虫提取代理 IP 时判断缓存是否达到足够使用的量,有则拿缓存好的 IP。

4 没有缓存则进行网络提取一批代理 IP 加入到网络缓冲池。

5、爬虫抓取过程也是验证过程。有效代理 IP 被 Cache 到缓存池以提供其他请求使用。

6、当请求失败后如果该 IP 来自缓存则将器 IP 踢出缓存队列。

7、可设置代理 IP 失效超时时间。在内存驻留超过时间的 IP 踢出队列

实现框架图如下:

4、URL 上下文使开发业务逻辑更加简单

在开发爬虫的时候发现数据库设计的数据常常在单一页面抓不完整。通常需要几个页面或者需要查询一些业务关联 ID。那么对于这些情况一般是重新去数据库查询更新的数据,所以在写 DAO 层的时候也多了很多方法。业务逻辑复杂度也越来越高。案例如图:

上下文类架构:

1、建立为每个初始 URL 封装 startRequest

2、提供支持线程并发安全的全局缓存的键值表

3、每个 Request 的实例化转移到上下文类当中

4、爬虫抓取时可向键值表中 put 属性

5、子页面需要时可以通过 Requst 取得上下文实例取得相应属性

6、爬虫任务完成。自动清除所有上下文缓存信息。

5、多线程的控制

爬虫线程工作周期很长如果在程序的某个阶段发生异常那么以为着之前程序所做的工作将会前功尽弃。所有爬虫多线程应划分为两个部分。一个是专门请求 URL 下载 html 页面的线程。这部分线程耗时长,各自工作独立,不需要较多使用 synchronized ,容易发生异常。另一部分是“离线处理“的线程就是把下载回来的数据进行抽取、清洗、封装、存储的线程。这部分线程跟业务关系紧密,处理快耗时短。工作有时需要协调、需要使用较多 synchronized 和线程安全的缓冲队列。建议下载线程和离线处理线程数量比例的 4:1。

最后还有一个线程生命周期和爬虫任务相同,它不断轮询 URL 队列最新的 URL,把 URL 分配给下载线程。

6、任务的定时问题

爬虫任务周期长或者周期短。或业务需要爬虫重复去抓取一些动态数据。这时就需要定时机制。实际上 Java 的 Timer 已经提供了定时的功能。我们只需要将启动爬虫的程序交给定时器。爬虫任务完成继而向定时器设置下次启动时间。随后休眠,等待再次启动。

结合多线程控制和任务定时管理得出如下架构图:

文章出处:CSDN