selenium + chrome(jbrowser) + Js

2020-01-22  本文已影响0人  咖啡不加糖HF

背景

最近有项目需求,改用无头浏览器进行微信文章得爬取,并对文章进行相应得改动,我虽并非爬虫方向开发,在需求开发过程中也有所总结,踩了不少坑,特此记录一下。

目前业界比较公认的无头浏览器是selenium+chrome的方式,除此之外也可以firefox,safari,ie等等,但是这些方案都有前提就是你的服务器上需要安装相应的浏览器,所以最初的时候,我尝试的是另一个浏览器引擎JBrowser(可被坑惨了....),下面我会相应介绍两种方案的不同,以及我所遇到的问题

selenium + jbrowser

jbrowser这个项目是github上的一个开源项目,基于javaFx技术实现网站爬取,无需在服务器上安装额外的浏览器,只需要安装带有javaFx的jdk8即可,不过据说在jdk10中javaFx被移除了,所以使用的话请注意一下
项目网址:https://github.com/MachinePublishers/jBrowserDriver

README中明确的介绍和使用案例,有三种模式,单机模式,独立节点模式和网格模式,个人理解大概就是单节点还是多节点的区别吧,我这里主要介绍单机模式

maven依赖

<dependency>
  <groupId>com.machinepublishers</groupId>
  <artifactId>jbrowserdriver</artifactId>
  <version>1.1.1</version>
</dependency>

<dependency>
   <groupId>org.seleniumhq.selenium</groupId>
   <artifactId>selenium-java</artifactId>
   <version>3.141.59</version>
</dependency>

jbrowser demo

public static void main(String[] args){

        String url = "https://www.baidu.com";
        
        // 创建jBrowser driver
        JBrowserDriver driver = new JBrowserDriver(Settings.builder()
                // 设置时区
                .timezone(Timezone.ASIA_SHANGHAI)
                // 设置1s连接超时
                .connectionReqTimeout(1000)
                // 设置socket超时时间2s
                .socketTimeout(2000)
                .build());
        
        // 获取网页内容
        driver.get(url);
        // 获取网页状态码
        System.out.println(driver.getStatusCode());
        // 获取网页代码
        System.out.println(driver.getPageSource());
        // 关闭jBrowser进程(与close方法有别,close是关闭标签页)
        driver.quit();
    }

问题一:linux环境缺少javafx环境

这段代码在window上是可以完美运行的,但是在Linux上就会报错

image.png
我在GitHub项目下边找到了这个issue,地址:https://github.com/MachinePublishers/jBrowserDriver/issues/344
大概的意思就是说,window环境的jdk8是带有jfx功能的,但是在linux环境是被移除的,linux环境更期望用户自己安装javaFx功能。
后来,我对比了一下window环境和linux环境的jdk,Linux缺少少了jfxrt.jar这个包
image.png
image.png
然后我在linux安装openjfx这个东西发现找不到,实在没办法,我就将jfxrt.jar这个包上传这个ext这个目录下,试试吧,看能不能生效。

问题二:Graphics Device initialization failed for : sw

又重新试了一下,报了一个新的问题:

image.png
同样,在github上也找到了issue,地址:https://github.com/MachinePublishers/jBrowserDriver/issues/87
大概的意思就是说,我的linux环境缺少了环境,文章有推荐安装xxx什么的,我跟着都装了一遍,发现没用,还是报这个错误,然后我觉得可能你把那个jar包拷贝进来根本没用,思考了一下绝地本质问题就是linux没有javaFx功能导致的,然后我寻寻觅觅终于找到的答案。

解决方案

参考链接:
https://blog.csdn.net/haoranhaoshi/article/details/102892216 https://blog.csdn.net/huangdeijia/article/details/79445046
通过这两篇文章,我得知linux环境的openjdk1.8是不带javaFx功能,如果你想要让系统中javaFx功能,有两种方法:一种是你直接安装oracelJDK8就好了;另一种是你要手动编译openJFX,我想图省事,选用了第一种方案,安装OracleJDK地址贴在下方,安装之后成功解决
安装OracleJDK8:https://blog.csdn.net/wen524/article/details/88104688

image.png
上边的是jbrowser自带的debug信息,不必在意,另外请各位注意一个问题:我访问https协议的网页时, 拿到的返回码是499,查了一下是说需要令牌,并且https协议的网页速度也很慢
image.png

总结

jbrowser无需安装额外的浏览器,但是需要本地jdk带有javaFx功能;Linux环境下的openJdk自身不带有javaFx模块,你可以通过自行编译openJFX或者更换为OracleJDK解决jbrowser无法启动的问题
另外,关于https协议的网页报499和https网页爬取速度优化的问题,我没有继续探究,感兴趣的同学可以研究一下,在评论中交流一下,jbrowser这个开源项目在网上的信息比较少,遇到问题的时候我在GitHub下边留言也没有人搭理我(可能我英文不太好/(ㄒoㄒ)/~~),但是确实不同于现在市面上的浏览器方案,根据需要进行选用吧。


selenium + chrome

这个方案算是网页爬取上比较常见方案,也是我最终选用的方案,我会分享一下我的使用过程。

前提条件

maven依赖

<dependency>
            <groupId>org.seleniumhq.selenium</groupId>
            <artifactId>selenium-java</artifactId>
            <version>3.141.59</version>
        </dependency>

chrome driver demo

 public static void main(String[] args) throws IOException {

        // 设置环境变量,指定chromedriver位置
        System.setProperty("webdriver.chrome.driver","d://chromedriver.exe");
        ChromeDriver driver = null;
        try {

            // 设置chrome浏览器的启动参数
            ChromeOptions options = new ChromeOptions();
            options.addArguments("--headless", "--disable-gpu", "--no-sandbox");
            Map<String, Object> prefs = new HashMap<>(2);
            prefs.put("pageLoadStrategy","eager");
            options.setCapability("prefs",prefs);

            // 构建chrome driver
            driver = new ChromeDriver(options);

            // 打开指定链接
            driver.get("https://mp.weixin.qq.com/s/jx0cygGoPsmASa5TUjtdfg");

            // 使用Jsoup解析网页内容
            Document document = Jsoup.parse(driver.getPageSource());

            // 关闭Jsoup的空格打印
            document.outputSettings().prettyPrint(false);

            // 将网页内容输出到文件中
            File file = new File("./chrome.html");
            FileWriter writer = new FileWriter(file);
            writer.write(document.toString());
            writer.flush();
            writer.close();
        } finally {

            // 关闭chrome driver 进程
            if (driver != null){
                driver.quit();
            }
        }
    }

chrome启动参数说明

options.setPageLoadStrategy(PageLoadStrategy.EAGER);

使用技巧


结果展示:成功

image.png image.png

项目不足及提醒

我最终选用了这个方案,对微信公众号文章进行解析和爬取,图片、部分视频需要进行特殊处理才能正常显示,有一部分的公众号文章样式有问题,部分视频是无法展示的,但是95%以上的文章在处理完之后是可以正常显示的(市面上有产品时支持那些有问题的文章的,但是我暂时并没有去完善)


文章到这里就结束了,欢迎各位在评论区进行交流和指正。

上一篇 下一篇

猜你喜欢

热点阅读