php抓取动态页面数据

为了安全性问题,很多网页会动态生成一些数据,当提交表单的时候会将这些数据提交服务端,然后在服务端进行校验。当遇到这类问题时,可以使用phantomjs或selenium模拟浏览器行为加载js脚本,获取动态数据。以京东模拟登陆(仅以学习为目的)为例:

京东模拟登陆

通过开发者工具Network分析网络请求数据可得京东登陆接口:
"京东登陆页面网络请求"

所需参数如下:
"参数列表"

页面源码如下:
"页面源码"

开发者工具Elements如下:
"elements"
经尝试可得eid与fp需引入js脚本方可获取其值。若仅使用curl抓取该页面数据,则无法抓取所需的所有数据。为此,使用phantomjs或selenium模拟浏览器行为加载js脚本。

phantomjs

下载链接:phantomjs download
quick start:phantomjs quick start

使用phantomjs加载js脚本文件

load.js:

1
2
3
4
5
6
7
var page = require('webpage').create();
page.open('https://passport.jd.com/new/login.aspx?ReturnUrl=https%3A%2F%2Fwww.jd.com%2F', function(status) {
page.includeJs('https://payrisk.jd.com/js/td.js', function () {
console.log(page.content);
phantom.exit();
});
});

上述代码将页面代码以字符串的形式返回。

调用phantomjs脚本

exec(‘phantomjs load.js’, $output);

exec()函数说明:

1
string exec ( string $command [, array &$output [, int &$return_var ]] )

exec() 执行 command 参数所指定的命令。
command
要执行的命令。

output
如果提供了 output 参数,那么会用命令执行的输出填充此数组,每行输出填充数组中的一个元素。数组中的数据不包含行尾的空白字符,例如 \n 字符。请注意,如果数组中已经包含了部分元素,exec() 函数会在数组末尾追加内容。如果你不想在数组末尾进行追加,请在传入 exec() 函数之前对数组使用 unset() 函数进行重置。

return_var
如果同时提供 output 和 return_var 参数,命令执行后的返回状态会被写入到此变量。

返回值
命令执行结果的最后一行内容。如果想要获取命令的输出内容,请确保使用 output 参数。

至此,可通过preg_match函数对源码进行模式匹配,提取出需要的数据。利用php curl扩展模拟post请求。

post参数被加密怎么办?

如密码字段使用JSEncrypt库加密后再向服务端请求,这时可以使用phantomjs调用该js库,获取加密后的密码字符串,示例代码如下:
encrypt.js:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
var page = require('webpage').create();
var system = require('system');
var pwd = system.args[1];
var pubKey = system.args[2];

page.includeJs('https://passport.jd.com/new/js/jdJsencrypt.min.js', function () {
var encryptPwd = page.evaluate(function(pubKey, pwd) {
var encrypt = new JSEncrypt();
encrypt.setPublicKey(pubKey);
return encrypt.encrypt(pwd);
}, pubKey, pwd);

console.log(encryptPwd);
phantom.exit();
});

终端运行:

1
$ phantomjs encrypt.js args1 args2

require(‘system’)获取命令行脚本参数,以此可以将php内的变量值传递进来,同上用exec()执行该命令行脚本,即可获取加密后的密码字段。

总结

当需要抓取动态网页数据时,可以使用phantomjs和selenium模拟浏览器行为加载js文件。