java抓取动态生成的网页--吐槽

最近在做项目的时候有一个需求:从网页面抓取数据,要求是首先抓取整个网页的html源码(后期更新要使用到)。刚开始一看这个简单,然后就稀里哗啦的敲起了代码(在这之前使用过Hadoop平台的分布式爬虫框架Nutch,使用起来是很方便,但是最后因为速度的原因放弃了,但生成的统计信息在后来的抓取中使用到了),很快holder.html和finance.html页面成功下载完成,然后解析完holder.html页面之后再解析finance.html,然后很沮丧的发现在这个页面中我需要的数据并没有在html源码中,再去浏览器查看源码果然是这样的,在源码中确实没有我需要的数据,看来不是我程序写错了,接下来让人身心疲惫的事情来了---获取包含动态内容的html页面。

  在所谓的中国最强搜索引擎---百度上面行走了好长的时间,发现大部分的人都在将使用WebDriver和HttpUnit(其实前者已经包含了后者),这个高兴,终于找到了解决办法。怀着万分的激动使用WebDriver,我要想骂人了。

  下面是关于WebDriver的吐槽

  WebDriver是一个测试框架,原本设计的时候就不是用来服务爬虫的,但是我想说的是:八字就差一撇了,你就不能多往前做一步吗?为什么网上还有那么多的人推荐WebDriver呢?我想这些人没有从实际出发,甚至还有的人狂言WebDriver可以解析完成后的页面返回给想要爬去整个页面的人(包含动态生成的内容),对,WebDriver可以完成这个任务,但是看到作者写的代码,我想说的是:哥们,你的代码局限性太大了,解析自己写的js代码,而且js代码简单,这样WebDriver当然是毫无压力的完成任务。WebDriver在解析动态内容是要看js代码的复杂性和多样性。

  什么是复杂性?

    先贴一段代码

WebDriver driver = newInternetExplorerDriver ();
HtmlPage page = driver.get(url);
System.out.println(page.asXml());

这一段代码的意思是相信大家都看懂,上面使用的IE内核,当然还有FirefoxDriver, ChromeDriver,HtmlUnitDriver,这些driver的使用原理都是一样的,先开启浏览器(这个要时间的),然后加载url并完成动态解析,然后通过page.asXml()就可以得到完成的html页面,其中HtmlUnitDriver模拟无界面浏览器,java中有执行js的引擎rhino,HtmlUnitDriver使用的就是rhino来解析js的,由于不会去启动有界面的浏览器,所以HtmlUnitDriver的速度比前面的三者都快。无论是什么Driver,避免不了的是解析js,这是需要时间的,而且不用的内核对js的支持程序又是不同,比如说HtmlUnitDriver对于带有滚动的js代码支持很差,在执行时会报错(亲自体验了)。js代码的复杂的意思就是:对于不同的内核他们支持的js是不完全相同的,这个应该根据具体情况来定,鄙人好久没有研究js了,所以关于各内核对js的支持就不说了。

  什么是多样性

  前面说了,浏览器解析js是需要时间的。对于只嵌入少数的js代码的页面来说,通过page.asXml()来获取完整的页面时没有问题的。但是对于嵌入比较多的js代码的页面,解析js是需要很多时间的(对于jvm来说),那么此时通过page.asXml()来获取的页面中大多数时候是不包含有动态生成的内容的。问题就来了,这样的话为什么还说WebDriver可以获得包含有动态内容的html页面呢?网上有人说在driver.get(url)之后需要是当前线程等待一下才能获取完成的页面,也就是类似于下面的形式

  

WebDriver driver = new InternetExplorerDriver();
HtmlPage page = dirver.get(url);
Thread.sleep(2000);
System.output.println(page.asXml());

我按照这个想法去尝试以下,呀,真的是可以。但是问题不正好也摆在那里了么?怎么样去确定等待时间?类似于数据挖掘中确定阀值时的凭经验的方法?,还是尽可能的是时间长一点。我觉得这些都不是很好的办法,时间代价比较大。我就想在driver应该可以捕获解析js完成后的状态,于是我去找啊,找啊,可是根本就没有这个方法,所以我说WebDriver的设计者为什么不再往前走一步,让我们可以在程序中获取到driver解析js完成后的状态,这样的话就不用使用Thread.sleep(2000)这样的不确定性代码了,可惜的是怎么也找不到,真是让我心痛了一场。FirefoxDriver, ChromeDriver,HtmlUnitDriver也有同样的问题,可以说使用WebDriver来辅助爬去动态生成的网页所得到的结果是很不稳定的。这一点我是深有体会,使用IEDriver的时候,同一个页面两次爬取的结果会出现不一样,而且甚至有时候IE直接挂掉,你说这样的东西你们敢用在爬虫程序中吗?我是不敢的。

  另外还有就是有人推荐使用HttpUnit,其实WebDirver中HtmlUnitDriver在内部使用的就是httpUnit,所以使用HttpUnit也会遇到同样的问题,我也做了实验,确实是这样。通过Thread.sleep(2000)来等待js的解析完成,我觉得不可取的办法。不确定性太大了,特别是在大型的抓取工作中。

  总结一下,WebDriver是为测试而设计的框架,虽然按照其原理理论上可以用来辅助爬虫获取包含有动态内容的html页面,但是在实际的应用中是不取的,不确定性太大了,稳定性太差,速度太慢,我们还是让框架各尽其值吧,不要折煞了他们的优点。

  我的工作没有完成,所以继续去网上需找办法,这次找到了一个稳定的,确定性高的辅助工具---phantomjs,目前我还不完全了解这个东西。但是目前已经用它来实现了我想要的功能。在java中通过runtime.exec(arg)来调用phantomjs得到解析js后的页面。我还是把代码贴出来吧

  phantomjs端要执行的代码

system = require(‘system‘)   
address = system.args[1];//获得命令行第二个参数 接下来会用到   //console.log(‘Loading a web page‘);   var page = require(‘webpage‘).create();   
var url = address;   
//console.log(url);   page.open(url, function (status) {   
    //Page is loaded!   
    if (status !== ‘success‘) {   
        console.log(‘Unable to post!‘);   
    } else {    
    //此处的打印,是将结果一流的形式output到java中,java通过InputStream可以获取该输出内容        console.log(page.content);   
    }      
    phantom.exit();   
});

java端执行的代码

  

public void getParseredHtml(){
  String url = "www.bai.com";
  Runtime runtime = Runtime.getRuntime();
  runtime.exec("F:/phantomjs/phantomjs/phantomjs.exe F:/js/parser.js "+url);
  InputStream in = runtime.getInputStream();  //后面的代码省略,得到了InputStream就好说了     }

这样的话在java端就可以获得解析完成后的html页面了,而不是像WebDriver中需要使用Thread.sleep()这样的不确定性的代码来获取可能完成的代码。有一点需要说明:在phantomjs端的js代码千万不要要语法错误,否则js代码编译不同的话,java端就一直等待着,并不会抛异常。再就是由于在使用phantomjs.exe的时候,java端每次都要去开启一个phantomjs进程,时间上消耗还是比较大的。但是最起码来说结果是稳定的。当然最后我还没有使用phantomjs,我直接download需要的数据,并没有去抓取整个完整的页面,主要是速度方面的问题(其实,我不敢用是因为phantomjs不熟悉,所以我慎用)。

  折腾了几天,虽然没有解决我的问题,但是见识长了不少,后期的工作是熟悉phantomjs,看能不能再速度方面提升,要是能打破速度的框框,以后再爬去网页的时候就得心应手了,再者就是Nutch这个框架,我佩服着哥们在使用的时候方便性,所有后期很有必要研究下如何优化Nutch在Hadoop上的抓取速度,另外,Nutch原始的功能中也不会抓取动态生成的页面内容,但是可以使用Nutch和WebDirver结合,说不定抓取的结果稳定了,哈哈,这些只是构想,但是不尝试怎么知道呢?

  如果园友对于使用WebDriver辅助爬虫所得到的结果的稳定性方面有要说的,欢迎各位啊,因为我确实没有找相关的资料来稳定爬去结果。

时间: 2024-10-13 08:33:03

java抓取动态生成的网页--吐槽的相关文章

java抓取动态生成的网页

最近在做项目的时候有一个需求:从网页面抓取数据,要求是首先抓取整个网页的html源码(后期更新要使用到).刚开始一看这个简单,然后就稀里哗啦的敲起了代码(在这之前使用过Hadoop平台的分布式爬虫框架Nutch,使用起来是很方便,但是最后因为速度的原因放弃了,但生成的统计信息在后来的抓取中使用到了),很快holder.html和finance.html页面成功下载完成,然后解析完holder.html页面之后再解析finance.html,然后很沮丧的发现在这个页面中我需要的数据并没有在html

怎样用java编程抓取动态生成的网页

最近在做项目的时候有一个需求:从网页面抓取数据,要求是首先抓取整个网页的html源码(后期更新要使用到).刚开始一看这个简单,然后就稀里哗啦的敲起了代码(在这之前使用过Hadoop平台的分布式爬虫框架Nutch,使用起来是很方便,但是最后因为速度的原因放弃了,但生成的统计信息在后来的抓取中使用到了),很快holder.html和finance.html页面成功下载完成,然后解析完holder.html页面之后再解析finance.html,然后很沮丧的发现在这个页面中我需要的数据并没有在html

python爬取动态生成的网页——以百度手机助手为例

在爬取js动态生成的页面时,直接打开页面是获取不到内容的,比如,我在爬取百度手机助手的应用时,就遇到了这样一个问题.在搜索旅游类应用时,返回数据有几页的内容,但是不管你翻到第几页,查看源代码发现都一样,都是第一页内容的源代码.分析原因我觉得可能是这样的:假设百度应用一页内容有八个应用,你把查询提交后他把内容的前8个生成一个html,然后再你翻页时,通过js,ajax等方式替换原来的8个应用,比如你选择第五页时,把返回应用列表的33-40个应用替换原来的1-8的内容.(应该是ajax或者其他表单提

scrapy和selenium结合抓取动态网页

1.安装python (我用的是2.7版本的) 2.安装scrapy:   详情请参考 http://blog.csdn.net/wukaibo1986/article/details/8167590 (提示,能下载源码安装的就避免用pip install **) 安装过程中遇到python扩展问题”unable to find vcvarsall.bat“的解决办法: http://blog.csdn.net/ren911/article/details/6448696 3.安装seleniu

盘点用Java抓取HTTP服务器和FTP服务器的网页数据或图片等数据的实用技巧

摘要 在信息时代,常常需要通过编程的方式来灵活整理各种网络数据.首先涉及到如何方便准确地抓取网络数据.下面盘点用Java程序来访问HTTP服务器以及FTP服务器的各种实用技巧.主要介绍了Java Socket.java.net.URL类.Selenuim软件包.Apache HttpClients.Apache FTPClient来和HTTP服务器以及FTP服务器通信的方法以及其优缺点. 参考资料 (1)本文参考了笔者所写的<Java网络编程核心技术详解>,2020年上半年出版. (2)Jav

使用scrapy-selenium, chrome-headless抓取动态网页

????在使用scrapy抓取网页时, 如果遇到使用js动态渲染的页面, 将无法提取到在浏览器中看到的内容. 针对这个问题scrapy官方给出的方案是scrapy-selenium, 这是一个把selenium集成到scrapy的开源项目, 它使用selenium抓取已经渲染好(js代码已经执行完成)的动态网页. ????事实上selenium自己也没有渲染动态网页的能力,它还是得依赖浏览器, 用浏览器作为动态网页的渲染引擎. 目前主流的浏览器都能以headless模式运行, 即没有图形界面只有

java 抓取网页图片

? 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86

java抓取网页数据,登录之后抓取数据。

最近做了一个从网络上抓取数据的一个小程序.主要关于信贷方面,收集的一些黑名单网站,从该网站上抓取到自己系统中. 也找了一些资料,觉得没有一个很好的,全面的例子.因此在这里做个笔记提醒自己. 首先需要一个jsoup的jar包,我用的1.6.0..下载地址为:http://pan.baidu.com/s/1mgqOuHa 1,获取网页内容(核心代码,技术有限没封装). 2,登录之后抓取网页数据(如何在请求中携带cookie). 3,获取网站的ajax请求方法(返回json). 以上这三点我就用一个类

java抓取12306火车余票信息

最近在弄一个微信的公众帐号,涉及到火车票查询,之前用的网上找到的一个接口,但只能查到火车时刻表,12306又没有提供专门的查票的接口.今天突然想起自己直接去12306上查询,抓取查询返回的数据包,这样就可以得到火车票的信息.这里就随笔记一下获取12306余票的过程. 首先,我用firefox浏览器上12306查询余票.打开firefox的Web控制台,选上网络中的"记录请求和响应主体" 然后输入地址日期信息之后点击网页上的查询按钮,就能在Web控制台下看到网页请求的地址了: 就是图片中