利用PhantomJs抓取动态网页
# 简介
PhantomJS是可使用JavaScript编写脚本的无头WebKit,我们可以用来做一些爬虫工作,网页截图等,不过目前项目已经被挂起。
# 基本使用
下载执行文件对应自己的操作系统,目前最新的是v2.11 下载地址 (opens new window)
语法
phantomjs [options] script.js [arg1 [arg2 [...]]]
1
编写脚本 hello.js
console.log("hello phantomJS!")
phantom.exit(0)
1
2
2
执行脚本
phantom hello.js
1
输出
hello phantomJS!
1
# 抓取网页脚本
var page = require('webpage').create();
page.open('http://blog.unclezs.com', function (status) {
if (status !== 'success') {
console.log('failed');
} else {
console.log(page.content);
}
phantom.exit();
});
1
2
3
4
5
6
7
8
9
2
3
4
5
6
7
8
9
执行即可看到抓取到的html
# 自定义请求头
可以通过 http://httpbin.org/get (opens new window) 这个网站测试自己的请求内容
page.customHeaders={
'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 11_0_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.88 Safari/537.36'
}
1
2
3
2
3
# 忽略SSL错误
通过参数 --proxy=address:port 设置
比如 phantom --proxy=127.0.0.1:80 script.js
# 代理
通过参数 --ignore-ssl-errors=[true|false|yes|no] 默认为false
比如 phantom --proxy=127.0.0.1:80 script.js
# 优化
取消图片加载 --load-images=[true|false|yes|no] 默认true
# Java示例
# Js脚本
/**
* phantomjs 解析动态网页
* 支持传入referer、cookie、useragent
*
* @author blog.unclezs.com
* @date 2020-12-24
* @see https://phantomjs.org/api/
*/
var page = require('webpage').create();
var system = require('system');
// 只传入脚本名称 不传入参数不执行
if (system.args.length === 1) {
phantom.exit();
}
// 为了提升加载速度,不加载图片
page.settings.loadImages = false;
// 超过10秒放弃加载
page.settings.resourceTimeout = 10000;
// 忽略SSL错误
// 参数 需要按照顺序
var url = system.args[1];
var referer = system.args[2];
var cookie = system.args[3];
var userAgent = system.args[4];
var customHeaders = {
'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 11_0_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.88 Safari/537.36',
'Referer': url
};
if (referer) {
customHeaders['Referer'] = referer;
}
if (cookie) {
customHeaders['Cookie'] = cookie;
}
if (userAgent) {
customHeaders['User-Agent'] = userAgent;
}
page.customHeaders = customHeaders;
page.open(url, function (status) {
if (status === 'success') {
console.log(page.content);
}
phantom.exit();
});
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
# Java工具
/**
* https://phantomjs.org/api/
* <p>
* 首先 添加system properties PHANTOMJS_PATH、PHANTOMJS_SCRIPT
* <p>
* 不然会使用默认位置去读取
*
* @author blog.unclezs.com
* @since 2020/12/24 17:30
*/
@Slf4j
public class PhantomJsClient implements HttpProvider {
/**
* PhantomJs执行文件的位置
*/
public static final String PHANTOMJS_PATH = "PHANTOMJS_PATH";
/**
* 脚本位置
*/
public static final String PHANTOMJS_SCRIPT = "PHANTOMJS_SCRIPT_PATH";
public static final String DEFAULT_PHANTOMJS_SCRIPT = FileUtil.USER_DIR + "/script/spider.js";
public static final String DEFAULT_PHANTOMJS_PATH =
FileUtil.USER_DIR + "/script/phantomjs" + SystemUtil.getExecuteSuffix();
/**
* 获取网页内容
*
* @param data 请求数据
* @return /
* @throws IOException /
*/
@Override
public String content(RequestData data) throws IOException {
return executePhantomJs(PhantomJsRequestData.from(data));
}
@Override
public InputStream stream(RequestData requestData) throws IOException {
throw new UnsupportedEncodingException("PhantomJs动态网页HTTP客户端不支持获取流");
}
@Override
public boolean isDynamic() {
return true;
}
public String content(String url) throws IOException {
return content(RequestData.defaultRequestData(url));
}
/**
* 执行PhantomJs脚本抓取动态网页
* phantomjs [options] script.js [arg1 [arg2 [...]]]
* @param data 请求数据
* @return /
*/
public String executePhantomJs(PhantomJsRequestData data) throws IOException {
if (StringUtil.isEmpty(data.getUrl())) {
log.warn("phantomJS request url 不能为空");
return StringUtil.EMPTY;
}
StringBuilder command = new StringBuilder();
// phantomJs
command.append(System.getProperty(PHANTOMJS_PATH, DEFAULT_PHANTOMJS_PATH));
// 忽略SSL错误
command.append(StringUtil.BLANK).append("--ignore-ssl-errors=").append(data.isIgnoreSslError());
// 不加载图片
command.append(StringUtil.BLANK).append("--load-images=").append(data.isLoadImg());
// HTTP代理
if (StringUtil.isNotEmpty(data.getProxy())) {
command.append(StringUtil.BLANK).append("--proxy=").append(data.getProxy());
}
// script
command.append(StringUtil.BLANK).append(System.getProperty(PHANTOMJS_SCRIPT, DEFAULT_PHANTOMJS_SCRIPT));
// args
command.append(StringUtil.BLANK).append(data.getUrl());
command.append(StringUtil.BLANK).append(data.getReferer());
command.append(StringUtil.BLANK).append(data.getCookie());
command.append(StringUtil.BLANK).append(data.getUserAgent());
return CommandUtil.execute(command.toString());
}
}
/**
* 执行CMD命令工具
*
* @author blog.unclezs.com
* @since 2020/12/25 11:09
*/
@Slf4j
@UtilityClass
public class CommandUtil {
/**
* 执行CMD命令
*
* @param command 命令
* @return 控制台数据
*/
public static String execute(String command) throws IOException {
StringBuilder buffer = new StringBuilder();
log.trace("执行Command - 命令:{}", command);
Process process = Runtime.getRuntime().exec(command);
InputStream is = process.getInputStream();
BufferedReader br = new BufferedReader(new InputStreamReader(is));
String tmp;
while ((tmp = br.readLine()) != null) {
buffer.append(tmp).append(StringUtil.NEW_LINE);
}
return buffer.toString();
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
# 参考
在 GitHub 编辑此页 (opens new window)
上次更新: 2024/02/25, 12:11:11