Java网络爬虫(十三)

Wesley13
• 阅读 663

先说点题外话吧,在我刚开始学习爬虫的时候,有一次一个学长给了我一个需求,让我把京东图书的相关信息抓取下来。恩,因为真的是刚开始学习爬虫,并且是用豆瓣练得手,抓取了大概500篇左右的影评吧,然后存放到了mysql中,当时觉得自己厉害的不行,于是轻松的接下了这个需求。。。

然后信心满满的开始干活。。首先查看网页源代码。。。???我需要的东西源代码里面没有!!!然后去问了学长。学长给我说,这是AJAX产生的数据,大概听完之后我就去查了资料。发现网上大片的资料都在阐述一个道理,对于动态页面,使用PhantomJs进行抓取,但是这样效率很低。作为一个优秀的程序员,当时看见效率很低这四个字,那在我心里是绝对不能被允许的,所以我就采用了抓包的方式,查看AJAX数据所在的URL,对于这个模拟浏览器的方法也就一直搁置到现在。

但是既然知道了这个东西,哪有不去学习的道理。所以我抽出了一点时间看了一下关于Java方面使用PhantomJs的资料,现在分享给大家。

对了,其实做网络爬虫,页面上90%的数据都可以使用抓包进行获取。所以我还是鼓励大家直接请求自己所需数据所在的URL。毕竟这种方式虽然方便,但是效率低下。


JS渲染与AJAX

在学习这个东西之前我们首先得了解什么是JS渲染、什么是AJAX以及为何这两种数据我们在网页源码里面获取不到。

依照我的理解,JS渲染与AJAX是一种相辅相成的关系,AJAX负责异步从服务器端获取数据,拿到数据后再使用JS进行渲染,最后呈现给用户。由于在Java中,HttpClient只能请求简单的静态页面,并不能请求到页面完全加载好后由JS调用相关代码产生的异步数据,所以我们不能直接通过HttpClient获取AJAX与JS渲染产生的数据。此时按上面所说的推荐大家直接进行网络抓包拿到AJAX数据所在的URL,或者使用本文所说的PhantomJs渲染引擎。


三大JS渲染引擎的比较

在网上进行资料查阅的时候,我们经常会因为五花八门的答案而不知所措,这时候一是要保持一颗平静的心情,二就要考虑搜索问题的相关姿势,必要的时候还需要科学上网。

先不说本文所说的JS渲染引擎,单说在Java爬虫中HTTP请求的库简直就可以用五花八门来形容,Java的原生HttpURLConnection类,HttpClient第三方库等等… …当然网络上提供了这么多方法,我们必须要进行选择,那么我们肯定想选择功能强大的,使用简单的类库。此时我们就应该在网上搜索对两个类库做相关比较的问题,来进行更好的选择,而不是随便挑一个学习就完事了,这样很有可能投入的学习成本与回报不成正比。

那么相信大家在准备使用JS引擎模拟浏览器的时候,在网上看过不仅有PhantomJs,还听说过Selenium,HtmlUnit这两个具有相同功能的东西。那么我们该如何选择呢?下图截选自其他网友的博客:

HtmlUnit

Selenium

PhantomJs

内置Rhinojs浏览器引擎,没有哪一款浏览器使用该内核,解析速度一般,解析JS/CSS差,无浏览器界面。

Seleninum + WebDriver = Selenium基于本地安装的浏览器,需打开浏览器,需要引用相应的WebDriver,正确配置webdriver的路径参数,在爬取大量js渲染页面时明显不合适。

神器,短小精悍,可本地化运行,也可作为服务端运行,基于webkit内核,性能及表现良好,完美解析绝大部分页面。

这也是我选择讲述PhantomJs的原因。

网上PhantomJs和Selenium还经常成对出现,原因是Selenium封装了PhantomJs的一部分功能,Selenium又提供了Python的接口模块,在Python语言中可以很好地去使用Selenium,间接地就可以使用PhantomJs。然而,是时候抛弃Selenium+PhantomJs了,原因之一此封装的接口很久没有更新了(没人维护了),原因之二Selenium只实现了一部分PhantomJs功能,且很不完善。


PhantomJs的使用

我使用的Ubuntu16.04的开发环境,至于PhantomJs + Selenium的环境部署,网络上有大篇资料,我就在这里给大家引入一个链接,也不详细说明了:ubuntu安装phantomjs

关于PhantomJs和Selenium的介绍我也就不再详说,大家直接百度就可以了。我们直接来看一下在Java中应该怎么使用PhantomJs~

如果你没有使用Maven的话,就在网上下载第三方jar包。我们所需要的Maven依赖如下:

<!-- https://mvnrepository.com/artifact/org.seleniumhq.selenium/selenium-java -->
<dependency>
      <groupId>org.seleniumhq.selenium</groupId>
      <artifactId>selenium-java</artifactId>
      <version>2.53.1</version>
    </dependency>

    <!-- https://mvnrepository.com/artifact/com.github.detro.ghostdriver/phantomjsdriver -->
    <dependency>
      <groupId>com.github.detro.ghostdriver</groupId>
      <artifactId>phantomjsdriver</artifactId>
      <version>1.1.0</version>
    </dependency>

接下来我们来看一下程序到底应该怎么写:

1.设置请求头

//设置必要参数
DesiredCapabilities dcaps = new DesiredCapabilities();
//ssl证书支持
dcaps.setCapability("acceptSslCerts", true);
//截屏支持
dcaps.setCapability("takesScreenshot", true);
//css搜索支持
dcaps.setCapability("cssSelectorsEnabled", true);
//js支持
dcaps.setJavascriptEnabled(true);
//驱动支持(第二参数表明的是你的phantomjs引擎所在的路径,使用whereis phantomjs可以查看)
dcaps.setCapability(PhantomJSDriverService.PHANTOMJS_EXECUTABLE_PATH_PROPERTY, "/usr/local/bin/phantomjs");

2.创建phantomjs浏览器对象

//创建无界面浏览器对象
PhantomJSDriver driver = new PhantomJSDriver(dcaps);

3.设置隐性等待

//设置隐性等待
driver.manage().timeouts().implicitlyWait(1, TimeUnit.SECONDS);

因为Load页面需要一段时间,如果页面还没加载完就查找元素,必然是查找不到的。最好的方式,就是设置一个默认等待时间,在查找页面元素的时候如果找不到就等待一段时间再找,直到超时。

以上三点是使用PhantomJs时需要注意的地方,大家可以看一下大致的整体程序:

import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.phantomjs.PhantomJSDriver;
import org.openqa.selenium.phantomjs.PhantomJSDriverService;
import org.openqa.selenium.remote.DesiredCapabilities;

import java.util.concurrent.TimeUnit;

/**
 * Created by hg_yi on 17-10-11.
 */
public class phantomjs {
   
        
    public static void main(String[] args) {
        //设置必要参数
        DesiredCapabilities dcaps = new DesiredCapabilities();
        //ssl证书支持
        dcaps.setCapability("acceptSslCerts", true);
        //截屏支持
        dcaps.setCapability("takesScreenshot", true);
        //css搜索支持
        dcaps.setCapability("cssSelectorsEnabled", true);
        //js支持
        dcaps.setJavascriptEnabled(true);
        //驱动支持(第二参数表明的是你的phantomjs引擎所在的路径)
        dcaps.setCapability(PhantomJSDriverService.PHANTOMJS_EXECUTABLE_PATH_PROPERTY,
                "/usr/bin/phantomjs-2.1.1-linux-x86_64/bin/phantomjs");
        //创建无界面浏览器对象
        PhantomJSDriver driver = new PhantomJSDriver(dcaps);

        //设置隐性等待(作用于全局)
        driver.manage().timeouts().implicitlyWait(1, TimeUnit.SECONDS);
        //打开页面
        driver.get("--------------------------------");
        //查找元素
        WebElement element = driver.findElement(By.id("img_valiCode"));

        System.out.println(element.getAttribute("src"));
    }
}

我成功的抓取到了网页源码里面没有的数据~

关于上面使用到的PhantomJSDriver类的相关API,大家直接看这篇资料即可,应该可以满足你的日常需求了:webdriver API中文版(WebDriver的API同样适用于PhantomJSDriver)。


PhantomJs的性能优化

我们都知道使用PhantomJs这种无头浏览器进行网页源码的抓取是非常费时的,所以当我们决定使用这个工具并且对抓取速度还有一定要求的时候,就需要掌握对PhantomJs进行性能优化的能力。

1.设置参数

Google,Baidu半天,还看了一点官方文档,还是找不到PhantomJs相关的Java调用API文档,好吧,先扔一篇Python的,以后找到这方面的内容再进行补充吧~~~

【phantomjs系列】Selenium+Phantomjs性能优化

题外话:其实对于Java网络爬虫。。。真想吐槽,建议刚开始准备学爬虫的人还是转战Python爬虫吧~~对于Java爬虫,只说一句话:学习难度大,学习周期长,投出与收入不成正比!!!

点赞
收藏
评论区
推荐文章
blmius blmius
3年前
MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1
文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s
皕杰报表之UUID
​在我们用皕杰报表工具设计填报报表时,如何在新增行里自动增加id呢?能新增整数排序id吗?目前可以在新增行里自动增加id,但只能用uuid函数增加UUID编码,不能新增整数排序id。uuid函数说明:获取一个UUID,可以在填报表中用来创建数据ID语法:uuid()或uuid(sep)参数说明:sep布尔值,生成的uuid中是否包含分隔符'',缺省为
待兔 待兔
3个月前
手写Java HashMap源码
HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程22
Jacquelyn38 Jacquelyn38
3年前
2020年前端实用代码段,为你的工作保驾护航
有空的时候,自己总结了几个代码段,在开发中也经常使用,谢谢。1、使用解构获取json数据let jsonData  id: 1,status: "OK",data: 'a', 'b';let  id, status, data: number   jsonData;console.log(id, status, number )
Easter79 Easter79
3年前
Twitter的分布式自增ID算法snowflake (Java版)
概述分布式系统中,有一些需要使用全局唯一ID的场景,这种时候为了防止ID冲突可以使用36位的UUID,但是UUID有一些缺点,首先他相对比较长,另外UUID一般是无序的。有些时候我们希望能使用一种简单一些的ID,并且希望ID能够按照时间有序生成。而twitter的snowflake解决了这种需求,最初Twitter把存储系统从MySQL迁移
Wesley13 Wesley13
3年前
mysql设置时区
mysql设置时区mysql\_query("SETtime\_zone'8:00'")ordie('时区设置失败,请联系管理员!');中国在东8区所以加8方法二:selectcount(user\_id)asdevice,CONVERT\_TZ(FROM\_UNIXTIME(reg\_time),'08:00','0
Wesley13 Wesley13
3年前
00:Java简单了解
浅谈Java之概述Java是SUN(StanfordUniversityNetwork),斯坦福大学网络公司)1995年推出的一门高级编程语言。Java是一种面向Internet的编程语言。随着Java技术在web方面的不断成熟,已经成为Web应用程序的首选开发语言。Java是简单易学,完全面向对象,安全可靠,与平台无关的编程语言。
Stella981 Stella981
3年前
Django中Admin中的一些参数配置
设置在列表中显示的字段,id为django模型默认的主键list_display('id','name','sex','profession','email','qq','phone','status','create_time')设置在列表可编辑字段list_editable
Wesley13 Wesley13
3年前
MySQL部分从库上面因为大量的临时表tmp_table造成慢查询
背景描述Time:20190124T00:08:14.70572408:00User@Host:@Id:Schema:sentrymetaLast_errno:0Killed:0Query_time:0.315758Lock_
Python进阶者 Python进阶者
9个月前
Excel中这日期老是出来00:00:00,怎么用Pandas把这个去除
大家好,我是皮皮。一、前言前几天在Python白银交流群【上海新年人】问了一个Pandas数据筛选的问题。问题如下:这日期老是出来00:00:00,怎么把这个去除。二、实现过程后来【论草莓如何成为冻干莓】给了一个思路和代码如下:pd.toexcel之前把这