1. 程式人生 > >利用Fiddler手機抓包對ONE·APP網頁爬蟲實現電影資訊微信Java開發

利用Fiddler手機抓包對ONE·APP網頁爬蟲實現電影資訊微信Java開發

前言

好久沒寫部落格了,打算把之前做的一個電影評分資訊推送的微信開發全程記錄一下,適合對網路爬蟲、微信開發感興趣的童鞋。在教程開始之前,我想先引出兩個問題(這次寫部落格假裝很有條理的樣子= =)

1. 為什麼想要抓取ONE電影的資料?

因為我平時本身就喜歡去電影院看電影,所以關注到ONE·APP有電影欄目,而且評分資訊一目瞭然,非常適合我這種人,該看哪一部你懂的~(PS:這是寫部落格當天截的圖,下週末去看82分機器貓,嘿嘿)

ONE電影評分手機截圖

當然了,豆瓣電影也有評分,但是感覺那裡水軍很多,所以資料參考價值不大吧。順便普及一下,“一個”APP是由韓寒創立的,最初只有文學欄目,2016年初才進軍電影行業(

相關報道),目的就是讓電影打分少一點套路,多一分真誠,用心良苦呀,所以我們就用收下韓寒這份好意吧!

2. 我需要提前準備什麼東西?

  • 首先,你得有一臺手機(你是不是傻?請忽略這條),如果16g蘋果沒記憶體可用安卓模擬器代替。。。(沒有別的意思…)
  • 其次,你得有java網路爬蟲相關知識,主要是httpclient的使用,解析JSON用的是效率較高的jackson。
  • 最後,你得有微信java開發經驗,主要解決資料呈現問題,當然你也可以使用僅用的JAVA EE知識做一個網頁來呈現資料。因為不能面面俱到,所以此教程可能不會過多講解這一塊內容,這裡推薦慕課網視訊教程,建議直奔重點看第五章,十分受用。

對了,先放個圖,看下微信開發的功能最終效果,噔噔噔噔~↓

電影功能截圖

還是像模像樣的,前面bb了那麼多,下面開始我們的教程吧!

思路

1. 抓取資料(Fidder抓包,手機wifi代理)

2. 分析資料(解析JSON/HTML,提取有用資訊)

3. 微信開發(文字訊息匹配、被動回覆圖文)

基本思路是對資料的抓取→分析→處理→呈現,下面以ONE·APP的電影資料為例,本教程會把重點放在前面兩part。

實戰

1. 抓取資料

前期準備

  1. 下載抓包工具Fiddler:大家到網上去下載就好了,我這裡用的是V4.6

  2. 設定Fiddler規則(關鍵):點Tools->Fiddler Options->HTTPS

    ,勾選Capture HTTPS CONNECTsDecrypt HTTPS traffic這兩項,建議勾上ignore server certificate erros (unsafe)保證我們抓包時候不會狂彈窗而影響心情;切換到Connections選項卡,再勾選allow remote computers to connect這項,記住這裡出現的Fiddler listens on port埠號是8888(當然這裡可以自己改成別的,但是建議不要這樣做),之後會用到它。
    Fiddler設定1
    Fiddler設定2
    設定完必須重啟Fiddler

  3. 搭建網路環境:使電腦和手機在同一個區域網下,這個為之後的手機wifi代理做準備。

  4. 檢視電腦內網IP:在命令列輸入ipconfig檢視內網IP,我這裡查到是192.168.2.106,先記住,下面會用到。
    電腦內網IP

  5. 設定手機wifi代理(關鍵):不用手機可能有點不一樣,我這裡以我的安卓小錘子來做示範。設定->無線網路->已連線的網路詳細->高階設定,開啟手動HTTP代理,填寫代理伺服器主機名為電腦內網IP 192.168.2.106,以及代理伺服器埠為Fiddler顯示的8888。其他系統和型號的手機自己琢磨下吧~
    手機wifi代理設定

  6. 手機下載“一個”APP:在各大手機應用市場搜尋一個ONE韓寒均可下載。

下面開始才是重點

  1. 手機開啟“一個”APP,在抓包之前先清理Fiddler剛剛的抓取到的包,方便我們等下篩選。
    清除Fiddler所有的包

  2. 點開“電影”欄目,觀察Fiddler的抓包情況。到這裡你已經成功了一半了,host為wufazhuce.com正是“一個”的域名,而且url為/api/movie/list/0?(這很restful…),可以確定是我們想要的那個請求。
    (但是在實際抓包中,往往會有各種各樣的無用資訊摻雜在裡面,這時候就需要我們去辨別哪些是我們想要的url)
    電影請求
    我們通過直接訪問剛剛抓取到的url:http://v3.wufazhuce.com:8000/api/movie/list/0?,打開發現返回的是json格式的資料,正是我們想要的。到此為止,我們的抓取資料part已經完成了,應該不困難吧= =
    電影列表返回資料

沒有抓取到包可能出現的原因

  1. 電腦和手機不在同一個區域網內
  2. Fiddler設定不對
  3. 手機wifi沒有代理成功,可能是填寫有誤,也可能是手機系統問題
  4. 最有可能的是我之前遇到的問題:設定完代理後,要先關閉APP,再重新開啟
  5. 人品問題,自行百度,也歡迎留言哈~

更多API分享

  1. 電影詳情:http://v3.wufazhuce.com:8000/api/movie/detail/ID

  2. 首頁電影故事:http://v3.wufazhuce.com:8000/api/movie/ID/story/1/0

  3. 全部電影故事:http://v3.wufazhuce.com:8000/api/movie/ID/story/0/0

  4. 熱門評論(點贊數) http://v3.wufazhuce.com:8000/api/comment/praise/movie/ID/0

  5. 全部評論(發表時間) http://v3.wufazhuce.com:8000/api/comment/time/movie/ID/0

注意:所有URL中的ID替換為實際的電影ID即可,最後以為引數0所代表的含義代表下標ID,在下文中會提及到,預設寫0。

2.分析資料

  1. 我們選擇那條請求,檢視軟體右邊的請求詳細分析,由於我們事先知道請求返回資料型別是json,所以我們點Inspectors選項卡下的JSON選項卡,如下圖。
    電影請求詳細分析

  2. 我們把有用的資訊記錄下來,很有必要。
    請求方式&地址:GET http://v3.wufazhuce.com:8000/api/movie/list/0
    備註:url中的最後一個引數代表電影ID下標,用於分頁功能,假如你第一頁最後一個電影記錄的ID是84,那麼你再次請求地址http://v3.wufazhuce.com:8000/api/movie/list/84,得到的資料就是從85開始,也就是下一頁電影的資料。這裡要靠大家軟體開發的經驗以及親手嘗試過才知道,聽不懂也沒關係,這一個引數不足以影響我們的開發。你只要知道預設是0,獲取最新的電影資料就行了。
    json返回部分有用資料

    {
      "res": 0,
      "data": [
        {
          "id": "103",
          "title": "哆啦A夢:新·大雄的日本誕生",
          "score": "82",
          "cover": "http://image.wufazhuce.com/FsaiDxnewphDWZvTn021Si22ZaMv"
        }
      ]
    }
    引數 型別 說明
    res int 返回碼:0-成功,1-失敗
    data array 資料集合
      id
    int 電影ID,唯一標識
      title
    string 電影名
      score
    int 評分
      cover
    string 封面地址

當然了,這種是json資料格式的分析過程,這個跟過程跟你得業務有關,而我只需要實現一開始所呈現的那種圖片效果,以上這些資料就夠了。使用jackson來解析資料。

如果返回的資料是xml格式,也很好辦,跟json差不多,使用xstream解析。

如果返回的資料是帶檢視模型(也就是有頁面的),那就要用瀏覽器審查元素或者檢視原始碼,細心觀察需要爬取的資料都在哪些div裡面,觀察它或者它的父元素是否有什麼標誌性的id甚至是class,這樣就能通過jsoup解析它們。網頁爬蟲可以參考我上一篇爬蟲文章《基於WebMagic寫的一個csdn部落格小爬蟲》,框架裡面用到的就是強大的jsoup。

資料分析完後,接下來就是真正的coding了!

3.微信開發

  1. 新增maven依賴maven配置視訊,或者手動下載jar包)

    <!-- HttpClient -->
    <dependency>
        <groupId>org.apache.httpcomponents</groupId>
        <artifactId>httpclient</artifactId>
        <version>4.3.6</version>
    </dependency>
    <dependency>
        <groupId>org.apache.httpcomponents</groupId>
        <artifactId>httpmime</artifactId>
        <version>4.3.6</version>
    </dependency>
    <!-- JSON -->
    <dependency>
        <groupId>org.codehaus.jackson</groupId>
        <artifactId>jackson-mapper-asl</artifactId>
        <version>1.9.13</version>
    </dependency>
    <!-- XML -->
    <dependency>
        <groupId>com.thoughtworks.xstream</groupId>
        <artifactId>xstream</artifactId>
        <version>1.4.7</version>
    </dependency>
    <!-- HTML -->
    <dependency>
        <groupId>org.jsoup</groupId>
        <artifactId>jsoup</artifactId>
        <version>1.9.2</version>
    </dependency>
    <!-- IO -->
    <dependency>
        <groupId>commons-io</groupId>
        <artifactId>commons-io</artifactId>
        <version>2.4</version>
    </dependency>
  2. 新增wx-tools.jar(我一個室友寫的框架,下載jar包,檢視官方文件,3分鐘上手教程
    當然了,如果嫌麻煩你可以不使用任何的微信後臺框架,如果沒學習過微信java開發的請移步到慕課網視訊教程,直奔重點看第五章。

  3. 編寫爬蟲業務(重點)

    package com.soecode.xfshxzs.service;
    
    /**
     * 電影爬蟲業務
     */
    public class MovieService {
    
        // 電影列表URL
        private static final String MOVIE_LIST_URL = "http://v3.wufazhuce.com:8000/api/movie/list/0";
    
        /**
         * 獲取電影列表
         * 
         * @return
         */
        public List<Movie> getMovieList() {
            List<Movie> list = new ArrayList<Movie>();
            try {
                String json = HttpUitl.doGet(MOVIE_LIST_URL);
                ObjectMapper mapper = new ObjectMapper();
                JsonNode root = mapper.readTree(json);
                JsonNode data = root.path("data");
                if (data.isArray()) {
                    for (JsonNode node : data) {
                        Movie movie = mapper.readValue(node, Movie.class);
                        list.add(movie);
                    }
                }
            } catch (ClientProtocolException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            }
            return list;
        }
    
    }

    自己寫的一個HTTP工具類,擁有doGet方法,實現了傳入一個url,輸出網頁字串文字。

    package com.soecode.xfshxzs.util;
    
    /**
     * HTTP工具類
     */
    public class HttpUitl {
    
        /**
         * 普通GET請求
         * 
         * @param uri
         * @return
         * @throws IOException
         * @throws ClientProtocolException
         */
        public static String doGet(String uri) throws ClientProtocolException, IOException {
            String html = null;
            CloseableHttpClient httpClient = HttpClients.createDefault();
            HttpGet httpGet = new HttpGet(uri);
            CloseableHttpResponse response = httpClient.execute(httpGet);
            HttpEntity entity = response.getEntity();
            if (entity != null) {
                html = EntityUtils.toString(entity);
                EntityUtils.consume(entity);
            }
            httpGet.releaseConnection();
            response.close();
            return html;
        }
    
    }
  4. 編寫處理器:呼叫業務方法,實現星星效果,裝配圖文訊息,傳送給使用者

    package com.soecode.xfshxzs.handler;
    
    /**
     * 電影訊息處理器
     */
    public class MovieMessageHandler implements WxMessageHandler {
    
        private MovieService movieService = new MovieService();
    
        public WxXmlOutMessage handle(WxXmlMessage wxMessage, Map<String, Object> context, WxService wxService)
                throws WxErrorException {
            String content = wxMessage.getContent();
            List<Movie> list = movieService.getMovieList();
            for (int i = 0; i < 8; i++) {
                Item item = new Item();
                item.setTitle(movieDetail.getScore() + "分 " + createStarsByScore(movieDetail.getScore()) + " | "
                        + movieDetail.getTitle());
                item.setPicUrl(movieDetail.getDetailcover());
                builder.addArticle(item);
            }
            return WxXmlOutMessage.NEWS().toUser(wxMessage.getFromUserName()).fromUser(wxMessage.getToUserName()).build();
        }
    
        /**
         * 根據分數建立星星
         * 
         * @param score
         * @return
         */
        private String createStarsByScore(int score) {
            String stars = "";
            int solidStarsNum = Math.floorDiv(score + 10, 20);
            for (int i = 0; i < solidStarsNum; i++) {
                stars += "★";
            }
            int hollowStarsNum = 5 - solidStarsNum;
            for (int i = 0; i < hollowStarsNum; i++) {
                stars += "☆";
            }
            return stars;
        }
    
    }
    
  5. 新建攔截規則:匹配文字類訊息“電影”,看不懂也沒關係,真的沒關係= =

    router.rule().async(false).msgType(WxConsts.XML_MSG_TEXT).rContent("電影").handler(new MovieMessageHandler()).end();
  6. 剩下就是微信伺服器驗證了,在開發過程中我們應該本地除錯過才放到自己伺服器上,之前使用的內網對映(穿透)工具ngrok(懷念一下)不知道何時用不了了,所以一直在用很不穩定的花生殼,大家自己選擇吧。到此為止,我們的教程已經順利完成了,此處應有掌聲,啪啪啪啪~

要原始碼請繼續往下看↓

後記

教程中只涉及到了電影資訊的爬蟲,還有查天氣、查快遞等更多功能請關注公眾號盡情調戲(好像有BUG?),僅作為一個DEMO參考。放二維碼目的不是為了增粉啊,真的不是啊,只是想演示以上教程,趕緊掃吧~

小鋒生活小助手微信公眾號二維碼

很感謝大家能夠看到這裡,你們的每一個閱讀量都是對我莫大的鼓勵!(如果能去github給個贊就更好啦~嘻嘻~)

哦對了,說到電影,我要順便給你們一點福(an)利,以下是我的電影日常= =。
男神福利:如何低價購買電影票?(知乎網友攻略
宅男福利高清控聯盟(專注高清藍光)

凌晨了,要睡覺了,又寫到這麼晚= = 以後不能再這樣了!!
在接下來的大學裡最後一個暑假,我要好好看完剛從圖書館裡借來的兩本書,加油!fighting!!