文档章节

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

黄亿华
 黄亿华
发布于 2013/07/26 16:48
字数 954
阅读 65644
收藏 100

一般的爬虫都是直接使用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也是可以的):

    <!-- lang: java --> System.getProperties().setProperty("webdriver.chrome.driver","/Users/yihua/Downloads/chromedriver");

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

<!-- lang: java -->
	 @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。

<!-- lang: java -->
    /**
 * 花瓣网抽取器。<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

© 著作权归作者所有

黄亿华

黄亿华

粉丝 2436
博文 131
码字总数 116344
作品 7
程序员
私信 提问
加载中

评论(34)

lijie33448
lijie33448
在一个页面中,需要通过往下滚滚动条来加载下一页的。
之所以要下拉滚动条来触发翻页,是因为翻页请求中有个参数是加密的,目前还无解。
这种情况如何代码如何写呢?
我能想到的是不使用SeleniumDownloader,而是自己来写操作WebDriver的代码。
t
tntlzhang
想请教您一下 我用webmagic+selenium 在main函数测试阶段都好用,但是部署进tomcat中时就会报错误,总说classNotfound,Debug跟了一下 是在new Chromedriver时报的错,what这是?
qsdfc
qsdfc
楼主 为啥我用
<!-- lang: java -->
   @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();
}
下在了页面 但是动态加载的数据还是下不上
z
zoujing123

引用来自“wantsor”的评论

博主您的webmagic我已经下载下来学习了源码并试用过了,感觉思路很清晰,解耦也非常到位!
这里想请教一个问题,用SeleniumDownloader的目的是为了解决网页中的AJAX加载部分的数据抓取,这里还有一种情况就是页面一些地方需要点击按钮才会AJAX渲染的,那部分数据用Selenium自带的方法应该能模拟点击去加载,但是封装到webmagic以后,无法调用Selenium自身的API,我如何去模拟点击等事件呢?
请问你当时怎么解决的?
y
youzhoutai

引用来自“wantsor”的评论

引用来自“thefun”的评论

引用来自“wantsor”的评论

引用来自“黄亿华”的评论

引用来自“wantsor”的评论

博主您的webmagic我已经下载下来学习了源码并试用过了,感觉思路很清晰,解耦也非常到位!
这里想请教一个问题,用SeleniumDownloader的目的是为了解决网页中的AJAX加载部分的数据抓取,这里还有一种情况就是页面一些地方需要点击按钮才会AJAX渲染的,那部分数据用Selenium自带的方法应该能模拟点击去加载,但是封装到webmagic以后,无法调用Selenium自身的API,我如何去模拟点击等事件呢?

很抱歉最近才看到!这个问题我也考虑过,但是实现起来还是满复杂的,所以就搁置了。我能想到有两种方案:一种是对Download做定制,直接将按钮逻辑写进去,这样的坏处就是每个站点都要实现一套Downloader。另一种是对PageProcessor做扩展,用它来描述浏览器行为,但是相应的,Downloader和PageProcessor的分隔就没有那么清晰了,因为PageProcessor对Downloader的结果起到反馈。我倒是比较喜欢第一种做法,简单清晰。

感谢博主的回复,我前段时间已经用第一种做法实现了一些比如点击按钮才ajax渲染出来的的数据抓取了,自己定制Downloader,还是非常好用,谢谢哈~

怎么做的?有时间介绍一下吗?

就是扩展Downloader ,在下载页面之前执行需要做的比如登陆,按钮点击ajax调用等操作,等ajax返回以后再下载页面
你好,我目前也碰到这样的情况,需要登录,点击才能出来,有对应的例子吗?想学习下,谢谢
天爵在线
天爵在线
chrome driver下载地址由:http://code.google.com/p/chromedriver/downloads/list
变更为:https://sites.google.com/a/chromium.org/chromedriver/
liaobo
liaobo
谢谢分享。我试了下调用webDriver.close() 关不掉chrome进程,得调用webDriver.quit()
Java_常
Java_常

引用来自“wantsor”的评论

引用来自“thefun”的评论

引用来自“wantsor”的评论

引用来自“黄亿华”的评论

引用来自“wantsor”的评论

博主您的webmagic我已经下载下来学习了源码并试用过了,感觉思路很清晰,解耦也非常到位!
这里想请教一个问题,用SeleniumDownloader的目的是为了解决网页中的AJAX加载部分的数据抓取,这里还有一种情况就是页面一些地方需要点击按钮才会AJAX渲染的,那部分数据用Selenium自带的方法应该能模拟点击去加载,但是封装到webmagic以后,无法调用Selenium自身的API,我如何去模拟点击等事件呢?

很抱歉最近才看到!这个问题我也考虑过,但是实现起来还是满复杂的,所以就搁置了。我能想到有两种方案:一种是对Download做定制,直接将按钮逻辑写进去,这样的坏处就是每个站点都要实现一套Downloader。另一种是对PageProcessor做扩展,用它来描述浏览器行为,但是相应的,Downloader和PageProcessor的分隔就没有那么清晰了,因为PageProcessor对Downloader的结果起到反馈。我倒是比较喜欢第一种做法,简单清晰。

感谢博主的回复,我前段时间已经用第一种做法实现了一些比如点击按钮才ajax渲染出来的的数据抓取了,自己定制Downloader,还是非常好用,谢谢哈~

怎么做的?有时间介绍一下吗?

就是扩展Downloader ,在下载页面之前执行需要做的比如登陆,按钮点击ajax调用等操作,等ajax返回以后再下载页面
能分享一下你ajax抓取的源码么? 邮箱:cxq@dasbank.coma
a
applejj
我想请问一个问题,selenium使用xpath来提取信息的时候,您是按照审查元素还是源码来做的?
Simeone
Simeone
抓新浪微博抓不到,只能抓到js
Python爬虫使用Selenium+PhantomJS抓取Ajax和动态HTML内容

1,引言 在Python网络爬虫内容提取器一文我们详细讲解了核心部件:可插拔的内容提取器类gsExtractor。本文记录了确定gsExtractor的技术路线过程中所做的编程实验。这是第二部分,第一部分实验...

fullerhua
2016/05/19
1K
1
使用 BeautifulSoup 和 Selenium 进行网页爬取

概述 HTML几乎是平铺直叙的。CSS是一个伟大的进步,它清晰地区分了页面的结构和外观。JavaScript添加一些魅力。道理上讲是这样的。现实世界还是有点不一样。 在本教程中,您将了解在浏览器中...

开源中国首席屌炸天
2018/08/28
2K
2
如何抓取Js动态生成数据且以滚动页面方式分页的网页

当我们在进行数据抓取的时候,如果目标网站是以Js的方式动态生成数据且以滚动页面的方式进行分页,那么我们该如何抓取呢? 如类似今日头条这样的网站:http://toutiao.com/ 我们可以使用Sel...

杨尚川
2015/10/13
4.3K
7
xautlx/nutch-ajax

Nutch AJAX page Fetch, Parse, Index Plugin 项目简介 基于Apache Nutch 2.3和Htmlunit, Selenium WebDriver等组件扩展,实现对于AJAX加载类型页面的完整页面内容抓取,以及特定数据项的解析...

xautlx
2015/02/26
0
0
Python网络爬虫(Xpath解析, lxml库, selenium)

安装: Windows :安装selenium python -m pip install selenium Anaconda Prompt下执行 : conda install selenium Linux/Mac OS: sudo pip3 install selenium Ubuntu :安装Scrapy框架 ####......

巴黎香榭
2018/11/10
0
0

没有更多内容

加载失败,请刷新页面

加载更多

最简单的获取相机拍照的图片

  import android.content.Intent;import android.graphics.Bitmap;import android.os.Bundle;import android.os.Environment;import android.provider.MediaStore;import andr......

MrLins
今天
5
0
说好不哭!数据可视化深度干货,前端开发下一个涨薪点在这里~

随着互联网在各行各业的影响不断深入,数据规模越来越大,各企业也越来越重视数据的价值。作为一家专业的数据智能公司,个推从消息推送服务起家,经过多年的持续耕耘,积累沉淀了海量数据,在...

个推
今天
8
0
第三方支付-返回与回调注意事项

不管是支付宝,微信,还是其它第三方支付,第四方支付,支付机构服务商只要涉及到钱的交易都要进行如下校验,全部成功了才视为成功订单 1.http请求是否成功 2.校验商户号 3.校验订单号及状态...

Shingfi
今天
4
0
简述Java内存分配和回收策略以及Minor GC 和 Major GC(Full GC)

内存分配: 1. 栈区:栈可分为Java虚拟机和本地方法栈 2. 堆区:堆被所有线程共享,在虚拟机启动时创建,是唯一的目的是存放对象实例,是gc的主要区域。通常可分为两个区块年轻代和年老代。更...

DustinChan
今天
6
0
Excel插入批注:可在批注插入文字、形状、图片

1.批注一直显示:审阅选项卡-------->勾选显示批注选项: 2.插入批注快捷键:Shift+F2 组合键 3.在批注中插入图片:鼠标右键点击批注框的小圆点【重点不可以在批注文本框内点击】----->调出批...

东方墨天
今天
6
1

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部