之前
之前利用Jsoup做了個(gè)小DEMO爬取百度免費(fèi)API(* http://apistore.baidu.com/ )潜支,很簡(jiǎn)單,用Jsoup就可以做到柿汛,因?yàn)轫?yè)面加載后的數(shù)據(jù)填充到html里面冗酿,此時(shí)查看源代碼會(huì)看見(jiàn)數(shù)據(jù)都在源代碼里面,這時(shí)候可以利用Jsoup爬取苛茂,前幾天有個(gè)需求要爬取天眼查的數(shù)據(jù)( http://www.tianyancha.com *)已烤,自以為和之前做的DEMO一樣,不難妓羊,就利用原來(lái)的DEMO改改,之后居然獲取不到想要的稍计。
需求:搜索(條件包括搜索框躁绸,注冊(cè)資本,地區(qū))
以下是我將要爬取的頁(yè)面:
搜索:有限
習(xí)慣性審查一下要爬取的元素:
胸有成竹代碼就出來(lái):
Document doc = Jsoup.connect("http://www.tianyancha.com/search?key=有限").ignoreHttpErrors(true).timeout(100000).get();
System.out.println(doc.body());
執(zhí)行--》
<body ng-class="isFromMac ? '':'windows-modal'">
<!-- <body class="b-c13" ng-class="{'windows-modal':!isFromMac, 'bodyOverHidden':bodyHidden, 'bodyOverShow':!bodyHidden}"> -->
<div id="loading" class="loading" loading=""></div>
<div id="ng-view" ng-view=""></div>
<!-- banner -->
<div ng-cloak="" ng-controller="bannerCtrl">
<!-- ![](http://static.tianyancha.com/wap/images/element.png?_v=)</img> -->
<div ng-cloak="" ng-if="isPCClient" class="bottom-banner">
<!-- <div class="bottom-banner-body" ng-show="showBanner" >
![app下載](http://upload-images.jianshu.io/upload_images/3810137-5c0f1e424921f6e4.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
<div class="bottom-banner-qrcode" >
<img class="bottom-banner-qrcode-img" alt="qrcode"
src="http://static.tianyancha.com/wap/images/banner-bottom-qrcode.png">
</div>
<img class="bottom-banner-close" alt="close"
ng-click="ctrlBanner(false);"
src="http://static.tianyancha.com/wap/images/banner-bottom-close.png">
</div> -->
<div class="bottom-banner-body2" ng-if="showBanner">
<div class="bottom-banner-box2 company_container">
![](http://upload-images.jianshu.io/upload_images/3810137-a12c9c8e1c375522.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
<div class="code_box">
![](http://upload-images.jianshu.io/upload_images/3810137-e7840a271fd37e8e.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
</div>
![](http://upload-images.jianshu.io/upload_images/3810137-2dc1551260095554.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
![](http://upload-images.jianshu.io/upload_images/3810137-2f8c0c671b889cd0.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
</div>
</div>
![app下載](http://upload-images.jianshu.io/upload_images/3810137-41c6fa56e3e5e7e5.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
<!-- <div ng-show="showAdvertise" advertise-banner></div> -->
</div>
<div ng-show="!isPCClient&&!isTYCClient&&!isWebAppClient">
<div ng-cloak="" ng-show="!showBannerMobile" style="position: fixed;left: 0;bottom:90px;" ng-click="closeClick(showBannerMobile);">
![下載天眼查專(zhuān)業(yè)版APP](http://upload-images.jianshu.io/upload_images/3810137-93ed2e33708d2d46.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
</div>
<div class="bottom-banner-mobile" ng-cloak="" ng-show="showBannerMobile">
![下載天眼查專(zhuān)業(yè)版APP](http://upload-images.jianshu.io/upload_images/3810137-0726860681c21931.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
![下載天眼查專(zhuān)業(yè)版APP](http://upload-images.jianshu.io/upload_images/3810137-fd3b233ccd8b1c0a.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
<span> <a target="_blank"> ![下載天眼查專(zhuān)業(yè)版APP](http://upload-images.jianshu.io/upload_images/3810137-d73cd12dbd35be37.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) </a> </span>
![關(guān)閉](http://upload-images.jianshu.io/upload_images/3810137-f2a78be96ebe8a57.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
</div>
</div>
</div>
<script>var gdt_tracker=gdt_tracker||[];gdt_tracker.push(["set_source_id","33937"]);!function(){var e=navigator.userAgent;if(e.indexOf("ignore")<0){var t=document,r=t.getElementsByTagName("head")[0],a=t.createElement("script");a.async=!0;a.src="http://qzs.qq.com/qzone/biz/res/gt.js";r&&r.insertBefore(a,r.firstChild)}}();</script>
<script>var _hmt=_hmt||[];!function(){var e=navigator.userAgent;if(e.indexOf("ignore")<0){var t=document.createElement("script");t.src="http://#/hm.js?e92c8d65d92d534b0fc290df538b4758";var r=document.getElementsByTagName("script")[0];r.parentNode.insertBefore(t,r)}}();</script>
<!-- <script>var _hmt=_hmt||[];!function(){var e=document.createElement("script");e.src="http://#/hm.js?9c350b9e33b321dffebc9cc49db07828";var t=document.getElementsByTagName("script")[0];t.parentNode.insertBefore(e,t)}();</script> -->
<!-- Piwik -->
<script type="text/javascript">var _paq=_paq||[];_paq.push(["trackPageView"]);_paq.push(["enableLinkTracking",!0]);!function(){var e="http://www.tianyancha.com/piwik/";_paq.push(["setTrackerUrl",e+"piwik.php"]);_paq.push(["setSiteId",1]);var a=document,p=a.createElement("script"),t=a.getElementsByTagName("script")[0];p.type="text/javascript";p.async=!0;p.defer=!0;p.src=e+"piwik.js";t.parentNode.insertBefore(p,t)}();</script>
<noscript>
<p>[站外圖片上傳中……(13)]</p>
</noscript>
<!-- End Piwik Code -->
<!--<script src="http://api.map.baidu.com/api?v=2.0&ak=E1r6u1CD9SzZ08IxP32bNjgz"></script>-->
<!--coolie@1.0.8-->
</body>
WTF臣嚣?
只有這點(diǎn)東西净刮?明明我審查元素的時(shí)候有那么多?為什么抓取出來(lái)就這么點(diǎn)硅则?這不科學(xué)淹父。
爬取的2個(gè)辦法:
- 利用Jsoup爬取
- 利用Ajax請(qǐng)求返回的數(shù)據(jù)
其一不行,取其二
通過(guò)Ajax請(qǐng)求數(shù)據(jù)怎虫,再填充到body里面暑认,于是研究Ajax請(qǐng)求,通過(guò)Chrome的NetWork可以抓到:
這個(gè)接口返回的就是列表的數(shù)據(jù)大审,欣喜若狂蘸际,這也太簡(jiǎn)單了,雙擊訪問(wèn)出現(xiàn):
WTF2
這徒扶。粮彤。到底是咋回事
在搜索了很多文章后發(fā)現(xiàn),這個(gè)網(wǎng)站本來(lái)就是從各大政府網(wǎng)站爬取過(guò)來(lái)的數(shù)據(jù)姜骡,哪能那么容易就輕松被別人爬取走导坟。況且:
失望中另辟蹊徑
失望中又想到另外的辦法,既然不能通過(guò)Jsoup去爬取圈澈,那么是不是有方法可以模擬人為訪問(wèn)惫周,訪問(wèn)后加載完所有的css和js,等數(shù)據(jù)都返回士败,再爬取闯两,這不就可以了褥伴。
開(kāi)啟搜索引擎一陣搜:
-
HtmlUnit
(https://my.oschina.net/MiniBu/blog/140729) -
WebDriver
(https://my.oschina.net/dyhunter/blog/94090)
以上方法都是做自動(dòng)化測(cè)試用的,根本不是用來(lái)爬取數(shù)據(jù)的漾狼,所以兼容性不能不是很好重慢。各種嘗試都沒(méi)有得到想要的效果。
最后發(fā)現(xiàn)了phantomjs
( http://phantomjs.org/ )逊躁。
下載phantomjs后終端就行似踱,加入環(huán)境變量自行百度,此處不再多說(shuō)稽煤。
windows下載對(duì)應(yīng)的phantomjs.exe
運(yùn)行:
/User/music-man/Downloads/phantomjs/phantomjs /User/music-man/Downloads/phantomjs/code.js http://www.tianyancha.com/search?key=有限
注意中間的空格核芽。第一個(gè)是phantomjs,第二個(gè)是code.js的路徑酵熙,第三個(gè)是爬取的路徑轧简。
code.js
system = require('system')
address = system.args[1];
var page = require('webpage').create();
var url = address;
page.open(url, function (status) {
//Page is loaded!
if (status !== 'success') {
console.log('Unable to post!');
} else {
console.log(page.content);
phantom.exit();
}
});
此時(shí)終端執(zhí)行命令,發(fā)現(xiàn)整個(gè)頁(yè)面已經(jīng)爬取下來(lái)匾二。
接下來(lái)就是如何與Java結(jié)合了哮独。
執(zhí)行命令Java可以這么做
Runtime rt = Runtime.getRuntime();
String exec = "/Users/music-man/Downloads/phantomjs/phantomjs /Users/music-man/Downloads/phantomjs/code.js " + url;
Process p = rt.exec(exec);
InputStream is = p.getInputStream();
這樣就可以獲得輸入流了,獲得輸入流之后想要怎么操作就簡(jiǎn)單了吧察藐。
獲取了文件流皮璧,想操作dom,如何操作呢分飞?
看了一下Jsoup悴务,發(fā)現(xiàn)
public static Document parse(InputStream in, String charsetName, String baseUri)
第一個(gè)參數(shù)是輸入流,第二個(gè)是字符集譬猫,第三個(gè)是地址:
Document doc = Jsoup.parse(is, "UTF-8", url);
獲取到Document再操作dom元素就很明了了讯檐。
最后用JFrame做了個(gè)界面
不穩(wěn)定
執(zhí)行起來(lái)發(fā)現(xiàn)不穩(wěn)定,有時(shí)候能爬取到頁(yè)面删窒,有時(shí)候就會(huì)失敗裂垦,讓我以為是網(wǎng)站做的限制,后來(lái)發(fā)現(xiàn)多次重復(fù)爬取效率過(guò)快的話網(wǎng)站會(huì)讓輸入驗(yàn)證碼肌索,導(dǎo)致卡住蕉拢。
解決
爬取不到我初步懷疑是因?yàn)榕廊〉臅r(shí)候頁(yè)面還沒(méi)加載完畢,就進(jìn)行抓取诚亚,有時(shí)候網(wǎng)速快晕换,加載好了就能抓取到,有時(shí)候沒(méi)有加載好站宗,爬取失敗闸准。看了下phantomjs例子
(https://github.com/ariya/phantomjs/blob/master/examples/page_events.js)
發(fā)現(xiàn)可以采用js的方法setTimeout
最終code.js改為
system = require('system')
address = system.args[1];
var page = require('webpage').create();
var url = address;
page.open(url, function (status) {
//Page is loaded!
if (status !== 'success') {
console.log('Unable to post!');
} else {
window.setTimeout(function () {
page.render("test1.png"); //截圖
console.log(page.content);
phantom.exit();
}, 5000);
}
});
增加了setTimeout方法后梢灭,等待5s差不多執(zhí)行完頁(yè)面和js夷家,此時(shí)再去抓取頁(yè)面蒸其,發(fā)現(xiàn)成功率大大提高。
(2017年12月05日 刪除圖片库快,泄漏隱私了)
抓取到后再把需要的寫(xiě)出文件就可以了摸袁。