浅谈动态爬虫与去重

日期: 2024-09-20 20:04:10|浏览: 70|编号: 96775

友情提醒:信息内容由网友发布,请自鉴内容实用性。

浅谈动态爬虫与去重

预计稿费:(如不同意,就来投稿吧!)

投稿方式:发送邮件至#,或登录网页版在线提交

0x01 简介

随着Web 2.0的发展,页面中的AJAX越来越多,由于传统爬虫依赖静态解析,无法准确抓取页面中的AJAX请求和动态更新内容,越来越不能满足需求。基于动态解析的Web 2.0爬虫应运而生,它通过浏览器内核解析页面源代码,模拟用户操作,可以有效解决上述问题。本文将详细分析使用+编写爬虫并进行去重的思路。

0x02

它是一个提供API的无界面解析器,由于去掉了可视化界面,所以速度比普通浏览器快很多,同时提供了很多监听和事件接口,可以很方便地操作DOM节点,模拟用户操作等。

接下来我们通过一个简单的例子来展示动态爬虫和传统爬虫的区别。目标:加载一个页面(那么,我们一起来玩吧)并获取其中所有的标签。

/.((){如果(.===''){.();}},10000)});

爬取结果如下:

/.mine/cmd2///cmd2///.html/.blog/.mine/.at/~发现推荐./help.html/江南水乡.bbs//摄影爱好者.bbs//快乐家庭.bbs//深夜食堂.bbs//顽皮小朋友之家.bbs//乐淘亲子营.bbs/.../*省略*/.../婚礼记录.bbs//我不知道的事.bbs//我不知道的事.bbs//婚礼记录.bbs//我不知道的事.bbs//cmd2///内容举报.html

静态爬取代码如下:

= .get("")count = 0pq = .(res.)for i in pq("a"):print (“[%d]: %s” % (count, pq(i).attr(“href”))

抓取结果为空。

从上面的例子我们可以很明显的看到,动态分析比静态分析捕获的结果更多。造成这种差异的原因是页面中的数据是通过 AJAX 请求加载的,并且所有标签都是动态更新到页面上的。静态分析在这种情况下无能为力,而基于浏览器内核的动态分析可以轻松处理这些情况。

但是动态解析的缺点也是显而易见的:占用系统资源较多且耗时较长,存在一些难以解释的陷阱,编写起来也比较复杂且耗时(需要对前端编程有一定的了解)。

当然还有一些其他的动态解析器​​,比如PyQt(最新版本也是基于pyqt的),也有基于内核的,基于封装的,基于Gecko的等等。由于没有统一的标准,各个动态解析器​​的API实现各不相同,会有各种各样的陷阱,并没有“最佳”的解决方案。

0x03 触发事件和页面监控

上面的例子介绍了爬虫中一个常见的场景:页面加载完成后通过 AJAX 加载数据。但实际场景往往更加复杂,需要在与用户交互后触发,比如点击按钮后跳转到某一页面,滚动到页面末尾后加载下一页的数据等。我们需要一个新的解决方案来模拟正常的用户操作。那么,我们应该如何将用户交互抽象成代码呢?

用户操作的本质其实就是触发绑定在 DOM 节点上的事件。因此,模拟用户操作的问题可以简化为触发节点事件。事件执行的结果也是多种多样的,但对于爬虫来说,我们只需要关注两个结果:1、是否有新的节点加入(等)2、是否发起新的​​请求(包括 AJAX 请求、跳转等)。简化之后,我们需要解决的问题是:

1.如何获取绑定事件?

2. 如何触发事件?

3.如何获取事件触发的结果?

最终我们的解决方案如下:

1.如何获取绑定的事件?在绑定事件中,会调用该函数,在页面中的代码执行前(|),钩子函数可以捕获到哪些DOM节点绑定了该事件。

12345

= ..;.. = (a,b,c) {.push({"event": event, "": this}).apply(this, );};

2.如何触发事件? 提供函数来触发指定DOM节点的指定事件,也就是我们在上一个问题中收集到的。

12345

for(var i in ){var evt = .('');evt.([i]["event"], true, true, null);[i][""].(evt);}

除了绑定事件之外,还有一些东西无法通过钩子获得。例如:

解决方法就是遍历节点,并执行所有属性的值。

61718

(){var nodes = .all;for (var i = 0; i < nodes.; i++) {var attrs = nodes[i].;for (var j = 0; j < attrs.; j++) { = attrs[j].; = attrs[j].;如果 (.(0, 2) == "on") {.log(attrs[j]. + ' : ' + );eval();}如果 ( in {"src": 1, "href": 1} && attrs[j]..(0, 11) == ":") {.log(attrs[j]. + ' : ' + );eval(.(11));}}}}

3.事件触发的结果如何获取?HTML5中的方法可以检查页面中的DOM是否发生变化。但是不支持(为 摊手 ),解决办法就是监听事件。捕获AJAX请求有两种解决方案:可以捕获非主框架的请求,但需要通过正则表达式匹配过滤掉有效的请求;hook .open 和 .send 可以准确捕获请求内容。

.('', (e) {var node = e.;如果(node.src || node.href){.push(node.src || node.href);}}, true);_open = ....open = (, url) {如果(!this._url) {this._url = url;this. = ;}_open.apply(this, );};_send = ....send = (data) {.$$.(this._url, this., data);_send.apply(this, );};

理一下,在页面加载前,需要hook.open、.send三个接口,在页面加载完成后,需要获取全部,

接下来是爬虫的效率测试,爬取目标是百度贴吧。结果如下:

1234

#.exe /Crawl //C:\Users\xxx\/计数:201,计数:101,时间计数:#.py {“depth”:5,“”:10}计数:410,:535,:339

可以看到随着网站复杂度的提升,WVS爬虫的请求数增长比较平稳,当线程数为10时,6分钟内完成爬取任务,属于正常性能。

在分析过程中,虽然速度很快,整体效率很高,但也存在一些缺点:无法指定爬取深度、无法跨平台、对伪静态URL去重效果较差(如下图所示,共计43个,占比42%)、有些URL分割会导致爬虫结果出现问题(例如:会拆分成两个,/home和/home/main,所以实际扫描到的URL数量会比结果少)等等。

由于目标网站的URL较多,覆盖率很难衡量,我们用脚本简单对比了一下爬取结果,除去静态资源,覆盖了98%的爬取结果(也就是98%的爬取结果也被抓取到了),而静态资源的覆盖率只有38%。

0x06 总结

除了上面提到的去重、动态解析之外,还有一些小技巧,比如对常用路径进行、从.txt中提取信息、爬取过程中识别敏感信息、生成网站信息画像等等,对爬虫覆盖以及后续的扫描任务有所帮助。

本文详细介绍了动态爬虫实现中可能遇到的问题及解决方法。优秀的代码并非一朝一夕就能实现的,需要不断的优化调整。后续会考虑开源,欢迎交流。

参考

让别人开心却让我伤心

陷阱清单

——打造强大的爬虫工具

XSS 使用

提醒:请联系我时一定说明是从浚耀商务生活网上看到的!