htmlunit抓取动态网页(HtmlUnit在多线程环境下怎么使用才能避免网页抓取失败的问题)

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

  htmlunit抓取动态网页(HtmlUnit在多线程环境下怎么使用才能避免网页抓取失败的问题)

  今天在网上看到一个问题,问如何在多线程环境下使用HtmlUnit,避免网页爬取失败。下面,根据我自己的经验,我将讨论解决这个问题的方法。

  这个问题的原因其实很简单。例如,线程 A 正在使用 WebClient 对象来爬取网页。在整个爬取过程结束之前,当前线程被CPU挂起,所以线程B被激活,然后B使用A正在使用的WebClient对象去抓取其他网页,那么这个时候,WebCLient对象就会清除刚刚完成的工作留下的数据,以此类推。共享 WebClient 的线程越多,问题发生的频率就越高。页面丢失的概率也更高。但其实这个问题并不难解决,它的解决方案也有广泛的适用性:无论是任何对象,在多线程环境下遇到资源共享问题时,通常有两种解决方案,

  早在JDK1.2版本就提供的java.lang.ThreadLocal和ThreadLocal,为解决多线程程序的并发问题提供了新思路。使用这个工具类,你可以编写精美的多线程程序。这个想法是为每个线程保留变量的本地副本,以确保变量不与其他线程共享 - 一种保守但有效的方法。本文的目的不是介绍ThreadLocal的用法(具体用法请参考百度百科),而是想用ThreadLocal解决多线程环境下HtmlUnit的WebClient对象的共享问题。

  请看如何使用 ThreadLocal 对象来解决上述问题:

  package cn.ysh.studio.crawler.htmlunit;import com.gargoylesoftware.htmlunit.BrowserVersion;import com.gargoylesoftware.htmlunit.WebClient;/** * * @author Shenghany * @date 2013-5-27 */publicclassThreadLocalClientFactory{//单例工厂模式privatefinalstaticThreadLocalClientFactory instance =newThreadLocalClientFactory();//线程的本地实例存储器,用于存储WebClient实例privateThreadLocal clientThreadLocal;/** * 构造方法,初始时线程的本地变量存储器 */publicThreadLocalClientFactory(){clientThreadLocal =newThreadLocal();}/** * 获取工厂实例 * @return 工厂实例 */publicstaticThreadLocalClientFactory getInstance(){return instance;}/** * 获取一个模拟FireFox3.6版本的WebClient实例 * @return 模拟FireFox3.6版本的WebClient实例 */publicWebClient getClient(){WebClient client =null;/** * 如果当前线程已有WebClient实例,则直接返回该实例 * 否则重新创建一个WebClient实例并存储于当前线程的本地变量存储器 */if((client = clientThreadLocal.get())==null){client =newWebClient(BrowserVersion.FIREFOX_3_6);client.setCssEnabled(false);client.setJavaScriptEnabled(false);clientThreadLocal.set(client);System.out.println("为线程 [ "+Thread.currentThread().getName()+" ] 创建新的WebClient实例!");}else{System.out.println("线程 [ "+Thread.currentThread().getName()+" ] 已有WebClient实例,直接使用. . .");}return client;}}

  测试代码:

<p>package cn.ysh.studio.crawler.htmlunit;import com.gargoylesoftware.htmlunit.WebClient;import com.gargoylesoftware.htmlunit.html.HtmlPage;/** * * @author Shenghany * @date 2013-5-27 */publicclassThreadLocalHtmlUnitTester{/** * 获取目标页面,并打印网页标题 * @param url 目标页面地址 */publicstaticvoid getPage(String url){//从工厂中获取一个WebClient实例WebClient client =ThreadLocalClientFactory.getInstance().getClient();try{//抓取网页HtmlPage page =(HtmlPage)client.getPage(url);//打印当前线程名称及网页标题System.out.println(Thread.currentThread().getName()+" [ "+ url +" ] : "+ page.getTitleText());}catch(Exception e){e.printStackTrace();}}/** * 测试程序执行入口 * @param s */publicstaticvoid main(String[] s){//文章编号int postId =50;//目标网页的部分内容String http ="http://www.yshjava.cn/post/4";/** * 共16篇文章,每个线程抓取两篇,共计将产生8个线程 */for(int i = postId; i

0 个评论

要回复文章请先登录注册


官方客服QQ群

微信人工客服

QQ人工客服


线