一般的爬虫都是直接使用http协议,下载指定url的html内容,并对内容进行分析和抽取。在我写的爬虫框架webmagic里也使用了HttpClient来完成这样的任务。

但是有些页面是通过js以及ajax动态加载的,例如:花瓣网。这时如果我们直接分析原始页面的html,是得不到有效的信息的。当然,因为无论怎样动态加载,基础信息总归是包含在初始页面中得,所以我们可以用爬虫代码来模拟js代码,js读取页面元素值,我们也读取页面元素值;js发送ajax,我们就拼凑参数、发送ajax并解析返回的json。这样总归是能做的,但是比较麻烦,有没有比较省力的方法呢?比较好的方法大概是内嵌一个浏览器了。

Selenium是一个模拟浏览器,进行自动化测试的工具,它提供一组API可以与真实的浏览器内核交互。Selenium是跨语言的,有Java、C#、python等版本,并且支持多种浏览器,chrome、firefox以及IE都支持。

在Java项目中使用Selenium,需要做两件事:

在项目中引入Selenium的Java模块,以Maven为例:

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

下载对应的driver,以chrome为例:http://code.google.com/p/chromedriver/downloads/list

下载后,需要将driver的位置写到Java的环境变量里,例如我在mac下将其下载到了/Users/yihua/Downloads/chromedriver,则需要在程序里添加以下代码(当然在JVM参数里写-Dxxx=xxx也是可以的):
    System.getProperties().setProperty("webdriver.chrome.driver","/Users/yihua/Downloads/chromedriver");

Selenium的API挺简单的,核心是WebDriver,下面是动态渲染页面,并获取最终html的代码:

@Test
    public void testSelenium() {
        System.getProperties().setProperty("webdriver.chrome.driver", "/Users/yihua/Downloads/chromedriver");
        WebDriver webDriver = new ChromeDriver();
        webDriver.get("http://huaban.com/");
        WebElement webElement = webDriver.findElement(By.xpath("/html"));
        System.out.println(webElement.getAttribute("outerHTML"));
        webDriver.close();
    }

值得注意的是,每次new ChromeDriver(),Selenium都会建立一个Chrome进程,并使用一个随机端口在Java中与chrome进程进行通信来交互。由此可见有两个问题:

因此如果直接关闭Java程序,Chrome进程可能是无法关闭的。这里需要显示的调用webDriver.close()来关闭进程。

创建进程的开销还是比较大的,尽量对webDriver进行复用会比较好。可惜根据官方的文档,webDriver不是线程安全的,所以我们需要建立一个webDriver池来保存它们。不清楚Selenium是否有这样的接口,反正我是自己写了一个WebDriverPool来完成这个任务。

我已经将Selenium整合到了我的爬虫框架webmagic中,目前还是试用版本,有兴趣的可以一起学习交流。

最后说说效率问题。嵌入浏览器之后,不但要多花CPU去渲染页面,还要下载页面附加的资源。似乎单个webDriver中的静态资源是有缓存的,初始化之后,访问速度会加快。我试用ChromeDriver加载了100次花瓣的首页(http://huaban.com/),共耗时263秒,平均每个页面2.6秒。

为了测试效果,我写了一个花瓣抽取器,抽取花瓣网的分享图片url,用了咱自己的webmagic框架,集成了Selenium。

/**
 * 花瓣网抽取器。<br>
 * 使用Selenium做页面动态渲染。<br>
 */
public class HuabanProcessor implements PageProcessor {

private Site site;

@Override
    public void process(Page page) {
        page.addTargetRequests(page.getHtml().links().regex("http://huaban\\.com/.*").all());
        if (page.getUrl().toString().contains("pins")) {
            page.putField("img", page.getHtml().xpath("//div[@id='pin_img']/img/@src").toString());
        } else {
            page.getResultItems().setSkip(true);
        }
    }

@Override
    public Site getSite() {
        if (site == null) {
            site = Site.me().setDomain("huaban.com").addStartUrl("http://huaban.com/").setSleepTime(1000);
        }
        return site;
    }

public static void main(String[] args) {
        Spider.create(new HuabanProcessor()).thread(5)
                .scheduler(new RedisScheduler("localhost"))
                .pipeline(new FilePipeline("/data/webmagic/test/"))
                .downloader(new SeleniumDownloader("/Users/yihua/Downloads/chromedriver"))
                .run();
    }
}

sample地址:HuabanProcessor.java

Selenium来抓取动态加载的页面的更多相关文章

  1. 使用Selenium来抓取动态加载的页面

    原文:http://my.oschina.net/flashsword/blog/147334?p=1 一般的爬虫都是直接使用http协议,下载指定url的html内容,并对内容进行分析和抽取.在我写 ...

  2. Scrapy 框架 使用 selenium 爬取动态加载内容

    使用 selenium 爬取动态加载内容 开启中间件 DOWNLOADER_MIDDLEWARES = { 'wangyiPro.middlewares.WangyiproDownloaderMidd ...

  3. Python+Selenium爬取动态加载页面(2)

    注: 上一篇<Python+Selenium爬取动态加载页面(1)>讲了基本地如何获取动态页面的数据,这里再讲一个稍微复杂一点的数据获取全国水雨情网.数据的获取过程跟人手动获取过程类似,所 ...

  4. Python+Selenium爬取动态加载页面(1)

    注: 最近有一小任务,需要收集水质和水雨信息,找了两个网站:国家地表水水质自动监测实时数据发布系统和全国水雨情网.由于这两个网站的数据都是动态加载出来的,所以我用了Selenium来完成我的数据获取. ...

  5. scrapy和selenium结合抓取动态网页

    1.安装python (我用的是2.7版本的) 2.安装scrapy:   详情请参考 http://blog.csdn.net/wukaibo1986/article/details/8167590 ...

  6. 微信小程序web-view之动态加载html页面

    官方推出的web-view方便了很多开发人员. 我们在做的时候,经常会想到写一个小程序的page然后通过动态加载web-view的形式来完成其他功能页面的开发. 之前研究web-view的时候发现网上 ...

  7. 在aspx页动态加载ascx页面内容,给GridView控件绑定数据

    在aspx页动态加载ascx页面内容 //加载ascx页面内容Control c1 = this.Page.LoadControl("WebUserControl1.ascx"); ...

  8. 爬虫再探实战(三)———爬取动态加载页面——selenium

    自学python爬虫也快半年了,在目前看来,我面临着三个待解决的爬虫技术方面的问题:动态加载,多线程并发抓取,模拟登陆.目前正在不断学习相关知识.下面简单写一下用selenium处理动态加载页面相关的 ...

  9. 爬虫再探实战(四)———爬取动态加载页面——请求json

    还是上次的那个网站,就是它.现在尝试用另一种办法——直接请求json文件,来获取要抓取的信息. 第一步,检查元素,看图如下: 过滤出JS文件,并找出包含要抓取信息的js文件,之后就是构造request ...

随机推荐

  1. HDOJ 5071 Chat 模拟

    大模拟: 1>saygoodbye要先对 always on top 的人说 2>对没有说过话的不要说good bye 3>用long long Chat Time Limit: 2 ...

  2. css概述

    前言 1.CSS    cascading   stylesheet  级联样式表 ,外观显示(页面内容显示的方式).CSS文档以.css作为后缀    2.w3c推荐页面文件定义      数据和结 ...

  3. Android imageView图片按比例缩放

    android:scaleType可控制图片的缩放方式,示例代码如下: <ImageView android:id="@+id/img" android:src=" ...

  4. PHP - 日期与时间

    第10章 日期与时间 学习要点: 1.PHP日期和时间库 使用PHP编程时,与你遇到的大多数其他类型的数据相比,日期和时间有很大不同.因为日期和时间没有明确的结构,并且日期的计算和表示也很麻烦.在PH ...

  5. 《火球——UML大战需求分析》(第1章 大话UML)——1.5 小结和练习

    说明: <火球——UML大战需求分析>是我撰写的一本关于需求分析及UML方面的书,我将会在CSDN上为大家分享前面几章的内容,总字数在几万以上,图片有数十张.欢迎你按文章的序号顺序阅读,谢 ...

  6. C#加密与解密

    密码加密之类的用处,直接复制黏贴,可用 1.加密的代码: /// <summary> /// DEC 加密过程 /// </summary> /// <param nam ...

  7. Java内部类——成员内部类

    成员内部类的意思就是,一个外层类里面包含着一个非static的class,举例如下: class OuterClass { //变量,函数定义... class InnerClass { //变量,函 ...

  8. html网页中 点击按钮页面跳转

    在html页面中 实现点击按钮页面跳转.语句如下: <input type="button" value="跳转" onClick="windo ...

  9. 国内使用Google Maps JavaScript API

    <!DOCTYPE html> <html> <head> <meta name="viewport" content="ini ...

  10. android用shape画虚线,怎么也不显示

     一直以为android的shape能画直线.虚线.矩形,圆形等.画直线也就算了.用一个view设一下高度和颜色,就能够出来一条直线了.所以说这个对我来说常常不用,圆形是能够,看看我应用里的消息提 ...