HtmlUnit 網絡爬蟲 菜鳥的學習筆記(二)

此次我以爬新浪微博爲例,這個過程太糾結了,參考了好多大神的帖子,不過仍是遺留了不少問題,咱們慢慢來看,但願大神幫於指正,個人方法暫時來講仍是比較挫的php

        登錄問題html

        爬新浪微博首先要登錄,以前爬的妹紙網站,因爲不用登錄,因此沒這一步,可是爬新浪微博咱們必需要先登陸,可是要涉及到一個問題,那就是驗證碼,驗證碼從我如今百度到的,和本身的理解,感受暫時仍是不能解決的,除非手工輸入,由於自己驗證碼就是防止惡意登錄,防爬蟲的,因此建議想試試的朋友用暫時用不輸入驗證碼的帳號試試(關於驗證碼,期盼大神能夠給些提示web

        下面是demo代碼json

WebClient webClient = new WebClient();
webClient.getOptions().setJavaScriptEnabled(true);
webClient.getOptions().setCssEnabled(false);
webClient.setAjaxController(new NicelyResynchronizingAjaxController());
webClient.getOptions().setThrowExceptionOnScriptError(false);

HtmlPage htmlPage = null;

try {
    htmlPage = webClient.getPage("http://login.sina.com.cn/sso/login.php?client=ssologin.js(v1.4.18)");
    HtmlInput username = (HtmlInput) htmlPage.getElementsByName("username").get(0);
    HtmlInput password = (HtmlInput) htmlPage.getElementsByName("password").get(0);

    HtmlInput btn = htmlPage.getFirstByXPath(".//*[@id='vForm']/div[3]/ul/li[6]/div[2]/input");

    username.setValueAttribute("****");
    password.setValueAttribute("****");
    btn.click();
} catch (IOException e) {
    e.printStackTrace();
}

            代碼和以前的差很少太多,多了一些參數設置,經過方法命名就應該能夠大致知道啥含義了,我就不過多解釋了,可是可能有人會問爲何webClient.getPage的url不是www.weibo.com 呢?由於若直接get那個www.weibo.com,獲得的html,debug看,全是一些js代碼,沒有任何登錄模塊而言,可見新浪的登錄模塊多半是腳本畫出來的,因此很差,而這個網站,我開始是參考之前一個大神寫的  http://blog.csdn.net/bob007/article/details/29589059 api

            這個網站打開實際上是新浪通行證的登錄頁面
瀏覽器

           

            開始我想爲啥是這個界面,因此後面用httpwatch看了一下經過www.weibo.com登錄的時候整個請求過程dom

             能夠看到,在輸入完密碼和帳號以後,咱們post的地址正是這個地址,也就是說,新浪微博的登錄內部應該是這樣的            工具

             1. 請求www.weibo.com 獲得登錄頁面,輸入完用戶密碼post

              2. 提交請求到新浪通行證,而後點擊登錄,完成登錄操做
學習

            咱們日常用的微博帳號,對於新浪而言,實際上是新浪通行證的一種,這樣也就好理解了

           

            咱們再回到htmlunit上,咱們獲取了新浪通行證的登錄頁面後(htmlpage對象),如何獲取到具體的用戶名和密碼的控件呢,這個你們能夠本身debug一下就很清楚了,而後用htmlpage.asXml()這個方法解讀一下這個頁面的各個元素,看一下就知道了

            而獲取登錄按鈕的方式也是直接參考以前那個大神裏的作法,用到了api是getFirstByXPath這個方法,這個裏的XPath語法就是w3c標準語法,能夠參考http://www.w3school.com.cn/xpath/學習一下,有了這個語法對於頁面的任何節點,只要稍加分析,基本均可以拿到的

            以後就簡單啦,獲取到了用戶名,密碼輸入框,還有提交按鈕,咱們最後三行代碼就是把用戶名和密碼set進去,而後點擊提交按鈕,這就完成了登錄操做,是否是感受到這個代碼邏輯就是和頁面操做同樣嘛,這也體現了模擬瀏覽器的描述了

            由於你如今已經登錄了,因此如今你就能夠瀏覽你的主頁和看你關注的人的微博啦

            可是你們這裏要注意一個很重要的問題,就是微博的展現方式,你們實際操做也能夠感受的到,展現微博時是這麼一個過程

            1. 展現一部分微博

            2. 滾動條向下滾動,刷出一部分新的微博

            3. 滾動幾回後,最後頁面底部出現分頁控件

            4. 點擊下一頁,又展現一部分微博,重複2-4的過程了

            因此我開始就遇到這樣的問題,我開始用下面的代碼請求個人主頁,而且打印出了個人微博,惋惜只有15條,由於個人滾動條沒有下拉,因此沒有請求到更多的微博

page3 = webClient.getPage("http://weibo.com/5622296819/profile?topnav=1&wvr=6");
List<HtmlDivision> htmlDivisions = (List<HtmlDivision>) page4.getByXPath("//div[@class='WB_text W_f14']");

for(i = 0; i < htmlDivisions.size(); i++) {
    System.out.println("第" + (counter++) + "條微博: "
                    + htmlDivisions.get(i).getTextContent().trim());
}

            因此我就開始了處處百度如何用htmlunit模擬滾動條滾動,找了好多,模擬這個下拉這個動做基本看無法搞(你們可能夠看看這個可憐的兄弟,14年就遇到這個問題了,他最後兩段說出了個人心聲 http://stackoverflow.com/questions/23491638/is-there-a-way-to-trigger-scroll-event-with-htmlunit-or-is-it-not-possible-at-al  )

            不過有人提出能夠模擬滾動條下拉這個請求,而不是模擬這個動做,好比這個大神http://blog.csdn.net/zhoujianfeng3/article/details/21395223 可是代碼仍是不全,我試着嘗試,並且他模擬的url是14年的,不報但願的試了一下,果真是不行的,可是他的想法仍是給我很大的啓發,我參照他的方式,經過httpwatch看了一下,如今的滾動下拉請求基本是這個樣子(這是我關注的一個帳號的微博,由於微博比較多,能夠用來練習抓)

            http://weibo.com/p/aj/v6/mblog/mbloglist?ajwvr=6&domain=100505&from=myfollow_all&pre_page=1&page=1&max_id=&end_id=3882220290581087&pagebar=0&filtered_min_id=&pl_name=Pl_Official_MyProfileFeed__22&id=1005051645851277&script_uri=/u/1645851277&feed_type=0&domain_op=100505&__rnd=1441077128511 

            通過幾回分析,注意其中的這兩個參數,page=1和pagebar=0,這個page就是當前這個分頁,而這個pagebar是滾動的那個序列,也就是繼續滾下去的話,page=1不變,pagebar要變爲1,若分頁的時候,page要變爲2(變爲相應頁數),而pagebar又要從0開始,按照以前說的那個微博展現的過程理解一下就不難了

            可是注意上面這個url是滾動的url,而點擊分頁又是另外一個,你們能夠本身用httpwatch看一下就知道了,這裏就不贅述

            說完分析思路,再說說作法

            這裏滾動下拉的請求,返回的是json數據,不是一個html頁面,因此就不能再用webClient.getPage了,你們要注意一下,而當前從我百度的來看,htmlunit還不能很好的解析json,因此這裏參考我以前說的大神的思路,用到了另外一個爬蟲工具JSoup,來解析,demo代碼以下

WebRequest requestOne = new WebRequest(new URL(url), HttpMethod.GET);
WebResponse jsonOne = webClient.loadWebResponse(requestOne);
JSONObject jsonObj = JSONObject.fromObject(jsonOne.getContentAsString());

String data = (String) jsonObj.get("data");

Document doc = Jsoup.parse(data);
Elements elementsTwo = doc.select("div[class=WB_text W_f14]");

for (int i = 0; i < elementsTwo.size(); i++) {
     Element element = elementsTwo.get(i);
     System.out.println("第" + (counter++) + "條微博: "
                    + elementsTwo.get(i).text());
}

            url就是分頁的url,這樣用HtmlUnit來構建一個Web的請求,而後獲取到json返回的結果,轉換爲JSONObject對象,再用JSoup來解析json的字符轉,這裏的doc.select後面參數的語法是CSSQuery語法,和Xpath差不太多,你們隨即可以百度一下,也是比較好理解的,最後打印一下全部的微博就能夠了

            差點忘了,這裏還須要增長新的依賴   

<!-- json begin -->
<dependency>
    <groupId>net.sf.json-lib</groupId>
    <artifactId>json-lib</artifactId>
    <classifier>jdk15</classifier>
    <version>2.2</version>
</dependency>
<!-- json end -->

<!-- jsoup begin -->
<dependency>
    <groupId>org.jsoup</groupId>
    <artifactId>jsoup</artifactId>
    <version>1.6.3</version>
</dependency>
<!-- jsoup end -->

            最後我是把這個微博帳號裏的微博5000多條微博,直接寫到一個文件裏了,算是完成了最基本的了,固然我知道這也只是爬蟲最基本的小demo,後面老大沒有給我分配其餘任務的時候,我會再繼續專研哈,但願大神們多指正

            

            其實這裏也只是給你們提供思路了,多多debug分析一下就行了,固然我這個辦法仍是屬於比較笨的,如有大神有更吊的方法,歡迎告訴我o(^▽^)o

相關文章
相關標籤/搜索