htmlunit抓取动态网页(2019独角兽企业重金招聘Python工程师标准(gt;gt))

优采云 发布时间: 2022-01-22 01:18

  htmlunit抓取动态网页(2019独角兽企业重金招聘Python工程师标准(gt;gt))

  2019独角兽企业招聘Python工程师标准>>>

  

  最近在做一个项目的时候,有个需求:从一个网页抓取数据,需求是先抓取整个网页的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,使用这些驱动的原理是一样的,先打开浏览器(这需要时间),然后加载url并完成动态解析,然后就可以得到通过page.asXml()完成html页面,其中HtmlUnitDriver模拟无接口浏览器,java有引擎rhino执行js,HtmlUnitDriver使用rhino解析js。它将启动一个带有界面的浏览器,因此 HtmlUnitDriver 比前面三个要快。不管是什么驱动,都难免解析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());

  我根据这个想法尝试了以下,是的,它确实有效。但问题不就在那里吗?如何确定等待时间?类似于数据挖掘中确定阈值的经验方法?,或尽可能长。我觉得这些都不是很好的解决方案,时间成本也比较高。本来以为驱动解析js后应该可以捕获状态,于是就去找找找,但是根本没有这个方法,所以说WebDriver的设计者为什么不走一步forward,这样我们就可以程序获取驱动解析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页面,而不是像Thread.sleep()这种不确定的代码,需要在WebDriver中使用才能获取可能完成的代码。需要说明一点:phantomjs端的js代码一定不能有语法错误,否则如果js代码编译不同,java端会一直等待,不会抛出异常。再者,使用phantomjs.exe时,java端每次都要开启一个phantomjs进程,耗费大量时间。但至少结果是稳定的。当然,最后我还没有使用phantomjs。我直接下载了自己需要的数据,并没有抓取整个页面,主要是速度问题(其实我对phantomjs不熟悉,所以不敢用,慎用)。

  折腾了几天,虽然没有解决我的问题,但还是收获了很多知识。后期的工作就是熟悉phantomjs,看看能不能提高速度。如果能突破限速,以后爬网的时候就得心应手了。此外,Nutch 是框架。我很佩服我的伙伴们在使用它时的便利。后期有必要研究如何优化Nutch on Hadoop的爬取速度。此外,Nutch 原有的功能不会爬行。动态生成的页面内容,不过可以结合Nutch和WebDirver,说不定爬取的结果是稳定的,哈哈,这些只是想法,但是不试试怎么知道呢?

  如果园丁对使用WebDriver辅助爬虫得到的结果的稳定性有什么想说的,不客气,因为我确实没有找到相关资料稳定爬取结果。

0 个评论

要回复文章请先登录注册


官方客服QQ群

微信人工客服

QQ人工客服


线