按鍵精靈編寫的腳本簡單方便,最直接的體驗是可以代替我們處理簡單重復的鼠標鍵盤操作。
《QQ自由幻想》這款游戲系統內置自動掛機功能,但是每隔1個小時就會自動彈出驗證碼校驗,校驗不通過就會被踢下線,然后只能通過①先花錢開通VIP-》②再花錢購買2/4/8小時免校驗卡(道具)跳過校驗,不氪金體驗極差。
對于這款已經很老的游戲,情懷黨表示還是要嘗試實現自動過驗證碼,增加游戲體驗
按鍵論壇可以搜到大漠插件建立字庫識別驗證碼的教程:『笨海綿』用大漠插件實現QQ自由幻想驗證碼后臺識別方法詳解
這種方法主要原理是收集圖片像素點數據建立字庫并進行對比識別出驗證碼字符,缺點是建立字庫繁雜,識別率也是個問題。
接下來說下處理過程,首先截取左邊難處理的驗證碼區域,上傳圖片到打碼平臺(若快),然后截取右邊列4個較為規則的答案選項上傳到百度文字識別,最終對比返回結果得出第幾個是正確答案就可以通過驗證了,思路非常簡單。
主要涉及下面幾點:
- 大漠插件的使用
- 人工打碼平臺的對接(若快打碼平臺)
- 百度文字識別api的使用
首先是大漠插件的使用
- 首先下載大漠插件V3.1233(最后免費版本),然后根據里邊提供的
大漠接口說明.CHM
注冊大漠插件
大漠接口說明.CHM
為什么要使用大漠插件?
優點:大漠插件建立字庫找字的功能比較方便。
按鍵精靈自帶命令也可以滿足大部分的使用要求,大漠插件可以補充按鍵不足部分,混合使用。
大漠插件通過dm.BindWindow
命令可以輕松切換前后臺模式,而不需要修改腳本中的大量命令
測試過程中經常發現按鍵的后臺截圖方法截圖失敗時會導致按鍵程序直接崩潰,使用大漠插件就沒有出現這種情況
缺點:注冊多一個大漠插件意味著有更高的安全風險,360之類的就可能會報錯。
- 然后在腳本中創建大漠對象就可以直接使用了(具體方法/參數說明可以查看大漠接口文檔)
//首先獲取當前游戲句柄(這里通過游戲類名獲取,也可以直接鼠標獲取Plugin.Window.MousePoint)
Hwnd = Plugin.Window.Find("QQSwordWinClass", 0)
//創建大漠插件對象
set dm = createobject("dm.dmsoft")
//后臺模式
dm_ret = dm.BindWindow(Hwnd,"dx2","windows","windows", 0)
//前臺模式
//dm_ret = dm.BindWindowEx(Hwnd, "dx2", "normal", "normal", "", 0)
//大漠插件綁定句柄后就可以直接調用方法了,例如鼠標的移動點擊
//dm.MoveTo X,Y
//dm.LeftClick
//屏幕截圖保存到本地:先設置大漠插件統一保存的文件目錄,再截圖保存
//設置文件保存路徑
//dm_ret = dm.SetPath("D:\temp\ZYHXCaptcha")
//驗證碼截圖,在上面的目錄可以找到截圖
//dm_ret = dm.CaptureJpg(x1, y1, x2, y2, "captcha.jpg", 100)
- 驗證碼區域的截圖(具體方法/參數說明可以查看大漠接口文檔)
- 首先找到驗證碼區域的坐標,因為驗證碼是屏幕內隨機區域出現的,這需要用到找字功能:目標是找到驗證碼左上角
神醫
兩個字。找字功能就需要我們先建字庫:
①打開大漠綜合工具,點擊抓圖截取需要的“神醫”兩個字
大漠綜合工具
②然后調用dm.FindStr
就可以找到當前程序神醫
兩個字的坐標了
//注意要先設置使用的大漠字庫
dm_ret = dm.SetDict(0, "C:\test_game\zyhx.txt")
//然后找字成功就會返回intX、intY坐標
dm_ret = dm.FindStr(0, 0, 2000, 2000, "神醫", "ff0000-000000", 0.9, intX, intY)
If dm_ret = 0 And intX >0 And intY >0 Then
TracePrint "神醫坐標=" & intX & ":" & intY
End If
- 對驗證碼區域進行截圖
①截圖需要確定截圖范圍即:左上角坐標(找字得到“神醫”坐標),右下角坐標(按鍵自帶抓抓工具簡單計算出)
按鍵抓抓工具計算坐標
然后就可以調用dm.CaptureJpg
方法對左邊驗證碼和右邊答案選項列表進行截圖了
//注意要先設置文件保存路徑
//dm_ret = dm.SetPath("D:\temp\ZYHXCaptcha")
//驗證碼截圖
dm_ret = dm.CaptureJpg(intX, intY + 60, intX + 160, intY + 170, "captcha.jpg", 100)
Delay 50
//答案選項截圖
dm_ret = dm.CaptureJpg(intX+195, intY + 36, intX + 233, intY + 114, "answer.jpg", 65)
使用打碼平臺實現復雜驗證碼的處理
左邊區域的復雜驗證碼使用打碼平臺進行處理,這里使用若快打碼平臺:http://wiki.ruokuai.com/ApiDemo_Spirit.ashx
可以直接調用示例中提供的方法實現上傳并拿到返回值:
xml文本 = Lib.RK_API.上傳本地驗證碼圖片(用戶名, 密碼, 驗證碼類型, 超時時間, 軟件id, 軟件key, 圖片路徑)
TracePrint "若快識別結果:" & xml文本
response_captcha= Lib.RK_API.Xml解析(xml文本,"<Result>","</Result>")
這里參數的用戶名, 密碼需要我們到若快官網注冊一個
普通用戶
并進行充值,可以先充1塊得到2500快豆進行測試,這里驗證碼類型是3位英數混合3030
,驗證一次需要消耗10快豆,而軟件id和軟件key則需要再注冊一個開發者賬號
,添加軟件并審核通過后就可以拿到軟件Id和軟件Key了(具體查看若快官方接入文檔)
調用百度OCR處理簡單/規則的文字或數字
-
百度文字識別文檔中有兩種調用方式,第一種是先獲取Token然后直接進行調用,請求參數為
image=圖像數據(base64編碼后進行urlencode)
這里我使用第二種帶authorization
請求頭的鑒權方式(推薦使用Token的方式一,簡單方便)
- 先下載文檔中的鑒權認證示例
我選擇了下載了Java的示例:git clone https://github.com/baidubce/bce-sdk-java.git
- 然后在IDEA中打開,找到
BceV1Signer.java
,執行sign
方法就可以生成authorization
- 注意這里AK/SK需要登錄百度云->用戶賬號->安全認證->獲取Access Key/Secret Key,參考文檔
-
headersTosign
是請求頭中需要參與加密的項,這里為了簡單只加密了必須的host
public static void main(String[] args) throws Exception {
BceV1Signer bs = new BceV1Signer();
InternalRequest request = new InternalRequest(HttpMethodName.POST,new URI("https://aip.baidubce.com/rest/2.0/ocr/v1/accurate_basic"));
//SimpleDateFormat sdf = new SimpleDateFormat("yyyy-mm-dd'T'hh:mm:ssZ");
//request.addHeader("x-bce-date",sdf.format(new Date()));
//request.addHeader("content-type","multipart/form-data");
//ak/sk
BceCredentials bceCredentials = new DefaultBceCredentials("your_AccessKey","your_SecretKey ");
SignOptions signOptions = new SignOptions();
signOptions.setExpirationInSeconds(3600*24*365);//有效期一年
Set<String> headersTosign = new HashSet<String>();
headersTosign.add("HOST");//對請求頭中的host進行加密處理
//headersTosign.add("x-bce-date");
//headersTosign.add("content-type");
signOptions.setHeadersToSign(headersTosign);
bs.sign(request,bceCredentials,signOptions);
}
- 按鍵精靈中讀取圖片文件base64
按鍵中可以使用vbs,還保留VBSBegin...VBSEnd直接調用vbs代碼的方式,參考vbscript將圖片轉換為base64字符串
'vbscript將圖片2進制信息轉為base64字符,參數FilePath為圖片文件物理路徑
'@return:ImagesToBase64返回圖片base64格式字符串,前綴為data:image/圖片類型;base64,base64數據
Function ImagesToBase64(FilePath)
Dim xml
Dim root
Dim fs
Dim objStream
Dim objXMLDoc
Dim Base64
Set objXMLDoc=CreateObject("msxml2.FreeThreadedDOMDocument")
objXMLDoc.loadXML "<?xml version='1.0' ?><data></data>"
Set fs = createObject("Scripting.FileSystemObject") ''FSO組件
If fs.FileExists(FilePath) Then '判斷File文件是否存在
'用 stream 來讀取數據
Set objStream = CreateObject("ADODB.Stream")
objStream.Type = 1
objStream.Open
objStream.LoadFromFile FilePath
objXMLDoc.documentElement.dataType = "bin.base64"
objXMLDoc.documentElement.nodeTypedvalue = objStream.Read
'數據流讀取結束.得到了值 objXMLDoc
'創建XML文件
Set xml = CreateObject("msxml2.FreeThreadedDOMDocument")
xml.load objXMLDoc
If xml.ReadyState>2 Then
Set root=xml.getElementsByTagName("data")
Base64 = root.Item(0).Text
Base64 = Replace(Base64,vbLf,"")
TracePrint "Base64=" & Base64
else
Base64=""
End If
Set xml=Nothing
Set objStream=Nothing
else
Base64=""
End If
Set fs=Nothing
Set objXMLDoc=Nothing
ImagesToBase64 = Base64
End Function
測試過程中發現base64后的字符串中間包含了多余的換行符需要去除
Replace(Base64,vbLf,"")
- 圖像數據,base64編碼后進行urlencode
Function URLEncode(strURL)
Dim I
Dim tempStr
For I = 1 To Len(strURL)
If Asc(Mid(strURL, I, 1)) < 0 Then
tempStr = "%" & Right(CStr(Hex(Asc(Mid(strURL, I, 1)))), 2)
tempStr = "%" & Left(CStr(Hex(Asc(Mid(strURL, I, 1)))), Len(CStr(Hex(Asc(Mid(strURL, I, 1))))) - 2) & tempStr
URLEncode = URLEncode & tempStr
ElseIf (Asc(Mid(strURL, I, 1)) >= 65 And Asc(Mid(strURL, I, 1)) <= 90) Or (Asc(Mid(strURL, I, 1)) >= 97 And Asc(Mid(strURL, I, 1)) <= 122) Or (Asc(Mid(strURL, I, 1)) >= 48 And Asc(Mid(strURL, I, 1)) <= 57) Then
URLEncode = URLEncode & Mid(strURL, I, 1)
Else
URLEncode = URLEncode & "%" & Hex(Asc(Mid(strURL, I, 1)))
End If
Next
End Function
圖片質量高的時候base64長度變長,上面的這個方法執行速度會很慢。
- 調用百度文字識別api上傳圖片到百度云
這里使用鑒權方式二,填入請求頭中的Authorization
參數,以及x-bce-date
時間在生成的Authorization
中可以找到,access_token
的調用方式一則不需要設置請求頭。
Function postBaiduOCR(Url)
Set xmlHttp=CreateObject("Microsoft.XMLHTTP")
xmlHttp.Open "POST", Url, False
xmlHttp.setRequestHeader "Host", "aip.baidubce.com"
xmlHttp.setRequestHeader "x-bce-date", "2019-02-15T02:23:01Z"
authorization = "your_authorization"
xmlHttp.setRequestHeader "Authorization", authorization
//答案選項列表圖片base64
base64str = ImagesToBase64("D:\temp\ZYHXCaptcha\answer.jpg")
//圖片base64后再urlencode
tmp = URLEncode(base64str)
TracePrint "URLEncode="&tmp
xmlHttp.send "image="&tmp
If xmlHttp.readyState=4 then
response = xmlHttp.ResponseText
End If
xmlHttp.Abort
Set xmlHttp = Nothing
TracePrint "調用百度識別返回結果=" & response
postBaiduOCR = response
End Function
- 得到返回的json數據并進行解析,可以參考這篇文章:按鍵精靈中解析json數據
百度文字識別接口返回的json數據示例
Set sc = CreateObject("MSScriptControl.ScriptControl")
sc.Language = "JScript"
sc.AddCode "var o = " & json_result & ";"
//獲取第i個words并去除兩邊空格,然后統一轉成大寫
word_str = UCase(Trim(sc.Eval("o.words_result[1].words")))
//然后可以逐個字符跟若快返回結果進行比較 TODO
測試過程中發現識別誤差率高的字符有
W
容易被識別成N
/M
,M
被識別成N
/H
,以及第三個字符是Y
識別返回成V
需要做一點判斷處理
通過對比若快返回驗證碼識別結果以及百度OCR返回的選項列表可以確定第幾個是正確的驗證碼選項,最后可以dm.CmpColor
找特定點顏色(“神醫”十字邊緣點黃色),判斷是否快到時間,則點擊按鈕開始校驗。