亚洲免费在线-亚洲免费在线播放-亚洲免费在线观看-亚洲免费在线观看视频-亚洲免费在线看-亚洲免费在线视频

html解析工具類、html表格解析解析工具類

張軍 6649 0
package zj.parser.util;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.log4j.Logger;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;

import com.gargoylesoftware.htmlunit.WebClient;
import com.gargoylesoftware.htmlunit.html.DomElement;
import com.gargoylesoftware.htmlunit.html.HtmlElement;
import com.gargoylesoftware.htmlunit.html.HtmlPage;

import zj.check.util.CheckUtil;
import zj.common.KV;
import zj.common.exception.ServiceException;
import zj.java.util.JavaUtil;
import zj.parser.bean.ParamBase;
import zj.parser.factory.WebClientFactory;

/**
 * html解析工具類
 * 
 * @author SHNKCS 張軍 {@link <a target=_blank href="http://www.shanghaijiadun.com">上海加盾信息科技有限公司</a>&nbsp;&nbsp;&nbsp;&nbsp;<a target=_blank href="http://m.eyofj.com">張軍個人網站</a>&nbsp;&nbsp;&nbsp;&nbsp;<a target=_blank href="http://user.qzone.qq.com/360901061/">張軍QQ空間</a>}
 * @date 2015-11-03 21:59:00
 * @modifiyNote
 * @version 1.0
 */
public class HtmlParserUtil {
	private static Logger logger = Logger.getLogger(HtmlParserUtil.class);

	/**
	 * 獲取元素集合
	 * 
	 * @param rootPage
	 *            當前頁面
	 * @param xpath
	 *            路徑表達式
	 * @author 張軍
	 * @date 2015-11-03 21:59:00
	 * @modifiyNote
	 * @version 1.0
	 * @return
	 */
	public static List<?> getHtmlElements(final HtmlPage rootPage, String xpath) {
		try {
			List<?> hes = null;
			long st = 0;
			long et = 0;
			st = System.currentTimeMillis();
			while ((hes = rootPage.getByXPath(xpath)).size() == 0) {
				et = System.currentTimeMillis();
				if (et - st > 30000) {
					return null;
				}
				Thread.sleep(10);
			}
			return hes;
		} catch (Exception e) {
			return null;
		}
	}

	/**
	 * 獲取元素
	 * 
	 * @param rootPage
	 *            當前頁面
	 * @param xpath
	 *            路徑表達式
	 * @author 張軍
	 * @date 2015-11-03 21:59:00
	 * @modifiyNote
	 * @version 1.0
	 * @return
	 */
	public static HtmlElement getHtmlElement(final HtmlPage rootPage, String xpath) {
		try {
			List<?> hes = getHtmlElements(rootPage, xpath);
			return (HtmlElement) hes.get(0);
		} catch (Exception e) {
			return null;
		}
	}

	/**
	 * 單頁面處理
	 * 
	 * @param param
	 *            參數
	 * @author 張軍
	 * @date 2015-11-03 21:59:00
	 * @modifiyNote
	 * @version 1.0
	 */
	public static void doNormalPaper(ParamBase param) {
		// 實例化抽取程序對象
		WebClient webClient = null;
		try {
			// 列表及詳情頁采集
			// 一、設置任務名稱String
			// 循環提出字段值
			if (param.normalFields == null || param.normalFields.size() == 0) {
				logger.info("未設置字段");
			} else {
				// 二、設置網址String
				String homeUrl = param.homeUrl;
				// 三、設置多個字段List<Map<String,String>>
				// 1.key:字段,value:xxx
				// 2.key:字段名,value:xxx
				// 3.key:數據類型,value:(1:抓取文本、2:抓取元素的innerHtml、3:抓取元素的outerHtml、4:抓取元素的屬性值:屬性名)
				// 采集結果
				// 實例化抽取程序對象
				webClient = WebClientFactory.getInstance().getWebClient();
				// 獲取html頁面對象
				HtmlPage rootPage = null;
				// 首頁列表
				rootPage = webClient.getPage(homeUrl);
				// 默認打開網頁休眠1秒
				String html = rootPage.asXml();
				// System.out.println(html);
				// html內容
				Document doc = Jsoup.parse(html);
				// logger.info(rootPage.asXml());
				// 取字段值
				Map<String, Object> pageFieldValue = getPageFieldValueNormal(param, doc);
				// Thread.sleep(param.sleepCallback);
				// 回調
				param.callBack(pageFieldValue);
			}
		} catch (Exception e) {
			throw new ServiceException(e);
		} finally {
			// // 關閉資源
			// WebClientFactory.getInstance().close(webClient);
		}
	}

	/**
	 * 分頁列表或表格處理
	 * 
	 * @param param
	 *            參數
	 * @author 張軍
	 * @date 2015-11-03 21:59:00
	 * @modifiyNote
	 * @version 1.0
	 */
	public static void doListPaper(ParamBase param) {
		// 實例化抽取程序對象
		WebClient webClient = null;
		try {
			// 正常數據
			if (param.normalFields.size() > 0) {
				// 列表及詳情頁采集
				// 一、設置任務名稱String
				// 循環提出字段值
				doNormalPaper(param);
			}
			// 列表中的數據
			if (param.listKV.size() > 0) {
				HtmlPage rootPage = null;
				if (param.rootPage == null) {
					// 實例化抽取程序對象(由于回調只能每次都獲取新頁面)
					webClient = WebClientFactory.getInstance().getWebClient();
					// 二、設置網址String
					// 采集結果
					// 獲取html頁面對象
					// 首頁列表
					rootPage = webClient.getPage(param.homeUrl);
					// 回調修改,可能進入頁面要做前期查詢
					rootPage = param.updateRootPage(rootPage);
				} else {
					rootPage = param.rootPage;
				}
				// 循環翻頁
				for (KV<String, String> kv : param.listKV) {
					// 默認0頁
					param.tempPage = 0;
					// 列表表達式
					String listXpath = kv.getK();
					// 下一頁
					String nextPage = kv.getV();
					// 設置默認值
					param.tempListFields = param.listFields;
					if (param.mapListFields != null && param.mapListFields.size() > 0) {
						List<Map<String, String>> listFields = param.mapListFields.get(listXpath);
						if (listFields != null) {
							// 替換原始值
							param.tempListFields = listFields;
						}
					}
					if (param.tempListFields.size() > 0) {
						// 只處理第一頁
						doListPaper(listXpath, param, rootPage);
						if (CheckUtil.isNotNull(nextPage)) {
							// 有翻頁
							long st = System.currentTimeMillis();
							// 六、設置翻頁Map<String,String>
							// 1.key:翻頁,value:xxx
							// 2.key:翻頁停止,value:xxx
							List<?> nextDoms = null;
							// 正常加載完成開始
							while (true) {
								try {
									// 條件判斷開始
									nextDoms = rootPage.getByXPath(nextPage);
									// logger.info("-----" + nextPage.size());
									// 加載完成
									HtmlElement nextDom = (HtmlElement) nextDoms.get(0);
									rootPage = nextDom.click();
									// 休眠500毫秒加載頁面
									Thread.sleep(param.sleepNextPageClick);
									param.checkPageReadyState(rootPage);
									// logger.info(rootPage.asXml());
									doListPaper(listXpath, param, rootPage);
									// 重置開始時間
									st = System.currentTimeMillis();
								} catch (Exception e) {
									long et = System.currentTimeMillis();
									if (et - st > 30000) {
										break;
									}
								}
							}
						} else {
							// 自定義下一頁
							// 有翻頁
							long st = System.currentTimeMillis();
							while (true) {
								try {
									// 條件判斷開始
									rootPage = param.nextPage(rootPage);
									if (rootPage == null) {
										break;
									}
									// logger.info(rootPage.asXml());
									doListPaper(listXpath, param, rootPage);
									// 重置開始時間
									st = System.currentTimeMillis();
								} catch (Exception e) {
									long et = System.currentTimeMillis();
									if (et - st > 30000) {
										break;
									}
								}
							}
						}
					}
				}
			}
		} catch (Exception e) {
			throw new ServiceException(e);
		} finally {
			// // 關閉資源
			// WebClientFactory.getInstance().close(webClient);
		}
	}

	/**
	 * 分頁列表或表格處理
	 * 
	 * @param param
	 *            參數
	 * @param rootPage
	 *            當前頁對象
	 * @author 張軍
	 * @date 2015-11-03 21:59:00
	 * @modifiyNote
	 * @version 1.0
	 */
	private static void doListPaper(String listXPath, ParamBase param, HtmlPage rootPage) {
		try {
			// 頁面+1
			param.tempPage = param.tempPage + 1;
			if (param.tempPage < 0) {
				System.out.println(param.tempPage);
				return;
			}
			// 正常處理
			// 四、設置列表String
			List<?> listBoxs = null;
			// 條件判斷開始
			// 有翻頁
			long st = System.currentTimeMillis();
			while ((listBoxs = rootPage.getByXPath(listXPath)).size() == 0) {
				long et = System.currentTimeMillis();
				if (et - st > 30000) {
					break;
				}
			}
			if (listBoxs == null || listBoxs.size() == 0) {
				// 加載完成
				logger.warn("根據[" + listXPath + "]未找到集合元素");
			} else {
				// 一頁區域的結果
				List<Map<String, Object>> pageFieldValues = new ArrayList<>();
				for (Object listBoxObj : listBoxs) {
					DomElement listBox = (DomElement) listBoxObj;
					// logger.info(listBox.asXml());
					String xml = listBox.asXml();
					if (CheckUtil.isNotNull(param.startHtml) && CheckUtil.isNotNull(param.endHtml)) {
						// 添加頭尾html
						xml = param.startHtml + xml + param.endHtml;
					}
					// 獲取jsoup
					Document doc = Jsoup.parse(xml);
					// 取字段值
					Map<String, Object> pageFieldValue = getPageFieldValueList(param, doc);
					if (pageFieldValue.size() == 0) {
						// 如果未查詢到數據
						continue;
					}
					// 設置頁面值
					pageFieldValues.add(pageFieldValue);
				}
				// System.out.println(rootPage.getUrl() + "->" + param.homeUrl + "," + param.tempPage + "," + param.isDetail);
				// 回調
				// Thread.sleep(param.sleepCallback);
				if (param.tempIsCallBack) {
					param.callBack(listXPath, pageFieldValues);
				}
				// param.callBack(listXPath, pageFieldValues);
			}
		} catch (Exception e) {
			throw new ServiceException(e);
		}
	}

	/**
	 * 抽取值
	 * 
	 * @param doc
	 *            當前頁對象
	 * @param pageFieldValue
	 *            抽取值
	 * @param jsoupField
	 *            字段對象
	 * @return
	 * @author 張軍
	 * @date 2015-11-03 21:59:00
	 * @modifiyNote
	 * @version 1.0
	 */
	private static void extractFieldValue(Document doc, Map<String, Object> pageFieldValue, Map<String, String> jsoupField) {
		try {
			String p_name = jsoupField.get("字段名");
			String p_jqfield = jsoupField.get("字段");
			Object qfieldvalue = null;
			if (CheckUtil.isNull(p_jqfield)) {
				// 如果不寫字段,取文本
				qfieldvalue = doc;
			} else {
				String p_type = jsoupField.get("數據類型");
				Elements e_fields = doc.select(p_jqfield);
				// logger.info("e_fields.size():" + e_fields.size());
				if (e_fields == null || e_fields.size() == 0) {
					logger.warn("根據[" + p_jqfield + "]未找到數據");
					return;
				}
				// 1:抓取文本、2:抓取元素的innerHtml、3:抓取元素的outerHtml、4:抓取元素的屬性值:屬性名
				if (CheckUtil.isNull(p_type)) {
					qfieldvalue = e_fields;
				} else {
					Element e_field = (Element) e_fields.get(0);
					if ("1".equals(p_type)) {
						qfieldvalue = e_field.text();
					} else if ("2".equals(p_type)) {
						qfieldvalue = e_field.html();
					} else if ("3".equals(p_type)) {
						qfieldvalue = e_field.outerHtml();
					} else if (p_type.startsWith("4:")) {
						String[] ptypeAry = JavaUtil.split(p_type, ":");
						if (ptypeAry.length > 1) {
							qfieldvalue = e_field.attr(ptypeAry[1]);
						} else {
							return;
						}
					} else {
						return;
					}
				}
			}
			pageFieldValue.put(p_name, qfieldvalue);
		} catch (Exception e) {
			// 不做處理
			logger.error("取field域值出錯,繼續下個字段取值", e);
		}
	}

	/**
	 * 獲取頁面值
	 * 
	 * @param param
	 *            參數
	 * @param doc
	 *            當前頁對象
	 * @return
	 * @author 張軍
	 * @date 2015-11-03 21:59:00
	 * @modifiyNote
	 * @version 1.0
	 */
	private static Map<String, Object> getPageFieldValueNormal(ParamBase param, Document doc) {
		// 五、設置多個字段List<Map<String,String>>
		// 取字段值
		Map<String, Object> pageFieldValue = new HashMap<>();
		// 1.key:字段,value:xxx
		// 2.key:字段名,value:xxx
		// 3.key:提取的數據類型,value:(1:抓取文本、2:抓取元素的innerHtml、3:抓取元素的outerHtml、4:抓取元素的屬性值)
		for (Map<String, String> jsoupField : param.normalFields) {
			extractFieldValue(doc, pageFieldValue, jsoupField);
		}
		// 是否打開詳細頁
		doCallBack(false, param, pageFieldValue);
		return pageFieldValue;
	}

	/**
	 * 獲取頁面值
	 * 
	 * @param param
	 *            參數
	 * @param doc
	 *            當前頁對象
	 * @return
	 * @author 張軍
	 * @date 2015-11-03 21:59:00
	 * @modifiyNote
	 * @version 1.0
	 */
	private static Map<String, Object> getPageFieldValueList(ParamBase param, Document doc) {
		// 五、設置多個字段List<Map<String,String>>
		// 取字段值
		Map<String, Object> pageFieldValue = new HashMap<>();
		// 1.key:字段,value:xxx
		// 2.key:字段名,value:xxx
		// 3.key:提取的數據類型,value:(1:抓取文本、2:抓取元素的innerHtml、3:抓取元素的outerHtml、4:抓取元素的屬性值)
		for (Map<String, String> jsoupField : param.tempListFields) {
			extractFieldValue(doc, pageFieldValue, jsoupField);
		}
		doCallBack(true, param, pageFieldValue);
		return pageFieldValue;
	}

	/**
	 * 獲取頁面值
	 * 
	 * @param param
	 *            參數
	 * @param pageFieldValue
	 *            值
	 * @return
	 * @author 張軍
	 * @date 2015-11-03 21:59:00
	 * @modifiyNote
	 * @version 1.0
	 */
	private static void doCallBack(boolean isList, ParamBase param, Map<String, Object> pageFieldValue) {
		// 是否打開詳細頁
		String detailFieldName = null;
		ParamBase paramDetail = null;
		if (param.detailKV == null) {
			// 當前頁碼
			if (!param.isDetail) {
				// 如果非詳細頁
				param.pageCurrent = param.tempPage;
			}
		} else {
			detailFieldName = param.detailKV.getK();
			paramDetail = param.detailKV.getV();
			// 當前頁碼
			paramDetail.pageCurrent = param.tempPage;
			String detailHomeUrl = JavaUtil.objToStr(pageFieldValue.get(detailFieldName));
			if (CheckUtil.isNotNull(detailHomeUrl)) {
				// 禁止父類回調
				param.tempIsCallBack = false;
				// 是否是url
				paramDetail.homeUrl = detailHomeUrl;
				// 詳細頁面
				paramDetail.isDetail = true;
				// 賦值當前數據
				paramDetail.currentRangeValue = pageFieldValue;
				if (isList) {
					// 抽取詳細頁數據
					doListPaper(paramDetail);
				} else {
					doNormalPaper(paramDetail);
				}
			}
		}
	}
}
package zj.parser.factory;

import org.apache.log4j.Logger;

import com.gargoylesoftware.htmlunit.BrowserVersion;
import com.gargoylesoftware.htmlunit.NicelyResynchronizingAjaxController;
import com.gargoylesoftware.htmlunit.ThreadedRefreshHandler;
import com.gargoylesoftware.htmlunit.WebClient;
import com.gargoylesoftware.htmlunit.WebClientOptions;

/**
 * webClient工廠<br>
 * 
 * @version 1.00 (2011.12.02)
 * @author SHNKCS 張軍 {@link <a href="http://user.qzone.qq.com/360901061/">張軍QQ空間</a>}
 */
public class WebClientFactory {
	private transient static final Logger logger = Logger.getLogger(WebClientFactory.class);
	// 線程的本地實例存儲器,用于存儲WebClient實例
	private ThreadLocal<WebClient> clientThreadLocal;

	/**
	 * 構造方法,初始時線程的本地變量存儲器
	 */
	private WebClientFactory() {
		clientThreadLocal = new ThreadLocal<WebClient>();
	}

	private static class SingletonHolder {
		private static final WebClientFactory INSTANCE = new WebClientFactory();
	}

	/**
	 * 獲取工廠實例
	 * 
	 * @return 工廠實例
	 */
	public static final WebClientFactory getInstance() {
		return SingletonHolder.INSTANCE;
	}

	/**
	 * 獲取一個模擬CHROME版本的WebClient實例
	 * 
	 * @return 模擬CHROME版本的WebClient實例
	 */
	public final WebClient getWebClient() {
		return getWebClient(BrowserVersion.CHROME);
	}

	/**
	 * 獲取一個模擬CHROME版本的WebClient實例
	 * 
	 * @return 模擬browserVersion版本的WebClient實例
	 */
	// public synchronized WebClient getClient() {
	public final WebClient getWebClient(final BrowserVersion browserVersion) {
		WebClient webClient = null;
		/**
		 * 如果當前線程已有WebClient實例,則直接返回該實例 否則重新創建一個WebClient實例并存儲于當前線程的本地變量存儲器
		 */
		if ((webClient = clientThreadLocal.get()) == null) {
			clientThreadLocal.set(webClient = getNewWebClient(browserVersion));
		} else {
			logger.debug("線程 [ " + Thread.currentThread().getName() + " ] 已有WebClient實例,直接使用. . .");
		}
		return webClient;
	}

	/**
	 * 獲取一個模擬CHROME版本的WebClient實例
	 * 
	 * @return 模擬CHROME版本的WebClient實例
	 */
	public final WebClient getNewWebClient() {
		return getNewWebClient(BrowserVersion.CHROME);
	}

	/**
	 * 獲取一個模擬CHROME版本的WebClient實例
	 * 
	 * @return 模擬browserVersion版本的WebClient實例
	 */
	// public synchronized WebClient getClient() {
	public final WebClient getNewWebClient(final BrowserVersion browserVersion) {
		WebClient webClient = null;
		/**
		 * 如果當前線程已有WebClient實例,則直接返回該實例 否則重新創建一個WebClient實例并存儲于當前線程的本地變量存儲器
		 */
		if (browserVersion == BrowserVersion.CHROME) {
			BrowserVersion.CHROME.setBrowserLanguage("zh_CN");
		}
		webClient = new WebClient(browserVersion);
		WebClientOptions options = webClient.getOptions();
		// 設置代理
		// ProxyConfig proxyConfig = options.getProxyConfig();
		// proxyConfig.setProxyHost("116.199.115.78");
		// proxyConfig.setProxyPort(80);
		// DefaultCredentialsProvider credentialsProvider = (DefaultCredentialsProvider) webClient
		// .getCredentialsProvider();
		// credentialsProvider.addCredentials(proxy.getUser(), proxy.getPassword());
		webClient.setRefreshHandler(new ThreadedRefreshHandler());
		// 開啟cookie管理
		webClient.getCookieManager().setCookiesEnabled(true);
		// 設置webClient的相關參數
		webClient.setAjaxController(new NicelyResynchronizingAjaxController());
		options.setJavaScriptEnabled(true);
		options.setCssEnabled(false);
		// options.setTimeout(120000);
		options.setTimeout(0);
		// 防止js語法錯誤拋出異常,js運行錯誤時,是否拋出異常
		options.setThrowExceptionOnScriptError(false);
		options.setThrowExceptionOnFailingStatusCode(false);
		options.setRedirectEnabled(true);
		// 是否使用不安全的SSL
		options.setUseInsecureSSL(true);
		// 設置javascript執行時間超時
		// webClient.setJavaScriptTimeout(300000);
		// webClient.waitForBackgroundJavaScript(300000);
		webClient.setJavaScriptTimeout(0);
		webClient.waitForBackgroundJavaScript(0);
		logger.debug("為線程 [ " + Thread.currentThread().getName() + " ] 創建新的WebClient實例!");
		return webClient;
	}

	/**
	 * 關閉內存
	 * 
	 * @param webClient
	 *            參數
	 * @author 張軍
	 * @date 2015-11-03 21:59:00
	 * @modifiyNote
	 * @version 1.0
	 */
	public void close() {
		close(getWebClient());
	}

	/**
	 * 關閉內存
	 * 
	 * @param webClient
	 *            參數
	 * @author 張軍
	 * @date 2015-11-03 21:59:00
	 * @modifiyNote
	 * @version 1.0
	 */
	public void close(WebClient webClient) {
		if (webClient == null) {
			return;
		}
		// System.out.println("關閉前:" + webClient.getCache().getSize());
		webClient.getCurrentWindow().getJobManager().removeAllJobs();
		webClient.close();
		webClient = null;
		// System.out.println("關閉后:" + webClient);
		System.gc();
	}
}
package zj.parser.bean;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

import org.apache.log4j.Logger;

import com.gargoylesoftware.htmlunit.html.HtmlPage;

import zj.common.KV;
import zj.reflect.util.MethodUtil;

/**
 * 采集參數類
 * 
 * @author SHNKCS 張軍 {@link <a target=_blank href="http://www.shanghaijiadun.com">上海加盾信息科技有限公司</a>&nbsp;&nbsp;&nbsp;&nbsp;<a target=_blank href="http://m.eyofj.com">張軍個人網站</a>&nbsp;&nbsp;&nbsp;&nbsp;<a target=_blank href="http://user.qzone.qq.com/360901061/">張軍QQ空間</a>}
 * @date 2015-11-03 21:59:00
 * @modifiyNote
 * @version 1.0
 */
public class ParamBase {
	// 日志
	private Logger logger = Logger.getLogger(this.getClass());
	/**
	 * 參數
	 * 
	 * @author 張軍
	 * @date 2015-11-03 21:59:00
	 * @modifiyNote
	 * @version 1.0
	 */
	public Map<String, Object> params = new ConcurrentHashMap<>();
	/**
	 * 自定義首頁
	 * 
	 * @author 張軍
	 * @date 2015-11-03 21:59:00
	 * @modifiyNote
	 * @version 1.0
	 */
	public HtmlPage rootPage;
	/**
	 * 等待回調時間,默認500毫秒
	 * 
	 * @author 張軍
	 * @date 2015-11-03 21:59:00
	 * @modifiyNote
	 * @version 1.0
	 */
	public long sleepCallback = 1000;
	/**
	 * 等待點擊下一頁加載頁面時間,默認500毫秒
	 * 
	 * @author 張軍
	 * @date 2015-11-03 21:59:00
	 * @modifiyNote
	 * @version 1.0
	 */
	public long sleepNextPageClick = 500;
	/**
	 * 名稱
	 * 
	 * @author 張軍
	 * @date 2015-11-03 21:59:00
	 * @modifiyNote
	 * @version 1.0
	 */
	public String name;
	/**
	 * 網址
	 * 
	 * @author 張軍
	 * @date 2015-11-03 21:59:00
	 * @modifiyNote
	 * @version 1.0
	 */
	public String homeUrl;
	/**
	 * 列表多個字段
	 * 
	 * @see// 三、設置多個字段List<Map<String,String>> @see// 1.key:字段,value:xxx @see// 2.key:字段名,value:xxx @see// 3.key:數據類型,value:(1:抓取文本、2:抓取元素的innerHtml、3:抓取元素的outerHtml、4:抓取元素的屬性值:屬性名)
	 * 
	 * @author 張軍
	 * @date 2015-11-03 21:59:00
	 * @modifiyNote
	 * @version 1.0
	 */
	public List<Map<String, String>> listFields = new ArrayList<>();
	/**
	 * 普通多個字段
	 * 
	 * @see// 三、設置多個字段List<Map<String,String>> @see// 1.key:字段,value:xxx @see// 2.key:字段名,value:xxx @see// 3.key:數據類型,value:(1:抓取文本、2:抓取元素的innerHtml、3:抓取元素的outerHtml、4:抓取元素的屬性值:屬性名)
	 * 
	 * @author 張軍
	 * @date 2015-11-03 21:59:00
	 * @modifiyNote
	 * @version 1.0
	 */
	public List<Map<String, String>> normalFields = new ArrayList<>();

	/**
	 * 添加開始html
	 * 
	 * @author 張軍
	 * @date 2015-11-03 21:59:00
	 * @modifiyNote
	 * @version 1.0
	 */
	public String startHtml;

	/**
	 * 添加結束html
	 * 
	 * @author 張軍
	 * @date 2015-11-03 21:59:00
	 * @modifiyNote
	 * @version 1.0
	 */
	public String endHtml;
	/**
	 * list地址 key:listXPath,value:nextPage
	 * 
	 * @author 張軍
	 * @date 2015-11-03 21:59:00
	 * @modifiyNote
	 * @version 1.0
	 */
	public List<KV<String, String>> listKV = new ArrayList<>();
	/**
	 * 臨時字段,列表多個字段 key:listXPath,value:listFields
	 * 
	 * @see// 三、設置多個字段List<Map<String,String>> @see// 1.key:字段,value:xxx @see// 2.key:字段名,value:xxx @see// 3.key:數據類型,value:(1:抓取文本、2:抓取元素的innerHtml、3:抓取元素的outerHtml、4:抓取元素的屬性值:屬性名)
	 * 
	 * @author 張軍
	 * @date 2015-11-03 21:59:00
	 * @modifiyNote
	 * @version 1.0
	 */
	public Map<String, List<Map<String, String>>> mapListFields = new HashMap<>();
	/**
	 * 列表當前頁(默認0頁)
	 * 
	 * @author 張軍
	 * @date 2015-11-03 21:59:00
	 * @modifiyNote
	 * @version 1.0
	 */
	public Integer pageCurrent = 0;

	// ==================================反射回調
	/**
	 * 普通抽取回調 key:類名,value:方法名
	 * 
	 * @author 張軍
	 * @date 2015-11-03 21:59:00
	 * @modifiyNote
	 * @version 1.0
	 */
	public KV<String, String> normalClassCallback;
	/**
	 * 列表抽取回調 key:類名,value:方法名
	 * 
	 * @author 張軍
	 * @date 2015-11-03 21:59:00
	 * @modifiyNote
	 * @version 1.0
	 */
	public KV<String, String> listClassCallback;

	/**
	 * rootPage回調修改
	 * 
	 * @param param
	 *            當前參數
	 * @author 張軍
	 * @date 2015-11-03 21:59:00
	 * @modifiyNote
	 * @version 1.0
	 */
	public HtmlPage updateRootPage(HtmlPage rootPage) {
		return rootPage;
	}

	/**
	 * 單頁面回調地址(默認不實現)
	 * 
	 * @param pageFieldValues
	 *            一頁的數據
	 * @author 張軍
	 * @date 2015-11-03 21:59:00
	 * @modifiyNote
	 * @version 1.0
	 */
	public void callBack(Map<String, Object> pageFieldValues) {
		if (normalClassCallback != null) {
			try {
				MethodUtil.invoke(Class.forName(normalClassCallback.getK()).newInstance(), normalClassCallback.getV(), new Object[] { this, pageFieldValues }, true);
			} catch (Exception e) {
				logger.error("單頁面回調出錯", e);
			}
		}
	}

	/**
	 * 列表或表格采集回調地址(默認不實現)
	 * 
	 * @param listXPath
	 *            集合表達式
	 * @param pageFieldValues
	 *            一頁的數據
	 * @author 張軍
	 * @date 2015-11-03 21:59:00
	 * @modifiyNote
	 * @version 1.0
	 */
	public void callBack(String listXPath, List<Map<String, Object>> pageFieldValues) {
		if (listClassCallback != null) {
			try {
				MethodUtil.invoke(Class.forName(listClassCallback.getK()).newInstance(), listClassCallback.getV(), new Object[] { this, listXPath, pageFieldValues }, true);
			} catch (Exception e) {
				logger.error("列表或表格采集回調出錯", e);
			}
		}
		// JJListCallBack callBack = new JJListCallBack();
		// callBack.callBack(this, listXPath, pageFieldValues);
	}

	/**
	 * 判斷翻頁是否完成
	 * 
	 * @param listXPath
	 *            集合表達式
	 * @param pageFieldValues
	 *            一頁的數據
	 * @author 張軍
	 * @date 2015-11-03 21:59:00
	 * @modifiyNote
	 * @version 1.0
	 */
	public void checkPageReadyState(HtmlPage rootPage) {
		// 有翻頁
		long st = System.currentTimeMillis();
		while (true) {
			if ("complete".equals(rootPage.getReadyState())) {
				break;
			} else {
				long et = System.currentTimeMillis();
				if (et - st > 10000) {
					break;
				}
			}
			try {
				Thread.sleep(1);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
	}

	/**
	 * 判斷翻頁是否完成
	 * 
	 * @param listXPath
	 *            集合表達式
	 * @param pageFieldValues
	 *            一頁的數據
	 * @author 張軍
	 * @date 2015-11-03 21:59:00
	 * @modifiyNote
	 * @version 1.0
	 */
	public HtmlPage nextPage(HtmlPage rootPage) {
		// 有翻頁
		return null;
	}

	// ==================================================
	/**
	 * 詳細頁面設置 key:字段名,value:詳細頁面對象
	 * 
	 * @author 張軍
	 * @date 2015-11-03 21:59:00
	 * @modifiyNote
	 * @version 1.0
	 */
	public KV<String, ParamBase> detailKV;
	/**
	 * 是否是詳細頁
	 * 
	 * @author 張軍
	 * @date 2015-11-03 21:59:00
	 * @modifiyNote
	 * @version 1.0
	 */
	public boolean isDetail;
	/**
	 * 當前數據對應的詳細頁面
	 * 
	 * @author 張軍
	 * @date 2015-11-03 21:59:00
	 * @modifiyNote
	 * @version 1.0
	 */
	public Map<String, Object> currentRangeValue;

	/**
	 * 臨時字段,當前頁(默認0頁)
	 * 
	 * @author 張軍
	 * @date 2015-11-03 21:59:00
	 * @modifiyNote
	 * @version 1.0
	 */
	public Integer tempPage = 0;
	/**
	 * 臨時字段,是否回調父類方法,默認回調
	 * 
	 * @author 張軍
	 * @date 2015-11-03 21:59:00
	 * @modifiyNote
	 * @version 1.0
	 */
	public boolean tempIsCallBack = true;

	/**
	 * 臨時字段,列表多個字段
	 * 
	 * @see// 三、設置多個字段List<Map<String,String>> @see// 1.key:字段,value:xxx @see// 2.key:字段名,value:xxx @see// 3.key:數據類型,value:(1:抓取文本、2:抓取元素的innerHtml、3:抓取元素的outerHtml、4:抓取元素的屬性值:屬性名)
	 * 
	 * @author 張軍
	 * @date 2015-11-03 21:59:00
	 * @modifiyNote
	 * @version 1.0
	 */
	public List<Map<String, String>> tempListFields = new ArrayList<>();

}
package zj.parser.bean;

import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

import com.gargoylesoftware.htmlunit.html.DomElement;
import com.gargoylesoftware.htmlunit.html.HtmlPage;

import zj.common.exception.ServiceException;
import zj.java.util.JavaUtil;
import zj.parser.util.HtmlTableParserUtil.IHtmlParserCall;
import zj.type.TypeUtil;

/**
 * html解析工具類接口
 * 
 * @author SHNKCS 張軍 {@link <a target=_blank href="http://www.shanghaijiadun.com">上海加盾信息科技有限公司</a>&nbsp;&nbsp;&nbsp;&nbsp;<a target=_blank href="http://m.eyofj.com">張軍個人網站</a>&nbsp;&nbsp;&nbsp;&nbsp;<a target=_blank href="http://user.qzone.qq.com/360901061/">張軍QQ空間</a>}
 * @date 2015-11-03 21:59:00
 * @modifiyNote
 * @version 1.0
 */
public class SimpleHtmlParser implements IHtmlParserCall {

	@Override
	public int pageCount(DomElement element) {
		// 直接獲取文本
		return TypeUtil.Primitive.intValue(element.asText());
	}

	@Override
	public String pageUrl(String url, int page) {
		// 默認直接替換
		return MessageFormat.format(url, page);
	}

	@Override
	public DomElement titleDomElement(DomElement element) {
		// 默認當前對象
		return element;
	}

	@Override
	public String title(DomElement element) {
		// 直接獲取文本
		return JavaUtil.objToStr(element.asText());
	}

	@Override
	public String titleHref(DomElement element) {
		// 直接獲取href文本
		return element.getAttribute("href");
	}

	@Override
	public String content(HtmlPage page, String xpathContent) {
		try {
			// 默認的讀取
			List<?> titleContents = page.getByXPath(xpathContent);
			DomElement titleContentEle = (DomElement) titleContents.get(0);
			// 獲取文章內容數據
			return titleContentEle.asXml();
		} catch (Exception e) {
			throw new ServiceException(e);
		}
	}

	/* (non-Javadoc)
	 * @see zj.parser.util.HtmlTableParserUtil.IHtmlParserCall#getTasks()
	 */
	@Override
	public List<String> getTasks() {
		return new ArrayList<String>();
	}

	/* (non-Javadoc)
	 * @see zj.parser.util.HtmlTableParserUtil.IHtmlParserCall#callResult(java.util.Map)
	 */
	@Override
	public boolean callResult(Map<String, Object> result) {
		//默認添加至results
		return true;
	}

}
package zj.parser.bean;

import org.apache.log4j.Logger;

import com.gargoylesoftware.htmlunit.BrowserVersion;
import com.gargoylesoftware.htmlunit.NicelyResynchronizingAjaxController;
import com.gargoylesoftware.htmlunit.ThreadedRefreshHandler;
import com.gargoylesoftware.htmlunit.WebClient;
import com.gargoylesoftware.htmlunit.WebClientOptions;

/**
 * webClient工廠<br>
 * 
 * @version 1.00 (2011.12.02)
 * @author SHNKCS 張軍 {@link <a href="http://user.qzone.qq.com/360901061/">張軍QQ空間</a>}
 */
public class ZjWebClient {
	private transient static final Logger logger = Logger.getLogger(ZjWebClient.class);

	public ZjWebClient() {
		this(BrowserVersion.CHROME);
	}

	public ZjWebClient(final BrowserVersion browserVersion) {
		if (browserVersion == BrowserVersion.CHROME) {
			BrowserVersion.CHROME.setBrowserLanguage("zh_CN");
		}
		webClient = new WebClient(browserVersion);
		/**
		 * 如果當前線程已有WebClient實例,則直接返回該實例 否則重新創建一個WebClient實例并存儲于當前線程的本地變量存儲器
		 */
		WebClientOptions options = webClient.getOptions();
		// 設置代理
		// ProxyConfig proxyConfig = options.getProxyConfig();
		// proxyConfig.setProxyHost("116.199.115.78");
		// proxyConfig.setProxyPort(80);
		// DefaultCredentialsProvider credentialsProvider = (DefaultCredentialsProvider) webClient
		// .getCredentialsProvider();
		// credentialsProvider.addCredentials(proxy.getUser(), proxy.getPassword());
		webClient.setRefreshHandler(new ThreadedRefreshHandler());
		// 設置webClient的相關參數
		webClient.setAjaxController(new NicelyResynchronizingAjaxController());
		options.setJavaScriptEnabled(true);
		options.setCssEnabled(false);
		// options.setTimeout(120000);
		options.setTimeout(0);
		// 防止js語法錯誤拋出異常,js運行錯誤時,是否拋出異常
		options.setThrowExceptionOnScriptError(false);
		options.setThrowExceptionOnFailingStatusCode(false);
		options.setRedirectEnabled(true);
		// 是否使用不安全的SSL
		options.setUseInsecureSSL(true);
		// 設置javascript執行時間超時
		// webClient.setJavaScriptTimeout(300000);
		// webClient.waitForBackgroundJavaScript(300000);
		webClient.setJavaScriptTimeout(0);
		webClient.waitForBackgroundJavaScript(0);
		logger.debug("為線程 [ " + Thread.currentThread().getName() + " ] 創建新的WebClient實例!");
	}

	/**
	 * 關閉內存
	 * 
	 * @param webClient
	 *            參數
	 * @author 張軍
	 * @date 2015-11-03 21:59:00
	 * @modifiyNote
	 * @version 1.0
	 */
	public void close() {
		if (webClient == null) {
			return;
		}
		// System.out.println("關閉前:" + webClient.getCache().getSize());
		webClient.getCurrentWindow().getJobManager().removeAllJobs();
		webClient.close();
		webClient = null;
		// System.out.println("關閉后:" + webClient);
		System.gc();
	}

	private WebClient webClient;

	/**
	 * 獲取實例
	 * 
	 * @author 張軍
	 * @date 2017年12月9日 下午3:40:11
	 * @version V1.0
	 * @return the webClient
	 */
	public WebClient getWebClient() {
		return webClient;
	}

}



更多文章、技術交流、商務合作、聯系博主

微信掃碼或搜索:z360901061

微信掃一掃加我為好友

QQ號聯系: 360901061

您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點擊下面給點支持吧,站長非常感激您!手機微信長按不能支付解決辦法:請將微信支付二維碼保存到相冊,切換到微信,然后點擊微信右上角掃一掃功能,選擇支付二維碼完成支付。

【本文對您有幫助就好】

您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描上面二維碼支持博主2元、5元、10元、自定義金額等您想捐的金額吧,站長會非常 感謝您的哦?。?!

發表我的評論
最新評論 總共0條評論
主站蜘蛛池模板: 国产美女一级高清免费观看 | 香蕉国产人午夜视频在线 | 久久精彩视频 | 欧美一区二区三区在线观看 | 国产高清视频青青青在线 | 成人影院高清在线观看免费网站 | 日本黄页网站在线观看 | 国内精品视频成人一区二区 | 在线观看 中文字幕 | 中文一区二区 | 国产 福利 在线 | 国产96福利视频在线观看 | 国产欧美日韩高清专区手机版 | 成人不卡视频 | 性感美女香蕉视频 | 精品日韩在线观看 | 国产极品嫩模大尺度福利视频 | 久久免费视频播放 | 国产成人成人一区二区 | 久久国产经典视频 | 亚洲短视频在线观看 | 久免费视频 | 欧美在线成人免费国产 | 99久久99久久精品国产 | 久久久久久久国产a∨ | 狠狠色噜噜狠狠狠狠色综合久 | 欧美一级人与动毛片免费播放 | 午夜日韩在线 | 国产综合91 | 亚洲国产精品成人午夜在线观看 | 亚洲国产欧美一区 | 激情综合网五月激情 | 成人精品一区二区三区校园激情 | 久久青| 婷婷在线成人免费观看搜索 | 中文福利视频 | 国产不卡在线观看 | 亚洲精品福利一区二区三区 | 国产婷婷综合在线视频中 | 国产成人免费在线 | 久久精品国产精品亚洲红杏 |