htmlunit抓取动态网页(HtmlUnit在多线程环境下怎么使用才能避免网页抓取失败的问题)
优采云 发布时间: 2021-11-21 13:03htmlunit抓取动态网页(HtmlUnit在多线程环境下怎么使用才能避免网页抓取失败的问题)
如何在多线程环境下使用HtmlUnit避免网页爬取失败的问题。我们来谈谈这个问题的解决方案。
这个问题的原因其实很简单。例如,线程 A 正在使用 WebClient 对象来获取网页。在整个抓取过程结束之前,当前线程被 CPU 挂起,所以线程 B 被激活,然后 B 使用 A 使用的 WebClient 对象正在做其他网页抓取工作,那么此时 WebCLient 对象将清除未完成的工作留下的数据,等等,共享一个WebClient的线程越多,出现问题的频率就越高。丢失网页的概率更高。但其实这个问题并不难解决,它的解决方案也有广泛的适用性:不管是什么对象,在多线程环境中遇到资源共享问题时,通常有两种解决方案,一种是使用对于 JDK1.2 之后的 ThreadLocal 对象,
早在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