以前搞過幾回模擬登陸,都是模擬 post 後取到 cookie,以後便能用這個 cookie 愉快玩耍。此次碰到了驗證碼,其實只需手動登陸一次,手動取到 cookie 後也能玩耍,不過 cookie 有效期不長,常常要換,十分麻煩。而後看到了這個庫 tesseract.js,因爲咱們的驗證碼機器識別難度並非很高,試了下出現 good case 機率仍是很是高的,決定試下自動識別驗證碼登陸。javascript
驗證碼是用 PHP 生成的,指向一個 PHP 地址。原理不是很難,PHP 生成驗證碼圖片,開啓 Session(因此每次點擊驗證碼切換圖片,都會是一個新的 Session),而後把驗證碼數字記在 Session 數組中,當用戶提交表單後,check 輸入的驗證碼數字是否存在於 Session 數組中。html
用的語言是 Node。以前想的很是簡單,首先將驗證碼 down 下來,而後調用 tesseract.js 識別,最後模擬 post 後取到後續操做須要的 key cookie。java
出現該問題須要知足兩個條件:node
模擬 post 有個參數 username 用的是中文,若是頁面是 utf-8 編碼應該沒這個問題,就直接發送中文參數了,可是看實際請求中文參數被編碼了,查了下 urlencode 這個包能夠作相似的編碼。將這個被編碼後的參數填入發起模擬請求,報用戶名錯誤,而後查到了 這個帖子,場景相似,一樣是 gbk 編碼頁面的 post 攜帶了中文參數,我猜想緣由也可能相同,被二次編碼了。git
但把轉換過的字符串傳到 request 的 form 中去後,request 又會對其中的 % 編碼爲 %25github
用帖子裏的方法能夠解決:npm
var request = require('request'); var iconv = require('iconv-lite'); var post_request = request .post({ url: 'https://xx.com', headers: { 'Content-Type': 'application/x-www-form-urlencoded', 'Cookie': 'PHPSESSID=xx' }, encoding: null // 關鍵代碼 }, function (err, sres, body) { // 解決返回頁面亂碼(gbk) var html = iconv.decode(body, 'gb2312'); console.log(html); }); // form data post_request.write("a=xx&b=xx&c=xx");
請求 gbk 頁面會中文亂碼,這裏用了 iconv-lite 這個包,其餘解決方法能夠參考 node爬蟲之gbk網頁中文亂碼解決方案數組
由於一直用的是 superAgent 這個模塊,因此但願能在 superAgent 基礎上解決這個問題,而後在 cnode 提了個 問題 ,最後也是解決了。瀏覽器
爲了不返回信息中文亂碼,用了 superagent-charset 這個包:cookie
var superagent = require('superagent-charset'); var req = superagent .post('https://xx.com') .set("Content-Type", "application/x-www-form-urlencoded") .set("Cookie", "PHPSESSID=xxx") .charset('gbk'); // form data req.write("username=xx&password=xx&checkcode=xx"); req.end(function(err, sres) { console.log(sres.text); });
以上問題解決後,PHPSESSID 這個 cookie 很是容易獲取,模擬請求一次取 cookie 便可。手動在代碼中輸入瀏覽器中顯示的驗證碼,模擬登陸能夠成功,而後取登陸後的 cookie,確實也能夠愉快玩耍,不過問題來了,驗證碼圖片沒法識別了!
昨天晚上試了下直接在登陸頁面右鍵複製下來驗證碼,而後用 tesseract.js 是能夠解析的,可是用 Node down 下來的卻不能解析,alsotang 大大說多是 "buffer 在 ondata 的相加問題"。剛纔試了下昨天手動保存驗證碼圖片,成功解析的 case 也報錯了,感受是 tesseract.js 這個庫還不是很成熟,過段時間再看看。
下載圖片用的是這個函數:
// to download picture function download(url, savePath) { var req = http.get(url, function(res){ var binImage = ''; res.setEncoding('binary'); res.on('data', function(chunk){ binImage += chunk; }); res.on('end', function(){ if (!binImage) { console.log('image data is null'); return null; } fs.writeFile(savePath, binImage, 'binary', function(err){ if (err) throw err; console.log('It\'s saved!'); // 文件被保存 }); }); }); }
對 Node 不熟,這個問題留坑之後待解決了。
問題解決過程當中,除了上面的帖子,還在 v 站發了個帖子,如何模擬登陸有驗證碼的網站?,FYI