`

HtmlUnit2.14使用样例—获取动态网页

阅读更多

编写不易,转载请注明(http://shihlei.iteye.com/blog/2067707)!

一 概述

 

    HttpClient适合处理静态资源,网络爬虫等类似应用很大程度需要处理动态网页(内容有js填充,如百度图片,body里基本没有数据,碰到最麻烦的是新浪微博列表页)。将网页下载后,结合JS和Dom模型还原网页,我目前还未攻破,但在下载层还原网页,HtmlUnit是一种解决方案,虽然对JS的支持还是不完美。

    HtmlUnit其实是自动化测试工具,集成了下载(HttpClient),Dom(NekoHtml),驱动JS(Rhino)。有一定的网页渲染能力,由于会驱动Dom,会消耗些CPU,内存。

   本文描述HTMLUnit请求响应,设置cookies,设置代理,驱动JS等方法。

 

二 版本

 

<dependency>
	<groupId>net.sourceforge.htmlunit</groupId>
	<artifactId>htmlunit</artifactId>
	<version>2.14</version>
</dependency>

 

三 典型功能

 

1) 打开google搜索百度

 

/**
 * 打开google 搜索百度
 * 
 * @param args
 * @throws Exception
 */
public static void main(String[] args) throws Exception {
	String url = "http://www.google.com.hk";

	final WebClient webClient = new WebClient();
	HtmlPage htmlPage = webClient.getPage(url);

	// HtmlUnit dom模型
	// 获取表单 ,获得form标签name属性=f
	HtmlForm form = htmlPage.getFormByName("f");
	// 获取输入框, 获取 input标签 ,name属性=q
	HtmlTextInput text = form.getInputByName("q");
	// 搜索百度
	text.setText("baidu");
	// 获取提交按钮
	HtmlSubmitInput button = form.getInputByName("btnG");
	// 提交表单
	HtmlPage listPage = button.click();

	System.out.println(listPage.asXml());
         
      webClient.closeAllWindows();
}

 

2)获取动态页面

 

/**
 * 获取百度图片js后的内容
 * 
 * @throws Exception
 */
public void demo2() throws Exception {
	String url = "http://image.baidu.com/i?tn=baiduimage&ipn=r&ct=201326592&cl=2&lm=-1&st=-1&fm=result&fr=&sf=1&fmq=1400328281672_R&pv=&ic=0&nc=1&z=&se=1&showtab=0&fb=0&width=&height=&face=0&istype=2&ie=utf-8&word=html";

	final WebClient webClient = new WebClient();

	// 1 启动JS
	webClient.getOptions().setJavaScriptEnabled(true);
	// 2 禁用Css,可避免自动二次请求CSS进行渲染
	webClient.getOptions().setCssEnabled(false);
	// 3 启动客户端重定向
	webClient.getOptions().setRedirectEnabled(true);

	// 4 js运行错误时,是否抛出异常
	webClient.getOptions().setThrowExceptionOnScriptError(false);
	// 5 设置超时
	webClient.getOptions().setTimeout(50000);
	
	HtmlPage htmlPage = webClient.getPage(url);
	// 等待JS驱动dom完成获得还原后的网页
	webClient.waitForBackgroundJavaScript(10000);
	// 网页内容
	System.out.println(htmlPage.asXml());
	webClient.closeAllWindows();
}

 

四 样例

(1)请求响应

 

/**
 * Get请求
 * @param url
 * @return
 * @throws Exception
 */
public static byte[] sendGetRequest(String url) throws Exception{
        WebClient webClient = new WebClient();
	WebRequest webRequest = new WebRequest(new URL(url));
	webRequest.setHttpMethod(HttpMethod.GET);
	return sendRequest(webClient,webRequest);
}

/**
 * Post 请求
 * 
 * @param url
 * @param params
 * @return
 * @throws Exception
 */
public static byte[] sendPostRequest(String url,Map<String,String> params) throws Exception{
        WebClient webClient = new WebClient();
	WebRequest webRequest = new WebRequest(new URL(url));
	webRequest.setHttpMethod(HttpMethod.POST);
	if (params != null && params.size() > 0) {
		for (Entry<String, String> param : params.entrySet()) {
			webRequest.getRequestParameters().add(new NameValuePair(param.getKey(), param.getValue()));
		}
	}
	return sendRequest(webClient,webRequest);
}

//底层请求
private static byte[] sendRequest(WebClient webClient,WebRequest webRequest) throws Exception{
	byte[] responseContent = null;
	Page page = webClient.getPage(webRequest);
	
	WebResponse webResponse = page.getWebResponse();
	
	int status = webResponse.getStatusCode();
	
	System.out.println("Charset : " + webResponse.getContentCharset());

	System.out.println("ContentType : " + webResponse.getContentType());

	// 读取数据内容
	if (status==200) {
		if (page.isHtmlPage()) {
			// 等待JS执行完成,包括远程JS文件请求,Dom处理
		     webClient.waitForBackgroundJavaScript(10000);
                     // 使用JS还原网页
		     responseContent = ((HtmlPage) page).asXml().getBytes();
		} else {
			InputStream bodyStream = webResponse.getContentAsStream();
			responseContent = ByteStreams.toByteArray(bodyStream);
			bodyStream.close();
		}
	}
	// 关闭响应流
	webResponse.cleanUp();

	return responseContent;
}

 

(2)配置JS,CSS,超时,重定向

 

private void configWebClient(WebClient webClient) {
	// 设置webClient的相关参数
	// 1 启动JS
	webClient.getOptions().setJavaScriptEnabled(true);
	// 2 禁用Css,可避免自动二次请求CSS进行渲染
	webClient.getOptions().setCssEnabled(false);
	// 3 启动客户端重定向
	webClient.getOptions().setRedirectEnabled(true);

	// 4 js运行错误时,是否抛出异常
	webClient.getOptions().setThrowExceptionOnScriptError(false);
	// 5 设置超时
	webClient.getOptions().setTimeout(timeout);
}

 

(3)代理

 

private void setProxy(WebClient webClient,HttpProxy proxy) {
	ProxyConfig proxyConfig = webClient.getOptions().getProxyConfig();
	proxyConfig.setProxyHost(proxy.getHost());
	proxyConfig.setProxyPort(proxy.getPort());

	DefaultCredentialsProvider credentialsProvider = (DefaultCredentialsProvider) webClient
			.getCredentialsProvider();
	credentialsProvider.addCredentials(proxy.getUser(), proxy.getPassword());
}

 

 辅助类:

 

package x.http.core;


/**
 * Http代理
 * 
 * @author shilei
 * 
 */
public class HttpProxy {
	private String proxy = "http";
	private String host;
	private int port;
	private String user;
	private String password;
	public String getProxy() {
		return proxy;
	}
	public void setProxy(String proxy) {
		this.proxy = proxy;
	}
	public String getHost() {
		return host;
	}
	public void setHost(String host) {
		this.host = host;
	}
	public int getPort() {
		return port;
	}
	public void setPort(int port) {
		this.port = port;
	}
	public String getUser() {
		return user;
	}
	public void setUser(String user) {
		this.user = user;
	}
	public String getPassword() {
		return password;
	}
	public void setPassword(String password) {
		this.password = password;
	}
}

 

(4)Cookies:可以用于认证数据设置

1)设置Cookies

 

private void setCookies(WebClient webClient,String domain, Map<String, String> cookies) {
	if (cookies != null && cookies.size() > 0) {
		webClient.getCookieManager().setCookiesEnabled(true);// enable
																// cookies
		for (Entry<String, String> c : cookies.entrySet()) {
			Cookie cookie = new Cookie(domain, c.getKey(), c.getValue());
			webClient.getCookieManager().addCookie(cookie);
		}
	}
}

 

2)获取响应Cookies

 

private Map<String, String> getResponseCookies(WebClient webClient) {
	Set<Cookie> cookies = webClient.getCookieManager().getCookies();
	Map<String, String> responseCookies = Maps.newHashMap();
	for (Cookie c : cookies) {
		responseCookies.put(c.getName(), c.getValue());
	}
	return responseCookies;
}

 

3)删除所有Cookies

 

/**
 * 清除所有cookie
 */
public void clearCookies(WebClient webClient) {
	webClient.getCookieManager().clearCookies();
}

 

 (5)驱动JS:

可实现自动化流程,如驱动表单提交,获取表单提交后的页面

如登录后页面:

public void doWeb(Page page) {
	if (page instanceof HtmlPage) {
		StringBuilder js = new StringBuilder();
		js.append("document.getElementsByName('username')[1].value='").append(WeiboAccount.USERNAME)
				.append("';");
		js.append("document.getElementsByName('password')[1].value='").append(WeiboAccount.PASSWORD)
				.append("';");
		js.append("document.getElementsByClassName('W_btn_g')[1].click();");
		HtmlPage htmlPage = (HtmlPage) page;
		htmlPage.executeJavaScript(js.toString());
	}
}

 

 附录:完整代码

package x.http.simple.htmlunit;

import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;

import x.http.core.HttpProxy;

import com.gargoylesoftware.htmlunit.DefaultCredentialsProvider;
import com.gargoylesoftware.htmlunit.HttpMethod;
import com.gargoylesoftware.htmlunit.Page;
import com.gargoylesoftware.htmlunit.ProxyConfig;
import com.gargoylesoftware.htmlunit.WebClient;
import com.gargoylesoftware.htmlunit.WebRequest;
import com.gargoylesoftware.htmlunit.WebResponse;
import com.gargoylesoftware.htmlunit.html.HtmlForm;
import com.gargoylesoftware.htmlunit.html.HtmlPage;
import com.gargoylesoftware.htmlunit.html.HtmlSubmitInput;
import com.gargoylesoftware.htmlunit.html.HtmlTextInput;
import com.gargoylesoftware.htmlunit.util.Cookie;
import com.gargoylesoftware.htmlunit.util.NameValuePair;
import com.google.common.collect.Maps;
import com.google.common.io.ByteStreams;

public class HtmlUnitDemo {

	private WebClient webClient = null;

	private int timeout = 50000;

	public HtmlUnitDemo() {
		this(null);
	}

	/**
	 * Get请求
	 * 
	 * @param url
	 * @return
	 * @throws Exception
	 */
	public byte[] sendGetRequest(String url) throws Exception {
		WebRequest webRequest = new WebRequest(new URL(url));
		webRequest.setHttpMethod(HttpMethod.GET);
		return sendRequest(webRequest);
	}

	/**
	 * Post 请求
	 * 
	 * @param url
	 * @param params
	 * @return
	 * @throws Exception
	 */
	public byte[] sendPostRequest(String url, Map<String, String> params) throws Exception {
		WebRequest webRequest = new WebRequest(new URL(url));
		webRequest.setHttpMethod(HttpMethod.POST);
		if (params != null && params.size() > 0) {
			for (Entry<String, String> param : params.entrySet()) {
				webRequest.getRequestParameters().add(new NameValuePair(param.getKey(), param.getValue()));
			}
		}
		return sendRequest(webRequest);
	}

	// 底层请求
	private byte[] sendRequest(WebRequest webRequest) throws Exception {
		byte[] responseContent = null;
		Page page = webClient.getPage(webRequest);

		WebResponse webResponse = page.getWebResponse();

		int status = webResponse.getStatusCode();

		System.out.println("Charset : " + webResponse.getContentCharset());

		System.out.println("ContentType : " + webResponse.getContentType());

		// 读取数据内容
		if (status == 200) {
			if (page.isHtmlPage()) {
				// 等待JS执行完成
				webClient.waitForBackgroundJavaScript(100000);
				responseContent = ((HtmlPage) page).asXml().getBytes();
			} else {
				InputStream bodyStream = webResponse.getContentAsStream();
				responseContent = ByteStreams.toByteArray(bodyStream);
				bodyStream.close();
			}
		}
		// 关闭响应流
		webResponse.cleanUp();

		return responseContent;
	}

	public HtmlUnitDemo(HttpProxy proxy) {
		webClient = new WebClient();
		configWebClient();
		// 设置代理
		if (proxy != null) {
			setProxy(proxy);
		}
	}

	private void configWebClient() {
		// 设置webClient的相关参数
		// 1 启动JS
		webClient.getOptions().setJavaScriptEnabled(true);
		// 2 禁用Css,可避免自动二次请求CSS进行渲染
		webClient.getOptions().setCssEnabled(false);
		// 3 启动客户端重定向
		webClient.getOptions().setRedirectEnabled(true);

		// 4 js运行错误时,是否抛出异常
		webClient.getOptions().setThrowExceptionOnScriptError(false);
		// 5 设置超时
		webClient.getOptions().setTimeout(timeout);
	}

	private void setProxy(HttpProxy proxy) {
		ProxyConfig proxyConfig = webClient.getOptions().getProxyConfig();
		proxyConfig.setProxyHost(proxy.getHost());
		proxyConfig.setProxyPort(proxy.getPort());

		DefaultCredentialsProvider credentialsProvider = (DefaultCredentialsProvider) webClient
				.getCredentialsProvider();
		credentialsProvider.addCredentials(proxy.getUser(), proxy.getPassword());
	}

	@SuppressWarnings("unused")
	private Map<String, String> getResponseCookies() {
		Set<Cookie> cookies = webClient.getCookieManager().getCookies();
		Map<String, String> responseCookies = Maps.newHashMap();
		for (Cookie c : cookies) {
			responseCookies.put(c.getName(), c.getValue());
		}
		return responseCookies;
	}

	@SuppressWarnings("unused")
	private void setCookies(String domain, Map<String, String> cookies) {
		if (cookies != null && cookies.size() > 0) {
			webClient.getCookieManager().setCookiesEnabled(true);// enable
																	// cookies
			for (Entry<String, String> c : cookies.entrySet()) {
				Cookie cookie = new Cookie(domain, c.getKey(), c.getValue());
				webClient.getCookieManager().addCookie(cookie);

				System.out.println("Set Cookies : " + c.getKey() + " | " + c.getValue());
			}
		}
	}

	/**
	 * 清除所有cookie
	 */
	public void clearCookies() {
		webClient.getCookieManager().clearCookies();
	}

	public void shutdown() throws IOException {
		webClient.closeAllWindows();
	}

	/**
	 * 打开google 搜索百度
	 * 
	 * @param args
	 * @throws Exception
	 */
	public void demo() throws Exception{
		String url = "http://www.google.com.hk";

		final WebClient webClient = new WebClient();
		HtmlPage htmlPage = webClient.getPage(url);

		// HtmlUnit dom模型
		// 获取表单 ,获得form标签name属性=f
		HtmlForm form = htmlPage.getFormByName("f");
		// 获取输入框, 获取 input标签 ,name属性=q
		HtmlTextInput text = form.getInputByName("q");
		// 搜索百度
		text.setText("baidu");
		// 获取提交按钮
		HtmlSubmitInput button = form.getInputByName("btnG");
		// 提交表单
		HtmlPage listPage = button.click();

		System.out.println(listPage.asXml());
		webClient.closeAllWindows();
	}
	/**
	 * 打开google 搜索百度
	 * 
	 * @param args
	 * @throws Exception
	 */
	public static void main(String[] args) throws Exception {
		String url = "http://www.google.com.hk";

		HtmlUnitDemo htmlUnit = new HtmlUnitDemo();
		byte[] getResponse = htmlUnit.sendGetRequest(url);
		System.out.println("Get Body : " + new String(getResponse, "utf-8"));
		byte[] postResponse = htmlUnit.sendPostRequest(url, null);
		System.out.println("Get Body : " + new String(postResponse, "utf-8"));

		htmlUnit.shutdown();
	}
}

 

 

分享到:
评论
3 楼 芦苇的殇殃 2016-11-01  
楼主,我想问下如何搜集所有页面的JSP信息,这个页面是有分页的,分页是由JS产生的,具体网址http://www.51science.cn/SearchIndexforStuPublic.aspx
2 楼 s568774056 2016-10-18  
谢谢LZ,解决了我的问题,
    webClient.waitForBackgroundJavaScript(10000);  放在后面界面才能解析,这个帮到我了
1 楼 人称二毛是也 2016-09-22  
写的这么好,居然没人顶?!!楼主我正需要,我可以要你完整的demo吗,我导入htmlunit的jar包后就编译不过去了,麻烦发我邮箱863215878@qq.com

相关推荐

    htmlunit2.14包

    在标题中提到的"htmlunit2.14包",指的是HTMLUnit的2.14版本,这是一个特定的发行版,包含了该版本的所有源代码、类库和其他必要的组件。 在描述中提到的“爬虫技术htmlunit可屏蔽javascript”,指的是HTMLUnit的一...

    java htmlunit-2.14

    在HTMLUnit-2.14中,可能使用了这些模块来提供基本的数据操作和功能支持。 2. **cssparser**:这是一个用于解析CSS(层叠样式表)的库,允许HTMLUnit解析并应用网页的样式规则,这对于准确地呈现页面的视觉效果至关...

    htmlunit-2.14-OSGi.jar

    htmlunit-2.14 jar包htmlunit爬去js加载后的页面特表好用

    htmlunit-2.14

    通过编程方式模拟用户行为,它可以获取动态生成的内容,从而帮助开发者获取和分析网页数据。 10. **兼容性**:HTMLUnit致力于保持与最新HTML、CSS和JavaScript标准的兼容性。`htmlunit-2.14`版本可能支持当时的大...

    通过htmlunit获取执行js代码后的html文档

    使用HTMLUnit获取执行JavaScript后的HTML文档,首先需要理解HTMLUnit的工作原理。HTMLUnit内建了一个基于WebClient的组件,它能够加载网页、执行JavaScript和处理DOM(文档对象模型)。以下是使用HTMLUnit进行此类...

    htmlunit-2.14.jar下载,全套

    在使用HTMLUnit进行爬虫开发时,你需要了解如何创建`HtmlUnit WebClient`实例,设置网络代理,处理异常,以及如何使用`HtmlPage`对象来获取和操作网页元素。同时,你也需要掌握JavaScript引擎的相关知识,因为...

    Htmlunit2.23-bin.zip

    在HTMLUnit 2.23中,开发者可以利用其JavaScript引擎执行网页上的脚本,这意味着它可以处理动态加载的内容,如AJAX请求和JavaScript事件。这使得HTMLUnit成为一个功能强大的工具,不仅能够获取静态HTML,还能处理...

    htmlunit java版无界面浏览器 网页自动登录

    htmlunit java版无界面浏览器 实现网页自动登录利器 官方最新下载 htmlunit 是一款开源的java 页面分析工具,读取页面后,可以有效的使用htmlunit分析页面上的内容。项目可以模拟浏览器运行,被誉为java浏览器的开源...

    Java爬虫Jsoup+httpclient获取动态生成的数据

    通过分析这些请求,开发者可以找到数据接口,并使用HttpClient来模拟这些请求,获取到动态加载的数据。 在本例中,我们通过Jsoup获取到了京东商品页面的静态HTML代码,但价格信息并未包含在内。通过分析页面源码...

    htmlUnit所需jar包

    使用HTMLUnit,开发者可以编写代码来浏览网页、填写表单、点击链接,甚至执行JavaScript,而无需真正打开一个浏览器。这对于自动化测试、数据抓取和无头爬虫来说非常有用。由于其无头特性,HTMLUnit在服务器端或...

    针对 httpclient4.* 绕验证码获取公司信息 包括 jsoup网页信息的爬虫及htmlUnit对动态网站信息的抓取

    本主题主要关注如何使用`httpclient4.*`库来绕过验证码获取公司信息,以及结合`jsoup`解析静态网页信息和`htmlUnit`处理动态网站的抓取。以下是对这些知识点的详细说明: 1. **httpclient4.***: Apache HttpClient...

    htmlunit爬取动态页面jar包

    HTMLUnit是一个Java库,模拟浏览器行为,用于自动化网页交互和数据抓取。它是一个无头浏览器,意味着它没有图形用户界面,而是通过程序接口(API)进行操作。这个压缩包包含21个jar文件,这些文件是实现HTMLUnit功能...

    htmlunit依赖jar包

    HTMLUnit是一款功能强大的Java库,它模拟了一个无头Web浏览器,...它简化了网页爬虫的编写,尤其是在处理需要JavaScript渲染的动态网页时。通过理解并正确配置其依赖,你可以有效地利用HTMLUnit进行各种自动化任务。

    htmlunit爬取网页并保存成Excel

    HTMLUnit是一个强大的无头浏览器库,它允许程序员模拟浏览器行为,...综上所述,HTMLUnit结合Apache POI库可以实现高效且灵活的网页数据抓取和整理,将动态网页内容转化为结构化的Excel表格,方便后续的分析和处理。

    htmlunit模拟cookie登录

    htmlunit 模拟cookie 存取 cookie值登录 如: wsyyuser.xywy.com Cookie c = new Cookie("wsyyuser.xywy.com", "PHPSESSID", Common.getValue("session_id") );

    传一个htmlunit依赖的jar包,官网所下

    接着,如果有JavaScript存在,HTMLUnit会使用内置的Rhino JavaScript引擎执行这些脚本,更新DOM树以反映动态变化的网页状态。这样,开发者可以通过HTMLUnit提供的API来访问和操作这个虚拟DOM,就像在实际浏览器中...

    htmlunit 及其 依赖包

    5. **HtmlunitTest.java**:这看起来是一个测试类,可能包含了使用HTMLUnit进行网页测试或爬虫的示例代码。通过这个文件,你可以学习如何初始化`WebClient`,加载网页,执行JavaScript,以及如何提取和处理网页上的...

    htmlunit基本jar包

    3. **错误处理**:在使用HTMLUnit时,由于JavaScript执行和网络请求的复杂性,需要处理可能出现的各种异常。 4. **性能优化**:虽然HTMLUnit是为了快速和自动化测试设计的,但在大规模使用时,仍需考虑性能优化,...

    htmlunit-2.8(api文档).zip

    2. **JavaScript支持**:HTMLUnit能够执行JavaScript代码,这意味着它能够解析和处理那些依赖JavaScript动态加载内容的网页。 3. **AJAX支持**:HTMLUnit可以处理AJAX异步请求,使得开发者能够测试那些通过AJAX技术...

Global site tag (gtag.js) - Google Analytics