HtmlUnit-JavaScript爬坑

源码地址: https://download.csdn.net/download/NaXieNianYiShiGuJi/15729089

maven设置

直接贴代码

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>
  <groupId>com.test.htmlunit</groupId>
  <artifactId>htm-unit</artifactId>
  <version>0.0.1-SNAPSHOT</version>
  <properties>
		<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
		<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
		<maven.compiler.encoding>UTF-8</maven.compiler.encoding>
	</properties>
	<build>
		<finalName>http-utils</finalName>
		<plugins>
			<plugin>
				<groupId>org.apache.maven.plugins</groupId>
				<artifactId>maven-javadoc-plugin</artifactId>
				<version>2.10.3</version>
				<configuration>
					<encoding>UTF-8</encoding>
				</configuration>
			</plugin>
			<plugin>
				<groupId>org.apache.maven.plugins</groupId>
				<artifactId>maven-resources-plugin</artifactId>
				<version>2.7</version>
				<configuration>
					<encoding>UTF-8</encoding>
				</configuration>
			</plugin>
			<plugin>
				<groupId>org.apache.maven.plugins</groupId>
				<artifactId>maven-compiler-plugin</artifactId>
				<version>3.5.1</version>
				<configuration>
					<source>1.8</source>
					<target>1.8</target>
					<encoding>UTF-8</encoding>
				</configuration>
			</plugin>
		</plugins>
	</build>
	<dependencies>
		<dependency>
			<groupId>junit</groupId>
			<artifactId>junit</artifactId>
			<version>4.12</version>
		</dependency>
		<dependency>
			<groupId>net.sourceforge.htmlunit</groupId>
			<artifactId>htmlunit</artifactId>
			<version>2.47.1</version>
			<!-- <version>2.29</version> -->
		</dependency>
		<dependency>
			<groupId>org.jsoup</groupId>
			<artifactId>jsoup</artifactId>
			<version>1.8.3</version>
		</dependency>
		<dependency>
			<groupId>dom4j</groupId>
			<artifactId>dom4j</artifactId>
			<version>1.6.1</version>
		</dependency>
		<dependency>
			<groupId>org.apache.commons</groupId>
			<artifactId>commons-lang3</artifactId>
			<version>3.4</version>
		</dependency>
		<dependency>
			<groupId>commons-codec</groupId>
			<artifactId>commons-codec</artifactId>
			<version>1.9</version>
		</dependency>
		<dependency>
			<groupId>commons-digester</groupId>
			<artifactId>commons-digester</artifactId>
			<version>2.0</version>
			<exclusions>
				<exclusion>
					<artifactId>commons-beanutils</artifactId>
					<groupId>commons-beanutils</groupId>
				</exclusion>
				<exclusion>
					<artifactId>commons-logging</artifactId>
					<groupId>commons-logging</groupId>
				</exclusion>
			</exclusions>
		</dependency>
		<dependency>
			<groupId>commons-beanutils</groupId>
			<artifactId>commons-beanutils</artifactId>
			<version>1.9.2</version>
			<exclusions>
				<exclusion>
					<artifactId>commons-logging</artifactId>
					<groupId>commons-logging</groupId>
				</exclusion>
			</exclusions>
		</dependency>
		<dependency>
			<groupId>commons-fileupload</groupId>
			<artifactId>commons-fileupload</artifactId>
			<version>1.3.1</version>
			<exclusions>
				<exclusion>
					<artifactId>commons-io</artifactId>
					<groupId>commons-io</groupId>
				</exclusion>
			</exclusions>
		</dependency>
		<dependency>
			<groupId>commons-io</groupId>
			<artifactId>commons-io</artifactId>
			<version>2.5</version>
		</dependency>
		<dependency>
			<groupId>commons-logging</groupId>
			<artifactId>commons-logging</artifactId>
			<version>1.2</version>
		</dependency>
		<dependency>
			<groupId>commons-httpclient</groupId>
			<artifactId>commons-httpclient</artifactId>
			<version>3.1</version>
			<exclusions>
				<exclusion>
					<artifactId>commons-codec</artifactId>
					<groupId>commons-codec</groupId>
				</exclusion>
				<exclusion>
					<artifactId>commons-logging</artifactId>
					<groupId>commons-logging</groupId>
				</exclusion>
			</exclusions>
		</dependency>
	</dependencies>
</project>

常规方法介绍

直接贴代码,注释很详细,上手很轻松

public static void main(String[] args) throws Exception {
		WebClient webClient = new WebClient(BrowserVersion.CHROME);//新建一个模拟谷歌Chrome浏览器的浏览器客户端对象
		webClient.getOptions().setThrowExceptionOnScriptError(false);//当JS执行出错的时候是否抛出异常, 这里选择不需要
		webClient.getOptions().setThrowExceptionOnFailingStatusCode(false);//当HTTP的状态非200时是否抛出异常, 这里选择不需要
		webClient.getOptions().setActiveXNative(false);
		//webClient.getOptions().setCssEnabled(false);//是否启用CSS, 因为不需要展现页面, 所以不需要启用
		webClient.getOptions().setCssEnabled(false);//是否启用CSS, 因为不需要展现页面, 所以不需要启用
		webClient.getOptions().setJavaScriptEnabled(true); //很重要,启用JS
		webClient.setAjaxController(new NicelyResynchronizingAjaxController());//很重要,设置支持AJAX
		try {
			// 拿到这个网页  
	            HtmlPage page = webClient.getPage("https://www.baidu.com");  
	            HtmlInput username = (HtmlInput)page.getElementById("kw");
	            username.type("李晟");
	            HtmlInput su = (HtmlInput)page.getElementById("su");
                    //input点击
	            HtmlPage nextPage = su.click();  
	            webClient.waitForBackgroundJavaScript(10000);//异步JS执行需要耗时,所以这里线程要阻塞30秒,等待异步JS执行结束
	            System.out.println(nextPage.asXml()); 
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			webClient.close();

     调用页面JavaScript方法,贴代码

                //简单function
	        String javaScriptCode = "funtion1('235','234')";
	        ScriptResult result = nextPage.executeJavaScript(javaScriptCode); 
	        //webClient.waitForBackgroundJavaScript(3000);//异步JS执行需要耗时,所以这里线程要阻塞30秒,等待异步JS执行结束
	        //如果是ajax,则还需重新请求
	        HtmlPage nextPage2=(HtmlPage)result.getNewPage();
	        System.out.println(nextPage2.asXml());

    是不是感觉很简单,当然调用JavaScript方法需要对页面源码有一定阅读能力

    好了,简单入手就到这里了,下面来个挑战

    需求如下,打开头条搜索,搜索关键词中国新闻网,点击用户,点击中国新闻网

    从如图看,我们分解下步骤

    1、我们可以直接访问头条搜索地址https://www.toutiao.com/search/?keyword=中国新闻网

    2、点击用户

    3、点击中国新闻网

    直接贴代码

        try {
		// 由于头条是https需要设置https支持
		webClient.getOptions().setUseInsecureSSL(true);
		//不想看javascript报错设置如下
                webClient.getOptions().setThrowExceptionOnScriptError(false);
		JavaScriptEngine engine = (JavaScriptEngine)webClient.getJavaScriptEngine();
		engine.holdPosponedActions();
	        HtmlPage page = webClient.getPage("https://www.toutiao.com/search/?keyword=中国新闻网");  
	        webClient.waitForBackgroundJavaScript(10000);//异步JS执行需要耗时,所以这里线程要阻塞30秒,等待异步JS执行结束
	        //快速查找<div class="tabBar"><ul><li>综合</li><li>视频</li><li>用户</li></ul></div>
	        List<HtmlListItem> tabli=page.getByXPath("//div[@class='tabBar']/ul/li[3]");
	        HtmlPage page2=tabli.get(0).click();
	        webClient.waitForBackgroundJavaScript(10000);//异步JS执行需要耗时,所以这里线程要阻塞30秒,等待异步JS执行结束
	        //System.out.println(page2.asXml());
	        //dom快速解析
	        Document doc = Jsoup.parse(page2.asXml());
	        Element element = doc.select("div[class=tabBar]").first();
	        System.out.println(":::::::::::::::::::::"+element.html());
	} catch (Exception e) {
		e.printStackTrace();
	} finally {
		webClient.close();

    代码中有段doc.select("div[class=tabBar]"),附下jsoup的select说明

    跑个代码看看,满怀期待

    没想着一次搞定,果然我们拿不到搜索的内容

    看看先看看浏览器的网络

     再在控制台找找,看有没有走这个ajax请求

    控制台有这个ajax请求的链接,那为啥我们没有拿到信息呢,我们再看看控制台

    原来头条的js经过混淆压缩了,导致htmlunit无法加载内容

    想想其他办法,既然ajax请求链接在控制台有打印,那我们想办法拿到ajax请求链接不就好了吗

      貌似没有啥接口开放啊,不过没关系,java么, 既然有这个东西,那我重写下呗,没有我拿不到的东西

package com.lz.test;
import com.gargoylesoftware.htmlunit.NicelyResynchronizingAjaxController;
import com.gargoylesoftware.htmlunit.WebRequest;
import com.gargoylesoftware.htmlunit.html.HtmlPage;
public class MyNicelyResynchronizingAjaxController extends NicelyResynchronizingAjaxController {
	public WebRequest ajaxSetting;
	public WebRequest getAjaxSetting() {
		return ajaxSetting;
	public void setAjaxSetting(WebRequest ajaxSetting) {
		this.ajaxSetting = ajaxSetting;
	@Override
	public boolean processSynchron(final HtmlPage page, final WebRequest settings, final boolean async) {
		ajaxSetting = settings;
		super.processSynchron(page, settings, async);
		return !async;

    把webClient.setAjaxController(new NicelyResynchronizingAjaxController());换成我的,顺便对页面加一下错误监听,直接贴代码

public static void main(String[] args) throws Exception {
		WebClient webClient = new WebClient(BrowserVersion.CHROME);//新建一个模拟谷歌Chrome浏览器的浏览器客户端对象
		webClient.getOptions().setThrowExceptionOnScriptError(false);//当JS执行出错的时候是否抛出异常, 这里选择不需要
		webClient.getOptions().setThrowExceptionOnFailingStatusCode(false);//当HTTP的状态非200时是否抛出异常, 这里选择不需要
		webClient.getOptions().setActiveXNative(false);
		//webClient.getOptions().setCssEnabled(false);//是否启用CSS, 因为不需要展现页面, 所以不需要启用
		webClient.getOptions().setCssEnabled(false);//是否启用CSS, 因为不需要展现页面, 所以不需要启用
		webClient.getOptions().setJavaScriptEnabled(true); //很重要,启用JS
		MyNicelyResynchronizingAjaxController myajax=new MyNicelyResynchronizingAjaxController();
		webClient.setAjaxController(myajax);//很重要,设置支持AJAX
		//webClient.setAjaxController(new NicelyResynchronizingAjaxController());//很重要,设置支持AJAX
		try {
			// 拿到这个网页  
	        HtmlPage page = webClient.getPage("https://www.baidu.com");  
	        HtmlInput username = (HtmlInput)page.getElementById("kw");
	        username.type("李晟");
	        HtmlInput su = (HtmlInput)page.getElementById("su");
	        HtmlPage nextPage = su.click();  
	        webClient.waitForBackgroundJavaScript(10000);//异步JS执行需要耗时,所以这里线程要阻塞30秒,等待异步JS执行结束
	        System.out.println(nextPage.asXml());  
	        //简单function
	        String javaScriptCode = "funtion1('235','234')";
	        ScriptResult result = nextPage.executeJavaScript(javaScriptCode); 
	        //webClient.waitForBackgroundJavaScript(3000);//异步JS执行需要耗时,所以这里线程要阻塞30秒,等待异步JS执行结束
	        //如果是ajax,则还需重新请求
	        HtmlPage nextPage2=(HtmlPage)result.getNewPage();
	        System.out.println(nextPage2.asXml());
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			webClient.close();
		try {
			// 由于头条是https需要设置https支持
			webClient.getOptions().setUseInsecureSSL(true);
			//不想看javascript报错设置如下
			//webClient.getOptions().setThrowExceptionOnScriptError(false);
			//javascript报错监听
			webClient.setJavaScriptErrorListener(new JavaScriptErrorListener() {
				@Override
				public void warn(String message, String sourceName, int line, String lineSource, int lineOffset) {
					// TODO Auto-generated method stub
					System.out.println("warn");
				@Override
				public void timeoutError(HtmlPage page, long allowedTime, long executionTime) {
					// TODO Auto-generated method stub
					System.out.println("timeoutError");
				@Override
				public void scriptException(HtmlPage page, ScriptException scriptException) {
					// TODO Auto-generated method stub
					System.out.println("scriptException"+page.getUrl());
				@Override
				public void malformedScriptURL(HtmlPage page, String url, MalformedURLException malformedURLException) {
					// TODO Auto-generated method stub
					System.out.println("malformedScriptURL"+url);
				@Override
				public void loadScriptError(HtmlPage page, URL scriptUrl, Exception exception) {
					// TODO Auto-generated method stub
					System.out.println("loadScriptError"+scriptUrl);
			JavaScriptEngine engine = (JavaScriptEngine)webClient.getJavaScriptEngine();
			engine.holdPosponedActions();
	                HtmlPage page = webClient.getPage("https://www.toutiao.com/search/?keyword=中国新闻网");  
	                webClient.waitForBackgroundJavaScript(10000);//异步JS执行需要耗时,所以这里线程要阻塞30秒,等待异步JS执行结束
	                //快速查找<div class="tabBar"><ul><li>综合</li><li>视频</li><li>用户</li></ul></div>
	                List<HtmlListItem> tabli=page.getByXPath("//div[@class='tabBar']/ul/li[3]");
	                HtmlPage page2=tabli.get(0).click();
	                webClient.waitForBackgroundJavaScript(10000);//异步JS执行需要耗时,所以这里线程要阻塞30秒,等待异步JS执行结束
	                System.out.println(page2.asXml());
	                //dom快速解析
	                Document doc = Jsoup.parse(page2.asXml());
	                Element element = doc.select("div[class=sections]").first();
	                System.out.println(":::::::::::::::::::::"+element.html());
	                //拿到ajax请求地址
	                WebRequest ajaxSetting = myajax.getAjaxSetting();
	                System.out.println("ajax=============="+ajaxSetting.getUrl());
	                List<HtmlAnchor> div_a=page2.getByXPath("//div[@class='sections']/div[1]/a");
	                //System.out.println(div_a.get(0).toString());
	                HtmlPage page3=div_a.get(0).click();
	                webClient.waitForBackgroundJavaScript(10000);//异步JS执行需要耗时,所以这里线程要阻塞30秒,等待异步JS执行结束
	                System.out.println(page3.asXml());
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			webClient.close();

    代码跑起来,看看控制台, 结果如下,至此问题解决,

源码地址:https://download.csdn.net/download/NaXieNianYiShiGuJi/15729089

源码地址:https://download.csdn.net/download/NaXieNianYiShiGuJi/15729089

源码地址:https://download.csdn.net/download/NaXieNianYiShiGuJi/15729089

HtmlUnit-JavaScript爬坑源码地址:https://download.csdn.net/download/NaXieNianYiShiGuJi/15729089简介 HtmlUnit是一个无界面浏览器Java程序。它为HTML文档建模,提供了调用页面、填写表单、单击链接等操作的API。就跟你在浏览器里做的操作一样。 HtmlUnit不错的JavaScript支持(不断改进),甚至可以使用相当复杂的AJAX库,根据配置的不同模拟Chrome、Firefox或Intern...
不知道大家在使用 jsoup 的过程中有没有遇到取内容时,发现有的网页里面的内容时通过 JavaScript 异步加载的数据,导致我们的爬虫空手而归(只抓到一个网页的外框)。 首先再遇到这个问题的时候想到的解决方案有两种: 使用类似 Python 中延迟加载的方式使等待网页异步加载完成后取异步加载完成的网页 使用某种特殊的方法使取出来的网页外框模拟执行里面的 JavaScript 代码
原文地址:http://www.haohaoblog.com/?p=1327&utm_source=tuicool 做Java编程的人其实,很多不懂SEO,也不知道如何让百度收录等等,当然,对于爬虫,网页抓取,也不是所有编程的人有考虑到,但是专门做这个人,还是需要了解一下这里面的知识的,那下面就来介绍一下一些爬虫和网页采集相关的组件和插件吧~ 大家在做爬虫、网页采集、通过网页自动...
 博客搬家系列(一)-简介:https://blog.csdn.net/rico_zhou/article/details/83619152  博客搬家系列(二)-取CSDN博客:https://blog.csdn.net/rico_zhou/article/details/83619509  博客搬家系列(三)-取博客园博客:htt...
在之前的系列文章中介绍了如何使用httpclient抓取页面html以及如何用jsoup分析html源文件内容得到我们想要的数据,但是有时候通过这两种方式不能正常抓取到我们想要的数据,比如看如下例子。 1.需求场景: 想要抓取股票的最新价格,页面F12信息如下: 按照前面的方式,取的代码如下: * @description: 取股票的最新股价 * @author: JAVA开发老...
### 回答1: Java爬虫是一种利用Java语言编写的爬虫程序,可以用于自动化地获取互联网上的信息。获取网页源代码是Java爬虫程序中的一项基本功能,可以利用Java提供的网络编程和HTML解析库来实现。 Java爬虫获取网页源代码的过程通常分为以下几个步骤: 1. 网络连接:Java爬虫需要通过网络连接到要取的网站,可以使用Java提供的URLConnection或者Apache HttpClient等库进行网络连接。 2. 发起请求:一旦网络连接建立,可以构造HTTP请求,并附上必要的参数和头信息,向服务器发送请求。 3. 接收响应:服务器收到请求后,会返回HTTP响应,Java爬虫需要接收并解析这个响应。 4. HTML解析:HTTP响应中通常包括HTML代码,需要使用HTML解析库(如Jsoup)对其进行解析,提取出需要的内容。 5. 存储数据:Java爬虫通常需要将从网站上取的数据存储到数据库或者文件中,以供后续分析和使用。 拆分HTML是指将HTML代码拆分成元素,根据标签将其分解成一棵树形结构,每个节点代表一个元素,例如div、p等。Java提供了很多HTML解析库,如Jsoup、HtmlUnit等,可以方便地将HTML代码拆分成元素,并通过操作DOM树实现对元素的查找和修改等操作。在Java爬虫中,拆分HTML代码是非常重要的一步,可以大大简化数据的提取和处理过程,从而实现高效、精确的数据抓取。 ### 回答2: Java爬虫是一种程序,能够自动地获取Web页面数据并提取感兴趣的内容。Java爬虫获取源代码的方法是使用Java网络请求库发送HTTP GET请求,并通过响应获取所需的HTML源代码。 拆分HTML源代码的方法通常包括两个步骤。首先,Java爬虫需要使用HTML解析工具(例如Jsoup)将HTML源代码转换成可操作的DOM对象。这样,Java爬虫就可以对HTML进行操作,例如查找特定的元素、获取元素属性或文本内容。 第二步是使用Java爬虫的逻辑或正则表达式进行HTML内容的拆分。拆分HTML的方法通常有两种:一种是通过使用Java的正则表达式库快速地定位所需的内容;另一种方法是使用HTML标签语言对HTML代码进行结构性解析,以此找到我们需要的内容。 在拆分HTML的过程中,Java爬虫需要针对每个网站的HTML源代码进行特定的处理,以确保获取所需信息的准确性和完整性。一般而言,Java爬虫需要根据网站的HTML结构和文件格式,制定适当的策略,确保取数据质量达到预期。 ### 回答3: Java爬虫是一种可以自动化获取网页内容的程序,通常用于获取互联网上的数据和信息,比如抓取网页内容、分析网页结构等。 获取网页内容的第一步是获取源代码,这可以通过Java中的URLConnection或HttpClient等类库实现。这些类库可以建立HTTP连接,获取网页源代码。获取到的源代码通常是一个包含HTML标签和CSS样式等文本字符串。 随后需要对获取的源代码进行解析和处理,这时我们可以选择使用各种类库和工具(比如Jsoup)来解析HTML代码,根据HTML标签来提取所需的数据。这些工具可以方便地捕获网页中的标签、属性、文本等信息,并对其进行处理和转换。 当数据被提取后,我们还需要将其进行处理,主要是拆分HTML文件,分离出所需的内容。这需要使用正则表达式等方法,对提取的数据进行逐一判断,分割。这样我们就可以将网页内容划分为独立的组件,包括标题、文本、图像等,并且可以根据需要进行重新排布。 总的来说,Java爬虫获取网页源代码并拆分HTML是获取网页信息的基本流程。通过各种类库和工具,我们可以轻松地处理原始源代码,提取出所需的数据,并按照需要进行处理和调整,实现对网页信息的自动化采集和处理。