按鍵精靈編寫的腳本簡(jiǎn)單方便,最直接的體驗(yàn)是可以代替我們處理簡(jiǎn)單重復(fù)的鼠標(biāo)鍵盤操作。
《QQ自由幻想》這款游戲系統(tǒng)內(nèi)置自動(dòng)掛機(jī)功能,但是每隔1個(gè)小時(shí)就會(huì)自動(dòng)彈出驗(yàn)證碼校驗(yàn),校驗(yàn)不通過(guò)就會(huì)被踢下線,然后只能通過(guò)①先花錢開通VIP-》②再花錢購(gòu)買2/4/8小時(shí)免校驗(yàn)卡(道具)跳過(guò)校驗(yàn),不氪金體驗(yàn)極差。
對(duì)于這款已經(jīng)很老的游戲,情懷黨表示還是要嘗試實(shí)現(xiàn)自動(dòng)過(guò)驗(yàn)證碼,增加游戲體驗(yàn)

按鍵論壇可以搜到大漠插件建立字庫(kù)識(shí)別驗(yàn)證碼的教程:『笨海綿』用大漠插件實(shí)現(xiàn)QQ自由幻想驗(yàn)證碼后臺(tái)識(shí)別方法詳解
這種方法主要原理是收集圖片像素點(diǎn)數(shù)據(jù)建立字庫(kù)并進(jìn)行對(duì)比識(shí)別出驗(yàn)證碼字符,缺點(diǎn)是建立字庫(kù)繁雜,識(shí)別率也是個(gè)問(wèn)題。
接下來(lái)說(shuō)下處理過(guò)程,首先截取左邊難處理的驗(yàn)證碼區(qū)域,上傳圖片到打碼平臺(tái)(若快),然后截取右邊列4個(gè)較為規(guī)則的答案選項(xiàng)上傳到百度文字識(shí)別,最終對(duì)比返回結(jié)果得出第幾個(gè)是正確答案就可以通過(guò)驗(yàn)證了,思路非常簡(jiǎn)單。
主要涉及下面幾點(diǎn):
- 大漠插件的使用
- 人工打碼平臺(tái)的對(duì)接(若快打碼平臺(tái))
- 百度文字識(shí)別api的使用
首先是大漠插件的使用
- 首先下載大漠插件V3.1233(最后免費(fèi)版本),然后根據(jù)里邊提供的
大漠接口說(shuō)明.CHM注冊(cè)大漠插件
大漠接口說(shuō)明.CHM
為什么要使用大漠插件?
優(yōu)點(diǎn):大漠插件建立字庫(kù)找字的功能比較方便。
按鍵精靈自帶命令也可以滿足大部分的使用要求,大漠插件可以補(bǔ)充按鍵不足部分,混合使用。
大漠插件通過(guò)dm.BindWindow命令可以輕松切換前后臺(tái)模式,而不需要修改腳本中的大量命令
測(cè)試過(guò)程中經(jīng)常發(fā)現(xiàn)按鍵的后臺(tái)截圖方法截圖失敗時(shí)會(huì)導(dǎo)致按鍵程序直接崩潰,使用大漠插件就沒有出現(xiàn)這種情況
缺點(diǎn):注冊(cè)多一個(gè)大漠插件意味著有更高的安全風(fēng)險(xiǎn),360之類的就可能會(huì)報(bào)錯(cuò)。
- 然后在腳本中創(chuàng)建大漠對(duì)象就可以直接使用了(具體方法/參數(shù)說(shuō)明可以查看大漠接口文檔)
//首先獲取當(dāng)前游戲句柄(這里通過(guò)游戲類名獲取,也可以直接鼠標(biāo)獲取Plugin.Window.MousePoint)
Hwnd = Plugin.Window.Find("QQSwordWinClass", 0)
//創(chuàng)建大漠插件對(duì)象
set dm = createobject("dm.dmsoft")
//后臺(tái)模式
dm_ret = dm.BindWindow(Hwnd,"dx2","windows","windows", 0)
//前臺(tái)模式
//dm_ret = dm.BindWindowEx(Hwnd, "dx2", "normal", "normal", "", 0)
//大漠插件綁定句柄后就可以直接調(diào)用方法了,例如鼠標(biāo)的移動(dòng)點(diǎn)擊
//dm.MoveTo X,Y
//dm.LeftClick
//屏幕截圖保存到本地:先設(shè)置大漠插件統(tǒng)一保存的文件目錄,再截圖保存
//設(shè)置文件保存路徑
//dm_ret = dm.SetPath("D:\temp\ZYHXCaptcha")
//驗(yàn)證碼截圖,在上面的目錄可以找到截圖
//dm_ret = dm.CaptureJpg(x1, y1, x2, y2, "captcha.jpg", 100)
- 驗(yàn)證碼區(qū)域的截圖(具體方法/參數(shù)說(shuō)明可以查看大漠接口文檔)
- 首先找到驗(yàn)證碼區(qū)域的坐標(biāo),因?yàn)轵?yàn)證碼是屏幕內(nèi)隨機(jī)區(qū)域出現(xiàn)的,這需要用到找字功能:目標(biāo)是找到驗(yàn)證碼左上角
神醫(yī)兩個(gè)字。找字功能就需要我們先建字庫(kù):
①打開大漠綜合工具,點(diǎn)擊抓圖截取需要的“神醫(yī)”兩個(gè)字
大漠綜合工具
②然后調(diào)用dm.FindStr就可以找到當(dāng)前程序神醫(yī)兩個(gè)字的坐標(biāo)了
//注意要先設(shè)置使用的大漠字庫(kù)
dm_ret = dm.SetDict(0, "C:\test_game\zyhx.txt")
//然后找字成功就會(huì)返回intX、intY坐標(biāo)
dm_ret = dm.FindStr(0, 0, 2000, 2000, "神醫(yī)", "ff0000-000000", 0.9, intX, intY)
If dm_ret = 0 And intX >0 And intY >0 Then
TracePrint "神醫(yī)坐標(biāo)=" & intX & ":" & intY
End If
- 對(duì)驗(yàn)證碼區(qū)域進(jìn)行截圖
①截圖需要確定截圖范圍即:左上角坐標(biāo)(找字得到“神醫(yī)”坐標(biāo)),右下角坐標(biāo)(按鍵自帶抓抓工具簡(jiǎn)單計(jì)算出)
按鍵抓抓工具計(jì)算坐標(biāo)
然后就可以調(diào)用dm.CaptureJpg方法對(duì)左邊驗(yàn)證碼和右邊答案選項(xiàng)列表進(jìn)行截圖了
//注意要先設(shè)置文件保存路徑
//dm_ret = dm.SetPath("D:\temp\ZYHXCaptcha")
//驗(yàn)證碼截圖
dm_ret = dm.CaptureJpg(intX, intY + 60, intX + 160, intY + 170, "captcha.jpg", 100)
Delay 50
//答案選項(xiàng)截圖
dm_ret = dm.CaptureJpg(intX+195, intY + 36, intX + 233, intY + 114, "answer.jpg", 65)

使用打碼平臺(tái)實(shí)現(xiàn)復(fù)雜驗(yàn)證碼的處理
左邊區(qū)域的復(fù)雜驗(yàn)證碼使用打碼平臺(tái)進(jìn)行處理,這里使用若快打碼平臺(tái):http://wiki.ruokuai.com/ApiDemo_Spirit.ashx

可以直接調(diào)用示例中提供的方法實(shí)現(xiàn)上傳并拿到返回值:
xml文本 = Lib.RK_API.上傳本地驗(yàn)證碼圖片(用戶名, 密碼, 驗(yàn)證碼類型, 超時(shí)時(shí)間, 軟件id, 軟件key, 圖片路徑)
TracePrint "若快識(shí)別結(jié)果:" & xml文本
response_captcha= Lib.RK_API.Xml解析(xml文本,"<Result>","</Result>")
這里參數(shù)的用戶名, 密碼需要我們到若快官網(wǎng)注冊(cè)一個(gè)
普通用戶并進(jìn)行充值,可以先充1塊得到2500快豆進(jìn)行測(cè)試,這里驗(yàn)證碼類型是3位英數(shù)混合3030,驗(yàn)證一次需要消耗10快豆,而軟件id和軟件key則需要再注冊(cè)一個(gè)開發(fā)者賬號(hào),添加軟件并審核通過(guò)后就可以拿到軟件Id和軟件Key了(具體查看若快官方接入文檔)
調(diào)用百度OCR處理簡(jiǎn)單/規(guī)則的文字或數(shù)字
-
百度文字識(shí)別文檔中有兩種調(diào)用方式,第一種是先獲取Token然后直接進(jìn)行調(diào)用,請(qǐng)求參數(shù)為
image=圖像數(shù)據(jù)(base64編碼后進(jìn)行urlencode)
這里我使用第二種帶authorization請(qǐng)求頭的鑒權(quán)方式(推薦使用Token的方式一,簡(jiǎn)單方便)
- 先下載文檔中的鑒權(quán)認(rèn)證示例
我選擇了下載了Java的示例:git clone https://github.com/baidubce/bce-sdk-java.git - 然后在IDEA中打開,找到
BceV1Signer.java,執(zhí)行sign方法就可以生成authorization - 注意這里AK/SK需要登錄百度云->用戶賬號(hào)->安全認(rèn)證->獲取Access Key/Secret Key,參考文檔
-
headersTosign是請(qǐng)求頭中需要參與加密的項(xiàng),這里為了簡(jiǎn)單只加密了必須的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");//對(duì)請(qǐng)求頭中的host進(jìn)行加密處理
//headersTosign.add("x-bce-date");
//headersTosign.add("content-type");
signOptions.setHeadersToSign(headersTosign);
bs.sign(request,bceCredentials,signOptions);
}
- 按鍵精靈中讀取圖片文件base64
按鍵中可以使用vbs,還保留VBSBegin...VBSEnd直接調(diào)用vbs代碼的方式,參考vbscript將圖片轉(zhuǎn)換為base64字符串
'vbscript將圖片2進(jìn)制信息轉(zhuǎn)為base64字符,參數(shù)FilePath為圖片文件物理路徑
'@return:ImagesToBase64返回圖片base64格式字符串,前綴為data:image/圖片類型;base64,base64數(shù)據(jù)
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 來(lái)讀取數(shù)據(jù)
Set objStream = CreateObject("ADODB.Stream")
objStream.Type = 1
objStream.Open
objStream.LoadFromFile FilePath
objXMLDoc.documentElement.dataType = "bin.base64"
objXMLDoc.documentElement.nodeTypedvalue = objStream.Read
'數(shù)據(jù)流讀取結(jié)束.得到了值 objXMLDoc
'創(chuàng)建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
測(cè)試過(guò)程中發(fā)現(xiàn)base64后的字符串中間包含了多余的換行符需要去除
Replace(Base64,vbLf,"")
- 圖像數(shù)據(jù),base64編碼后進(jìn)行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
圖片質(zhì)量高的時(shí)候base64長(zhǎng)度變長(zhǎng),上面的這個(gè)方法執(zhí)行速度會(huì)很慢。
- 調(diào)用百度文字識(shí)別api上傳圖片到百度云
這里使用鑒權(quán)方式二,填入請(qǐng)求頭中的Authorization參數(shù),以及x-bce-date時(shí)間在生成的Authorization中可以找到,access_token的調(diào)用方式一則不需要設(shè)置請(qǐng)求頭。
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
//答案選項(xiàng)列表圖片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 "調(diào)用百度識(shí)別返回結(jié)果=" & response
postBaiduOCR = response
End Function
- 得到返回的json數(shù)據(jù)并進(jìn)行解析,可以參考這篇文章:按鍵精靈中解析json數(shù)據(jù)
百度文字識(shí)別接口返回的json數(shù)據(jù)示例
Set sc = CreateObject("MSScriptControl.ScriptControl")
sc.Language = "JScript"
sc.AddCode "var o = " & json_result & ";"
//獲取第i個(gè)words并去除兩邊空格,然后統(tǒng)一轉(zhuǎn)成大寫
word_str = UCase(Trim(sc.Eval("o.words_result[1].words")))
//然后可以逐個(gè)字符跟若快返回結(jié)果進(jìn)行比較 TODO
測(cè)試過(guò)程中發(fā)現(xiàn)識(shí)別誤差率高的字符有
W容易被識(shí)別成N/M,M被識(shí)別成N/H,以及第三個(gè)字符是Y識(shí)別返回成V需要做一點(diǎn)判斷處理
通過(guò)對(duì)比若快返回驗(yàn)證碼識(shí)別結(jié)果以及百度OCR返回的選項(xiàng)列表可以確定第幾個(gè)是正確的驗(yàn)證碼選項(xiàng),最后可以dm.CmpColor找特定點(diǎn)顏色(“神醫(yī)”十字邊緣點(diǎn)黃色),判斷是否快到時(shí)間,則點(diǎn)擊按鈕開始校驗(yàn)。



