简介

PhantomJS是可使用JavaScript编写脚本的无头WebKit,我们可以用来做一些爬虫工作,网页截图等,不过目前项目已经被挂起。

基本使用

下载执行文件对应自己的操作系统,目前最新的是v2.11 下载地址

语法

phantomjs [options] script.js [arg1 [arg2 [...]]]

编写脚本 hello.js

console.log("hello phantomJS!")
phantom.exit(0)

执行脚本

phantom hello.js

输出

hello phantomJS!

抓取网页脚本

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();
});

执行即可看到抓取到的html

自定义请求头

可以通过 http://httpbin.org/get 这个网站测试自己的请求内容

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'
}

忽略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();
});

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 zhanghongguo@sensorsdata.cn
 * @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();
    }
}

参考

官方文档

评论

博客
分类
标签
归档
关于