使用v8识别js重定向

一 重定向
爬虫抓取的过程中,遇到重定向时需要识别出重定向后的url。
总结下,主要有如下3类重定向:
1 http协议的3XX
301 永久移动
302 临时
305 必须通过指定定代理才能访问相应资源
307 临时

比如 访问http://www.meilishuo.com/,响应如下

HTTP/1.1 301 Moved Permanently
Server: mls/1.1
Date: Mon, 01 Jul 2013 07:19:15 GMT
Transfer-Encoding: chunked
Connection: keep-alive
Location: /welcome
Cache-Control: no-cache,must-revalidate,no-store
Pragma: no-cache

2 html的meta字段
meta字段的refresh属性

<html>
<meta http-equiv="refresh" content="1; url=http://www.petermao.com" />
<body>
</body></html>

3 js重定向
有好几种,后面总结下,这里给个简单例子:

<html><body>
<script type='text/javascript'>window.open("http://www.petermao.com")
</script>
</body></html>

解决方案:
第一种在获得http首部后,根据状态码,就可以判断是否重定向,再根据location属性来获取重定后的url。

第二种已经获得了网页内容。一般是是通过正则匹配出meta,refresh以及content属性,再获取重定向后的url。当然也可以进行dom解析,正确性会好点,但可能会存在性能问题,个人感觉没有这个必要。正则匹配即可。

第三种是难点。我们先来看看js重定向有哪些表现形式。

二 JS重定向分类
主要有如下几类,这里得到了朋友@秋声落叶的帮助,欢迎其他朋友补充。
1 window:
window.open(url)

2 location属性:

location=url;
location.href=url;
window.location=url;
document.location=url;
window.location.href=url;
window.location.replace(url)
window.location.assign(url)
location.replace(url);
location.assign(url);
self.location=url;
top.location=url;

3 navigate方法:

window.navigate(url)
top.navigate(url);

4 document+meta字段

document.write('<META HTTP-EQUIV="refresh" content="0;url=http://www.petermao.com">');
document.writeIn('<META HTTP-EQUIV="refresh" content="0;url=http://www.petermao.com">');
document.close();

三 JS重定向识别的1个思路
1 问题
要识别前面的重定向,通过正则可能不现实,比如前面的JS可以封装在函数里,通过变量来传递重定向后的url。比如前面的location的变种:

<html>
<head>
<script type='text/javascript'>
function AutoRedirect(seconds,redirectUrl){
setTimeout("Redirect('"+redirectUrl+"')",seconds);}
function Redirect(redirectUrl){
location.href=redirectUrl;
}
</script>
</head>
<body>
<script type='text/javascript'>AutoRedirect(2, 'http://www.petermao.com');
</script></body></html>

此时要获得这些JS,只能通过完整的解析了,基于DOM树可以完整的获取这些JS。将script当作html的一个标签即可。
在完整获得这些JS后,怎么知道其实际表示什么内容了?这个就需要JS运行环境了。可以考虑开源的V8与SpiderMonkey了。(本文只考虑V8)。

2 使用V8的问题
不过这里有个问题,对于在浏览器中运行的html网页,浏览器会提供1个叫做window的全局对象,像location、top等对象,以及settimeout等函数就是window的子属性/方法,而这个window的实现被封装在BOM模型(浏览器对象模型)中,该模型不像DOM、JS那样有统一的标准。V8只提供JS运行环境,像window等对象是由浏览器内核提供的,比如webkit中有BOM的实现。之前曾短暂研究过webkit,不过这货太过复杂,还未入门,抽取其中的库来解析与运行网页,不知道是否可行,有研究的朋友可以一起讨论下。前面那些抽取出来的JS,如果直接交给V8来运行,会出现undefined的错误,也就是window、location、settimeout等在V8中并没有定义。

3 最后
在只有V8的情况下,如何运行网页中的JS了?那就需要mock了。

V8中表示JS运行环境的是Context对象,我们可以一开始在Context中初始化window等全局对象。然后轮流运行解析出来的JS脚本,最后通过location属性来获取重定向后的url。

最后给出部分初始化mocker代码如下,完整的需要mock前面给出的JS重定向的各种变形。实际mock可以参考Node.js,该货基于V8,提供了一些有用函数的实现,也有利于了解V8的特性。

至于V8的使用,还是翻翻官方文档吧,这里就不说了。

类似的,对于有些JSON数据,或者AJAX的抓取,应该也可以考虑类似的思路。欢迎大家讨论。

window = {};
location = {};
window.location = {};
location.href = {};
window.location.href = {};
top={};
parent={};

location.assign = function (url) {
  window.location.href = url;
}

location.replace = function (url) {
  window.location.href = url;
}

window.location.assign = location.assign;
window.location.replace = location.replace;
---
此条目发表在 搜索引擎 分类目录,贴了 , , 标签。将固定链接加入收藏夹。

发表评论

电子邮件地址不会被公开。 必填项已被标记为 *

*

您可以使用这些 HTML 标签和属性: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>