爬虫篇:动态网页的处理方式(上)——逆向工程

###每篇一句:

A man is not old as long as he is seeking something. A man is not old until regrets take the place of dreams.


动态网页简介:

在我们编写爬虫时,可能会碰到以下两种问题:

  • 我们所需要爬取的数据在网页源代码中并不存在;
  • 点击下一页跳转页面时,网页的URL 并没与发生变化;

造成这种问题原因是,你所正在爬取的页面采取了动态加载的方式,是一个动态网页。

所谓的动态网页,是指跟静态网页相对的一种网页编程技术。静态网页,随着html代码生成,页面的内容和显示效果就不会发生变化了。而动态网页则不然,其显示的页面则是经过Javascript处理数据后生成的结果,可以发生改变。这些数据的来源有多种,可能是经过Javascript计算生成的,也可能是通过Ajax加载的。

动态网页经常使用的一种技术是Ajax请求技术。

  • Ajax:

    Ajax = Asynchronous JavaScript and XML(异步的 JavaScript 和 XML),其最大的优点是在不重新加载整个页面的情况下,可以与服务器交换数据并更新部分网页的内容。

目前,越来越多的网站采取的是这种动态加载网页的方式,一来是可以实现web开发的前后端分离,减少服务器直接渲染页面的压力;二来是可以作为反爬虫的一种手段。


爬虫处理动态页面的两种方式

接下来就以 新浪读书——书摘 这个网站为例(典型的Ajax请求技术应用),采用这两种方法分别介绍一下爬虫如何处理这种动态页面,获取所需要数据的。


逆向工程:

对于动态加载的网页,我们想要获取其网页数据,需要了解网页是如何加载数据的,该过程就被成为逆向工程

对于使用了Ajax 请求技术的网页,我们可以找到Ajax请求的具体链接,直接得到Ajax请求得到的数据。

  • 需要注意的是,构造Ajax请求有两种方式:
    • 原生的Ajax请求,会直接创建一个XMLHTTPRequest对象。
    • 调用jQuery的ajax()方法。一般情况下,$.ajax()会返回其创建的XMLHTTPRequest对象;但是,如果$.ajax()dataType参数指定了为scriptjsonp类型,$.ajax()不再返回其创建的XMLHTTPRequest对象。

对于这两种方式,只要创建返回了XMLHTTPRequest对象,就可以通过Chrome浏览器的调试工具在NetWork窗口通过设置XHR过滤条件,直接筛选出Ajax请求的链接;如果是$.ajax()并且dataType指定了为scriptjsonp,则无法通过这种方式筛选出来。


示例:

接下来以 新浪读书——书摘 为例,介绍如何得到无法筛选出来的Ajax请求链接:

  1. 在Chrome中打开网页,右键检查,会发现首页中书摘列表包含在一个id为subShowContent1_static的div中,而查看网页源代码会发现id为subShowContent1_static的div为空。

    点击更多书摘下一页时,网页URL并没有发生变化。

    与我们最前面所说的两种情况相同。

  2. F12打开调试工具,打开NetWork窗口*(功能是记录浏览器的活动记录network activities)*,F5刷新,可以看到浏览器发送以及接收到的数据记录:

    活动记录

    其实我们所找的Ajax请求链接就是其中一条。

    首先设置XHR过滤条件:

    过滤条件

    发现为空白,可以推断出这个网页采用的Ajax请求应该是设置了dataTypescript或者jsonp

  3. 重新打开调试工具,点击网页上的更多书摘,发现NetWork窗口出现了很多记录,网页也多了新的内容,说明浏览器向服务器发送了请求。

    在网页上,右键检查 更多书摘,观察次元素绑定的JavaScript事件:

    JavaScript

    根据JavaScript的知识:javascript:是一个伪协议,表示在触发<a>时,执行一段JavaScript代码,而javascript:;表示什么都不执行,这样点击<a>时就没有任何反应。但一般在这种情况下,会给<a>绑定一个事件回调,来执行业务.

    接下来就需要在网页的JavaSCript代码中找到更多书摘所触发的回调函数。

  4. 右键检查网页源代码Ctrl+F搜索subShowContent1_loadMore”(元素更多书摘的id),发现并没有某个具体的函数与之相关:

    函数

    这说明更多书摘的回调函数不在网页自身写的JavaScript代码中,那就应该在网页嵌入的JS文件中(通过<script type=”text/javascript” src=“***.js”> <script>这种形式调用的JS文件)。

  5. 逐个打开嵌入的JS文件,查找与更多书摘绑定的函数,终于在“http://n.sinaimg.cn/book/js/feedlist.js”这个JS文件中发现函数$()如下:

    函数

    • 但此函数中并没有直接构造Ajax请求,而是通过调用ListMore()函数执行。

    • 查找ListMore()函数,发现其内部还是未构造Ajax请求,通过ListMore()内部调用的函数进一步寻找,经过以下过程:

      $() -> ListMore() -> GetmoreList() -> getMore()

    • 终于在getMore()函数中发现了Ajax请求的构造过程,发现dataType确实是jsonp

      函数

  6. NetWork窗口Initiator栏点击feedlist.js进入Sources窗口:

    7

  7. 之前我们说过,在NetWork窗口就有我们需要的Ajax请求链接,对比发现,果然存在:

    存在

  8. 当我们点击更多书摘下一页时,发现又多了几条这样的请求:

    翻页

    对比发现:只有jsonp**********page=*这两部分不同, jsonp后面跟的数字为当前时间的时间戳,是jQuery.ajax()方法自动计算添加的,page后面就是页数,这时候我们只要改变page后面的数字就可以构造翻页的链接了。


总结一下这种方法:
  • 首先通过设置XHR过滤条件,观察是否可以直接得到Ajax 请求;如果不可以,继续下一步。
  • 查找能够发送Ajax请求的元素绑定的事件或回调函数:首先在网页源代码中查找,没有的话,逐个查找嵌入的JS文件。
  • 找到之后,看函数内部是否直接构造Ajax请求,没有直接构造的话,根据函数调用关系一步一步查找,直到找到构造过程为止。
  • 添加断点,调试,根据Ajax请求的构造方式以及数据形式手动构造链接。
  • 验证构造的链接的正确性。

其实当你有了经验之后,对一些不是很复杂的网页,根本就不用进行这么复杂的逆向工程,凭URL形式可以很快的在NetWork窗口很快的 选择-验证 出所需的Ajax请求。

得到Ajax请求链接之后,可以直接得到请求的数据,一般为json格式,处理后即可使用。

代码见:dynamic-web-process —— GitHub


最后:

  本文以 新浪读书——书摘 这个示例,介绍了如何得到 Ajax请求链接,这是爬取动态网页时可以采取的一种方式,这种方式可能会在寻找Ajax请求的过程中浪费一点时间,并且要求对JavaScript有一定的了解,但找到链接后,爬取的过程可以很迅速。

  如果对爬虫执行效率没有过多要求,又不想浪费太多时间在了解JavaScript代码逻辑、找寻Ajax请求链接上,可以参看下一篇文章 爬虫篇:动态网页的处理方式(中)—— 渲染动态网页,这篇文章提供了爬取动态网页的另一种思路。


文中有什么错误或不足之处,欢迎指出!

评论 15
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值