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> <a target=_blank href="http://m.eyofj.com">張軍個人網站</a> <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> <a target=_blank href="http://m.eyofj.com">張軍個人網站</a> <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> <a target=_blank href="http://m.eyofj.com">張軍個人網站</a> <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; } }
本文為張軍原創文章,轉載無需和我聯系,但請注明來自張軍的軍軍小站,個人博客http://m.eyofj.com
更多文章、技術交流、商務合作、聯系博主
微信掃碼或搜索:z360901061

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