作为比较好的动态网页爬虫手段,phantomjs在许多方面令人比较满意。调用Phantomjs的方式,一般有如下几种情况。
1. 命令行模式
在CMD或Shell中,直接输入phantomjs回车,进入命令行模式,能够完成各种操作。但一般情况是通过命令用调用phantomjs来完成爬虫或模拟工作,具体的代码放在JS中。如
../bin/phantomjs --debug=yes ./server.js 8910
../bin/phantomjs --debug=yes ./hello.js
其中phantomjs参数直接放在phantomjs后面,脚本作为参数放在其次,最后添加脚本的参数列表。
2. selenium调用
selenium是一套完整的测试爬虫工具,能够调用IE、Chrome、Firefox等浏览器内核API完成相应的功能,也可以调用如Phantomjs、HtmlUnitDriver等模拟浏览器作为调用接口。
调用浏览器内核与不调用浏览器内核的浏览器[这里指的是HtmlUnitDriver],浏览器内核的API,可以完成截图功能及其他浏览器功能,但HtmlunitDriver采用的是JS模拟浏览器的策略,因此不具备截图等浏览器功能。
2.1. Java+selenium+Phantomjs调用
public static PhantomJSDriver getPhantomJspublic static PhantomJSDriver getPhantomJs(String phantomJS,
String userAgent, boolean loadImages, boolean jsEnabled,
String encoding,boolean proxyEnabled,String... proxys) {
System.setProperty("phantomjs.binary.path", phantomJS);
DesiredCapabilities desiredCapabilities = DesiredCapabilities
.phantomjs();
if (userAgent != null) {
desiredCapabilities.setCapability(
"phantomjs.page.settings.userAgent", userAgent);
desiredCapabilities.setCapability(
"phantomjs.page.customHeaders.User-Agent", userAgent);
}
desiredCapabilities.setJavascriptEnabled(jsEnabled);
PhantomJSDriver driver = null;
List cli = new ArrayList<>();
cli.add("--load-images=" + loadImages);
cli.add("--output-encoding=" + encoding);
if (proxyEnabled) {
String proxy_ip = proxys[0];
String proxy_port = proxys[1];
String proxy_user = proxys[2];
String proxy_pass = proxys[3];
cli.add("--proxy="+proxy_ip+":"+ proxy_port));
cli.add("--proxy-auth=" +proxy_user+":" +proxy_pass);
}
desiredCapabilities.setCapability(
PhantomJSDriverService.PHANTOMJS_CLI_ARGS, cli);
driver = new PhantomJSDriver(desiredCapabilities);
driver.manage().timeouts()
.implicitlyWait(WAIT_TIME, TimeUnit.MILLISECONDS);
driver.manage().deleteAllCookies();
return driver;
}
2.2. Java+selenium+HtmlunitDriver调用
public static HtmlUnitDriver getHtmlUnitDriverpublic static HtmlUnitDriver getHtmlUnitDriver(String userAgent,
boolean jsEnabled, boolean loadImages, boolean proxyEnabled,
String... proxys) {
DesiredCapabilities desiredCapabilities = DesiredCapabilities
.htmlUnit();
desiredCapabilities.setCapability("phantomjs.page.settings.loadImages",
false);
desiredCapabilities.setJavascriptEnabled(jsEnabled);
if (userAgent != null) {
desiredCapabilities.setCapability(
"phantomjs.page.settings.userAgent", userAgent);
desiredCapabilities.setCapability(
"phantomjs.page.customHeaders.User-Agent", userAgent);
}
desiredCapabilities.setCapability(
PhantomJSDriverService.PHANTOMJS_CLI_ARGS,
new String[] { "--load-images=" + loadImages });
HtmlUnitDriver driver = null;
if (proxyEnabled) {
String proxy_ip = proxys[0];
String proxy_port = proxys[1];
String proxy_user = proxys[2];
String proxy_pass = proxys[3];
Proxy proxy = new Proxy();
proxy.setHttpProxy(proxy_ip + ":" + proxy_port);
desiredCapabilities.setCapability(CapabilityType.PROXY, proxy);
driver = new HtmlUnitDriver(desiredCapabilities) {
@Override
protected WebClient modifyWebClient(WebClient client) {
DefaultCredentialsProvider creds = new DefaultCredentialsProvider();
creds.addCredentials(proxy_user, proxy_pass);
client.setCredentialsProvider(creds);
return client;
}
};
} else
driver = new HtmlUnitDriver(desiredCapabilities);
driver.manage().timeouts()
.implicitlyWait(10 * 1000, TimeUnit.MILLISECONDS);
driver.manage().deleteAllCookies();
return driver;
}
3. 服务器模式
phantomjs服务器模式,需要在服务端开启服务,然后在客户端发起Http请求然后返回想要的内容,就是一个C/S模式的服务。
3.1. 服务端
server.js内容如下所示
var webserver = require('webserver').create();
var page = require('webpage').create();
var system = require('system');
var port = system.args[1];
webserver.listen(system.args[1], function(request, response) {
var url = request.headers.url;// conf target url in headers
page.open(url, function(status) {
var title = page.evaluate(function() {
return $(":root").html();// return pageSource
});
response.write(title);
response.close();
});
});
命令行启动
bin/phantomjs example/server.js 8910
3.2. 客户端
在客户端发起http请求,无论是get,还是post只要能够获取到Headers里面的目标URL,就可以返回pageSource。当然,这里最好使用异步加载网页内容。
Map<String, String> params = Map<String, String> params = new HashMap();
params.put("url", targetURL);
public static String HttpPost(String url, String postDataStr)
throws MalformedURLException, IOException {
URLConnection conn = new URL(url).openConnection();
conn.addRequestProperty("method", "post");
conn.addRequestProperty("ContentType",
"application/x-www-form-urlencoded");
conn.addRequestProperty("method", "post");
conn.addRequestProperty("http.socket.timeout", "60000");
conn.setDoOutput(true);
conn.getOutputStream().write(
URLEncoder.encode(postDataStr, "utf-8").getBytes());
StringBuilder sb = new StringBuilder();
BufferedReader br = new BufferedReader(new InputStreamReader(
conn.getInputStream()));
String line = null;
while ((line = br.readLine()) != null)
sb.append(line);
return sb.toString();
}
4. 比较
方式 | 优点 | 缺点 |
---|---|---|
命令行模式 | 1、调用简单 | 1、需要配合JS 2、无法大规模并发控制 |
服务器模式 | 1、减少内存 2、客户端方便 |
1、存在并发限制,最多10个线程 2、试验产品,可能存在安全隐患 |
selenium调用 | 1、客户端精准控制 2、调用比较方面,无需写JS 3、可大规模并发 |
1、“吃”内存:内存随线程数增加较快 2、需手动释放内存,确保phantomjs释放 |
5. 注
- 由于目前phantomjs已停止更新维护,所以可以选择其他带有webkit内核的模拟浏览器,如Headless Chrome等作为测试/爬虫的首选。
- phantomjs使用代理,最好使用无密码代理。
6. 参考
本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!