JAVA中使用selenium + Chrome驱动程序抓取页面内容时,碰到的一些问题及思考整理

作者: admin 分类: Selenium,应用技巧 发布时间: 2019-08-23 18:30  阅读: 234 views

背景说明

由于目标页面是vue结构写的,所以无法用urlConnection获取获取连接后,使用Document/Jsoup等解析。页面元素是通过js动态渲染出来的。后来尝试通过webMagic框架,配合selenium\Chrome等进行基础数据的抓取及整理。

处理过程

  1. 设计标记型表结构,对抓取的状态、数据等做记录
  2. 配置selenium相关环境、工具
  3. 分析页面的dom元素,编码解析html过程
  4. 对webmagic框架的processor、pipeline层进行编码整合、调试
  5. 对已获取的有效数据进行入库操作

步骤剖析

1. 标记型表结构设计、样表如下


CREATE TABLE `data` ( `id` int(11) NOT NULL AUTO_INCREMENT, `name` varchar(255) NOT NULL COMMENT 'dataname', `type` tinyint(4) DEFAULT NULL COMMENT '类型', `xx` int(11) DEFAULT '0' COMMENT '修订', `xx` ... PRIMARY KEY (`id`) ) ENGINE=InnoDB AUTO_INCREMENT=0 DEFAULT CHARSET=utf8 COMMENT='数据标记'

做这个表的初衷是为了对抓取数据做个基本的留存,提取过程中的核心数据作为后期的统计、校验处理。因为我本身对于抓取数据的结果是不信任的【可能由于网络中断、页面无法正常打开、页面打开后布局错乱、并发情况下浏览器窗口意外关闭、页面改版元素增改等各种情况导致无法获取目标数据】。所以有type字段,记录如下流程状态

爬取 -> 打开 -> 操作 -> 解析 -> 入库 -> 爬取

其中

1.爬取 是指抓取根路径或者获取到页面上的目标url路径;
2.打开 是指通过Chrome driver打开url的过程;
3.操作 是指需要通过selenium模拟点击、跳转、输入等操作;
4.解析 是指到达目标页面后对html元素进行解析并获取有效内容
5.入库 将内容进行持久化操作
6.爬取 获取下一级链接,循环此操作

这里最容易发生不可控的步骤是2、3、4。可能由于各种原因产生各种问题。所以要记录下当前数据的执行状态。当然,如果数据对你来说是可丢失、可重复、信任度要求不高的话,你完全可以忽略部分数据,以量取胜。

2. selenium相关环境配置

先引入jar,下载浏览器对应驱动并配置

<!-- selenium处理 -->
<dependency>
    <groupId>org.seleniumhq.selenium</groupId>
    <artifactId>selenium-java</artifactId>
    <version>3.9.1</version>
</dependency>
<dependency>
    <groupId>org.seleniumhq.selenium</groupId>
    <artifactId>selenium-server</artifactId>
    <version>3.9.1</version>
    <exclusions>
        <exclusion>
            <groupId>org.yaml</groupId>
            <artifactId>snakeyaml</artifactId>
        </exclusion>
    </exclusions>
</dependency>

以上是pom配置,以下是驱动变量设置,

static
{
    System.getProperties().setProperty("webdriver.chrome.driver", "/Users/chenhailong/Downloads/tools/nessarytool/chromedriver");
}

运行以下编码时,能正常打开浏览器说明配置正常

WebDriver w = new ChromeDriver();
w.get("https://www.deathearth.com");


# 控制台会输出以下信息
Starting ChromeDriver 2.38.552518 (183d19265345f54ce39cbb94cf81ba5f15905011) on port 33558
Only local connections are allowed.
八月 23, 2019 5:02:46 下午 org.openqa.selenium.remote.ProtocolHandshake createSession
信息: Detected dialect: OSS

这个环境最容易出现问题的是,浏览器版本和驱动版本不一致,导致程序无法打开浏览器。或者浏览器自动升级产生的影响。仔细配置就好。

3. 解析页面上的html元素

a. 这里最头疼的是页面改版问题,本来刚写好一套匹配规则进行处理。但是目标网站经常改变布局、按钮功能效果调整。所以,这里基本要随着目标网站的变动进行变动。没办法。

b. 其次,是解析效率的问题。碰到过两种情况,一种是在抓取长文本类型(超过10w字节)的文章内容时,通过父元素的text()方法读取,会对内容做截断处理。导致信息不完整。这里通过循环子标签进行处理。如下

<div id="content">
    <span></span>
    <span></span>
    <span></span>
    ...
    ...
    <span></span>
</div>


修改前: w.findElements(By.id("content")).getText()

修改后:List<WebElement> ls = w.findElements(By.xpath("div"))

        for(int i = 0;i<ls.size();i++){
            sb += ls.get(i).getText();
        }

另一种是,在遇到页面元素结构较为复杂时,不同的解析方式会有不同的处理效率。
如下:

<div>
    <div>
        <a>
            <span>
                <div>
                    <div id="abc">
                        xxx
                    </div>
                </div>
            </span>
        </a>
        <a>
        </a>
    </div>
</div>

# 利用 xpath的常规解析
w.findElements(By.xpath("div/div/a[1]/span/div/div")).getText()

# 根据id解析
w.findElements(By.xpath(".//div[@id="abc"]")).getText() 
或
w.findElements(By.id("abc")).getText() 

由于浏览器控制台提供了右键获取xpath路径功能,所以经常直接拿来使用,但是层级很多时,解析效率会有点慢。所以不如直接精确定位元素查找的快。

c. 最后,是抓取策略的问题。需要根据页面结构、数据需求等多方面结合思考。

比如我的规则,有256个类目,循环处理每一个类目。每个类目会依次打开目标页面,找到输入框进行键入操作,确认后会出现类目相关列表。然后将列表中的每条信息进行解析处理。(就像在百度随便输入一个关键词,将返回列表的前3页数据入库)。

第一次处理,共700条数据完全入库单线程大概走了3个小时。(多线程会导致浏览器意外退出的情况。由于要模拟人类操作,对于键入文字的速度、页面的点击、页面的有效加载等做了处理【防止触发反爬机制】)。

在对模拟时间和程序代码的基本调整后,时间缩短为2小时。但是过程中,还是丢失了一些数据或者发生了些异常的情况。主要表现在每次驱动浏览器打开目标页面地址时,加载时间会长触发连接超时,这样的话就无法获取数据。

再次进行优化,将目标页面连接的获取和页面正文的获取分开。先一次性获取所有页面的url后。通过驱动一次浏览器,循环页面后进行跳转等处理。避免了浏览器程序的频繁开启、退出。这样时间又缩短了一半,且没有出现页面超时类的异常情况。保证了数据的准确度。

注: 爬取一般来说是一种资源分享、扩散的方式【也可以是盗窃机密、非法买卖的行径】,反爬是一种数据保护机制。双方的交战常常发生在无形之中。反爬中的封ip、封账号属于简单的无奈之举。滑动验证码通过大数据分析人的操作轨迹,通过机器模拟已经很难正常通过。可以简单看下之前碰到的类似问题,点这里。还碰到过一个比较好的机制,在抓取过程中,目标网站释放了一个伪装好的链接,让爬虫认为是有效链接,从而进入无限循环的抓取过程中。根据一些爬虫框架的功能设计,可能会吃光爬虫服务器的内存,造成假死状态。

4.框架编码整合

这里主要用的是java语言的webMagic,编写过程中根据自己的要求进行整理,达到使用简易、方便扩展的要求即可。考验自己的设计功底了。

之前用python做过一些简单的尝试。虽然效率好但毕竟不是自己的主战场。
Scrapy根据XPATH解析页面内容、下载为json格式文件、抓取列表页等的简单示例。还是用java做一些个性化的处理比较顺手一点,哈哈。

5.数据入库

现在数据库种类那么多,可以随便放到任何一个去。但是怎么进行有效的利用和分析就不是那么简单的事情了。可以简单看下这个
《大数据时代》/bigdata电子书下载以及阅读分析,不是说教你怎么分析数据,而是告诉你利用数据可以做很多事情。


   原创文章,转载请标明本文链接: JAVA中使用selenium + Chrome驱动程序抓取页面内容时,碰到的一些问题及思考整理

如果觉得我的文章对您有用,请随意打赏。您的支持将鼓励我继续创作!

发表评论

电子邮件地址不会被公开。 必填项已用*标注

更多阅读