1. 程式人生 > >基於JAVA解決淘寶爬蟲限制

基於JAVA解決淘寶爬蟲限制

不僅僅限於java

前言

以前做過淘客開發,那時候高傭api很少,高傭的辦法就是查詢商品模擬轉鏈為高傭,但是後來淘寶慢慢禁止了爬蟲一直彈驗證碼,後來我就利用驗證碼識別成功扛過那段日子,大批淘寶工具商釋出高傭介面,驗證碼識別也就沒有用了。本文說的並不是指怎麼利用影象去識別的技術,而是怎麼突破淘寶的介面限制讓爬蟲可以獲取資訊。

驗證碼識別

你可以去各大驗證碼的打碼平臺識別或者自己寫識別庫。
以後如果我有時間可能會搭建一下驗證碼識別的介面~再說吧

工具

Google瀏覽器,Fiddler代理工具,IDEA(程式碼編寫),驗證碼識別介面。

分析

  1. 當去模擬請求一個淘寶頁面的時候,如果過於頻繁會302轉向到類似如下介面
    在這裡插入圖片描述
  2. 分析一下提交的引數
    在這裡插入圖片描述
    可以看到checkcode 就是我們輸入的數字,如果輸入對了就會跳轉到原url,否則將會繼續請求驗證碼圖片url,
    在這裡插入圖片描述在這裡插入圖片描述
    關於其他引數和驗證碼圖片的url都可以在這個驗證HTM文字中找到。除了提交的checkcode(驗證碼)的需要自己輸入,還有淘寶ua的演算法比較難搞其他的引數本來在頁面就是有的,經測試ua其實對驗證碼提交無影響,所以只需要識別驗證碼就可以啦。
  3. 輸入正確的驗證碼就可以繼續訪問的原來的介面

編碼

Java HTTP請求模組,個人最喜歡的~當然你也可以用httpckient等其他模組。

Requests is a http request lib with fluent api for java, inspired by the python request module. Requests requires JDK 1.7+.
https://github.com/hsiafan/requests

		//首先訪問原始介面
            resp = Requests.get(url2).headers(headersmap).send();
            result1 = resp.readToText();
            //如果獲取的原始介面中內容為空 就表示淘寶限制了
            String createtime = getMiddleText.......//省略
            
            //僅僅識別五次,五次還不通過,就放棄本條資料
            for (int i = 0; i < 5 && StringUtils.isEmpty(createtime); i++) {
            	//獲取驗證碼圖片url
                String codeurl = "https:" + getMiddleText(result1, "<img id=\"checkcodeImg\" src=\"", "\"");
                //呼叫識別介面
                String code = getCode(codeurl);
                System.out.println("這是識別後的結果" + code);
                //獲取頁面其他引數
                Map<String, Object> map = getParamsMap(result1, code);
                //模擬手動輸入驗證碼  提交資料(這個函式 我在下面會公開,因為涉及到一些坑)
                String coderes = queryCode(map, headersmap);
                createtime = getMiddleText(coderes, ....//省略
            }

拼接引數函式
這裡說明一下,requests提交的時候預設會自動編碼成utf8

  public static Map getParamsMap(String text, String code) {
        text = text.replaceAll("amp;", "");
        Map<String, Object> map = new HashMap<String, Object>();
        try {
            Pattern pattern = Pattern.compile("<input type=\"hidden\" name=\"(.*?)\" value=\"(.*?)\"");
            Matcher matcher = pattern.matcher(text);
            //正則批量提取form中引數
            while (matcher.find()) {
               //URLEncoder.encode(matcher.group(2), "utf-8");
                map.put(matcher.group(1), matcher.group(2)); 
            }
            //識別的驗證碼
            map.put("checkcode", code);
            //無影響
            map.put("ua", "");

            return map;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

提交驗證碼引數,注意一定要用淘寶cookie。

 /*驗證碼識別--提交識別結果*/
    public static String queryCode(Map<String, Object> map, Map headersMap) {
        RawResponse rawResponse = Requests.post("https://sec.taobao.com/query.htm").body(map)
               .headers(headersMap)
                .send();
           //代理模式 我一般是除錯的時候結合Fiddler,這樣就可以在Fiddler看到java請求,很方便找出模擬和實際的區別     
        // .proxy(Proxies.httpProxy("127.0.0.1", 8888))
        //列印響應頭
         System.out.println(rawResponse.getHeaders().toString());
        String code = rawResponse.readToText();
        return code;
    }

資料演示

可以發現一般都是識別一次就可以獲取到資料了,並不用識別5次,(當然這個更識別準確度有關~~~)
在這裡插入圖片描述

後記

使用resquests模組居然發現他預設編碼utf8,導致我一直error。後來通過Http代理到FIddler檢視請求才發現(Fiddler直接是抓不到除錯的時候http資料包,所以只有手動代理才能發現)
提交驗證碼的時候需要淘寶cookie,不然返回過去也有問題
Java的正則寫多行的話是真的難看啊~~~一堆的\n什麼的 以後也不方便修改~
另外關於驗證是滑塊的也可以通過打碼來解決的~我沒去深究,有興趣的可以自己嘗試……