-
Notifications
You must be signed in to change notification settings - Fork 3
/
Copy pathcraw.js
215 lines (168 loc) · 5.72 KB
/
craw.js
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
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
/*global phantom*/
"use strict";
//相当于 -vvv 模式
var debugMode = false;
//单个请求的最长时间 ms
var singleRequestTimeout = 5000;
// 每隔 N 毫秒检查 dom 是否加载完毕
// 其实基本上都加载完毕了,因为本来就是 phantomjs 的 onLoadFinished 的回调
// 这个值基本等同于页面执行的时间,为了等待 js 执行
var domReadyCheckTime = 200;
//默认ua
var ua = '';
//浏览器宽高
var viewSize = {
width: 1280,
height: 1014
};
var customHeaders = {
"Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8"
};
// bug see https://github.com/ariya/phantomjs/issues/10150
console.warn = function () {
require("system").stderr.write(Array.prototype.join.call(arguments, ' ') + '\n');
};
console.error = function () {
require("system").stderr.write(Array.prototype.join.call(arguments, ' ') + '\n');
};
phantom.onError = function (msg, trace) {
var msgStack = ['PHANTOM ERROR: ' + msg ];
if (trace && trace.length) {
msgStack.push('TRACE:');
trace.forEach(function (t) {
msgStack.push(' -> ' + (t.file || t.sourceURL) + ': ' + t.line + (t.function ? ' (in function ' + t.function + ')' : ''));
});
}
console.error(msgStack.join('\n'));
phantom.exit(1);
};
// PhantomJS WebPage模块
var page = require('webpage').create();
// NodeJS 系统模块
var system = require('system');
// 资源请求并计数
page.onResourceRequested = function (req, net) {
if (debugMode) {
console.error('req '+req.id + ' ' + req.url + ' ' + req.method);
}
};
// 资源加载完毕
page.onResourceReceived = function (res) {
// chunk模式的HTTP回包,会多次触发resourceReceived事件,需要判断资源是否已经end
if (res.stage !== 'end') {
return;
}
if (debugMode) {
console.error('res ' +res.id + ' ' + res.url + ' ' + res.status + ' ' + res.redirectURL);
}
// 第一次请求
if (res.id === 1) {
requestHeaderContentType = res.contentType;
requestHeaderStatus = res.status;
if (res.redirectURL) {
requestRedirectUrl = res.redirectURL;
}
}
};
// catch error,防止错误直接暴露到页面
page.onError = function (msg, trace) {
var msgStack = ['ERROR: ' + msg ];
if (trace && trace.length) {
msgStack.push('TRACE:');
trace.forEach(function (t) {
msgStack.push(' -> ' + t.file + ': ' + t.line + (t.function ? ' (in function "' + t.function + '")' : ''));
});
}
console.error(msgStack.join('\n'));
};
page.onConsoleMessage = function(msg, lineNum, sourceId) {
console.error('CONSOLE: ' + msg + ' (from line #' + lineNum + ' in "' + sourceId + '")');
};
// 资源加载超时
page.onResourceTimeout = function (request) {
console.error('Response (#' + request.id + '): ' + request.url + ' timeout ' + JSON.stringify(request));
};
// 资源加载失败
page.onResourceError = function (resourceError) {
console.error('Unable to load resource (#' + resourceError.id + 'URL: ' + resourceError.url + ' )' + ' Error code: ' + resourceError.errorCode + '. Description: ' + resourceError.errorString);
};
page.onLoadFinished = function(status) {
if (debugMode) {
console.error('onLoadFinished: ' + status + ' ' + url );
}
};
page.onLoadStarted = function() {
if (debugMode) {
console.error('onLoadStarted: ' + url);
}
};
var requestRedirectUrl = '';
var requestHeaderContentType = '';
var requestHeaderStatus = 200;
// 从CLI中获取第二个参数为目标URL
var url = system.args[1];
if (system.args[2]) {
ua = require('base-64').decode(system.args[2]);
}
// 设置PhantomJS视窗大小
page.viewportSize = viewSize;
//timeout
page.settings.userAgent = ua + ' ' + 'ServerRenderJavascript';
page.settings.resourceTimeout = singleRequestTimeout;
page.customHeaders = customHeaders;
// 页面 load 完毕,开始处理数据
var capture = function (errCode) {
//纯文本数据
var content = page.plainText;
//对 html ,需要保留标签,并且读取渲染之后的数据
if (requestHeaderContentType.indexOf("html") > -1) {
content = page.evaluate(function() {
return "<!DOCTYPE html>\n" + document.documentElement.outerHTML;
});
}
//对 xml ,需要保留标签
if (requestHeaderContentType.indexOf("xml") > -1) {
content = page.content;
}
//没有获取到内容时,记录错误,并返回错误
if (content === '') {
errCode = 3;
console.error("Unsupported Type: " + requestHeaderContentType + ' ' + url);
}
content = requestHeaderStatus + "\n" + requestHeaderContentType + "\n" + requestRedirectUrl + "\n" + content;
console.log(content);
// 任务完成,正常退出
phantom.exit(errCode);
};
// 每 N 毫秒检查一次是否加载完毕
function checkReadyState() {
setTimeout(function () {
var readyState = page.evaluate(function () {
return document.readyState;
});
if (debugMode) {
console.error('readyState: ' + readyState + ' ' + url);
}
if ("complete" === readyState) {
capture(0);
} else {
checkReadyState();
}
}, domReadyCheckTime);
}
// 打开页面,回调表示加载完毕 html 时
page.open(url, function (status) {
if (status !== 'success') {
phantom.exit(1);
} else {
if (debugMode) {
console.error('onLoadFinished in open Callback: ' + url + ' ' + status);
}
//只有 html 页面才需要等待渲染
if (requestHeaderContentType.indexOf("html") > -1) {
checkReadyState();
} else {
capture(0);
}
}
});