• <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>

            不會飛的鳥

            2010年12月10日 ... 不鳥他們!!! 我要用自己開發(fā)的分布式文件系統(tǒng)、分布式調(diào)度系統(tǒng)、分布式檢索系統(tǒng), 做自己的搜索引擎!!!大魚有大志!!! ---楊書童

            [轉(zhuǎn)]驗證碼識別技術(shù)

            模擬精靈是首個公開最有效的驗證碼識別技術(shù)的軟件,
            使用模擬精靈制作了大量的免費、商用群發(fā)軟件,對很多復(fù)雜BT的驗證碼都能成功的識別。
            但是驗證碼仍然需要精湛的技術(shù)與足夠的耐心。請牢記這一點。
            驗證碼識別不適合浮躁的人去做。

            驗證碼識別是一項特殊的技術(shù),任何一個公開的驗證碼識別代碼都會很快的失效。
            因為代碼的公開后相關(guān)網(wǎng)站都會很快的更改驗證碼。
            所以下面我只會介紹其原理。

            在這里討論驗證碼識別技術(shù)純粹基于技術(shù)研究目的。
            公開此技術(shù)也是為了讓更多的網(wǎng)站采取更有效的防范措施。
            禁止任何人利用這里介紹的驗證碼識別技術(shù)濫發(fā)垃圾信息。

            本文介紹的驗證碼識別適用于比較復(fù)雜的圖片驗證碼,也是大多數(shù)網(wǎng)站采用的方法。
            有一些網(wǎng)站的驗證碼極簡單,例如在網(wǎng)頁中直接顯示驗證碼字符而不是圖片,或者圖片的文件名直接就是驗證碼上的字符。
            或者有其他規(guī)律可循,或者有其他明顯的漏洞可以利用(例如通過改寫訪問驗證碼頁面的源代碼使驗證碼不刷新)。

            這一類的驗證碼識別極其簡單,只要熟練掌握web庫element庫的函數(shù)即可,不需要使用下面介紹的方法。

            一、下載驗證碼樣本

            打開c:\test文件夾,選“查看縮略圖”,
            然后重復(fù)運行下面的LAScript腳本,每運行一次,就查看c:\test下自動生成的圖片,把圖片上的字符改為文件名.
            例如圖片上面顯示5,就把文件名改為5.jpg.

            如果變化比較復(fù)雜的驗證碼,可以對每個字符多用幾個樣本,第一個字符為驗證碼字符,第二個字符可以為任意字符。
            例如:5a.jpg , 5b.jpg , 5c.jpg ...........等等。 
            樣本多就會識別能力就越強。

            img = image.new();

            --下載圖像,沒有后綴名要顯示指定*.bmp格式

            img:getURL("http://www.***.com/test.asp","*.png");
            assert(img:ok(),"下載驗證碼失敗");

            img:Crop(4 ,3 , 56 ,18 )
            img:save("c:\\test\\test.jpg") --保存到硬盤


            --折分圖片,指定一行四列
            img2,img3,img4,img5 = img:split(1,4);

            img2:save("c:\\test\\0001.jpg")
            img3:save("c:\\test\\0002.jpg")
            img4:save("c:\\test\\0003.jpg")
            img5:save("c:\\test\\0004.jpg")

            image.del(img);


             如何確定圖片后綴名

            在整個驗證碼識別過程中,格式與后綴名一定不能搞錯,否則就會失敗。
            通常:asp的驗證碼是bmp格式,php的驗證碼是png格式,其他驗證碼很多是jpg格式。
            簡單的,在驗證碼上右鍵點選“圖片另存為”,就可以看到格式(不一定準(zhǔn)確)。

            另外,你可以用UltraEdit等以二進制方式打開看文件頭部

            首先下載:
            str = web.getURL("http://www.***.com/test.asp")
            string.save( str,"c:\\test.bin")

            然后用UE打開test.bin看文件頭部(第一行)

            jpg文件頭部有 JFIF 字眼
            png文件頭部 有 PNG 字眼
            gif文件頭部有 GIF字眼

            如果你搞不清楚,這時候就不要指定后綴名
            img:getURL("http://vwww.***.com/test.asp","")
            這樣就可以下載了

            二、生成驗證碼樣本數(shù)據(jù)庫

            復(fù)制下面的代碼并粘貼到fap程序的「腳本區(qū)塊」內(nèi),然后點擊"回放運行",最后再點擊"讀取源代碼"。

            你就可以在ApeML源代碼最后面的「數(shù)據(jù)區(qū)塊」中看到生成的驗證碼樣本了。
            將「數(shù)據(jù)區(qū)塊」的內(nèi)容復(fù)制需要使用驗證碼識別的fap模擬程序中覆蓋「數(shù)據(jù)區(qū)塊」即可。

            local tkey ={A=0,B=0,C=0,D=0,E=0,F=0,G=0,H=0,I=0,J=0,K=0,L=0,M=0,N=0,O=0,P=0,Q=0,R=0,S=0,T=0,U=0,V=0,W=0,X=0,Y=0,Z=0};
             
            --在字典中添加所有數(shù)字鍵
            for i =0,9,1 do
                tkey[ tostring(i) ] = 0
            end;

            --如果一個字符有多個樣本,例如 5A.jpg 5B.jpg 5C.jpg
            for k,v in pairs(tkey) do 
                if((#k)~=2)then --如果元素鍵名不是兩位字符
                    tkey[k.."A" ]=0;
                    tkey[k.."B" ]=0;
                    tkey[k.."C" ]=0;
                    tkey[k]=nil;--刪除單字符的鍵名
                end;
            end;
             
            --k參數(shù)為鍵,v參數(shù)表示值 一個典型的tkeyle迭代器回調(diào)函數(shù)
            loadtkey = function(k,v) 
                local img = image.new();
                
                img:load("C:\\test\\"..k..".jpg");
                assert(img:ok(),"C:\\test\\"..k..".jpg".."\n不是有效的圖片");
                
                img:bpp(1);
                img:bpp(24);
                --通過上面兩句,輕松去掉驗證碼上的雜色雜點
                
                img:Crop( 1 , 0 , 9 , 10);--修剪單個字符
                img:median(2);--中值濾波進一步去雜點
                
                tkey[k]string.encode( img:getBytes("*.jpg") , "")--因為轉(zhuǎn)換到字符串還是二進制,所以用base64進行編碼
                image.del(img);
            end;
             
            --遍歷表tkey的所有元素,調(diào)用loadtkey加載圖片文件 
            for k,v in pairs(tkey) do 
                loadtkey(k,v);
            end;
             
            --把所有圖片保存到數(shù)據(jù)島,
            ape:saveTable(tkey,"驗證碼樣本")

            三、驗證碼識別

            將下面的代碼添加到fap模擬程序最前面的init腳本區(qū)塊中即可

            --從數(shù)據(jù)區(qū)塊讀取base64編碼的圖片數(shù)據(jù)
            codekey = ape:loadTable("驗證碼樣本");
            local timg = {}--這是一個圖像數(shù)組,用來儲存還原后的驗證碼樣本的圖片數(shù)據(jù)
            --必須進行一個轉(zhuǎn)換,因為codekey里面只是base64編碼的普通字符串,而timg 將是真正的圖片對象(二進制數(shù)據(jù))
             
            --還原到圖片對象
            toImage = function(k,v)
                local img = image.new();
                local str = string.decode( v ,"");--首先進行base64解碼,將純文本轉(zhuǎn)換為二進制數(shù)據(jù)
                img:setBytes( str ,"*.jpg");--將二進制數(shù)據(jù)還原為圖像
                timg[k] = img; 
            end;
             
            --載入驗證碼樣本
            tkey = ape:loadTable("驗證碼樣本");
            for k,v in pairs(tkey) do  --驗證樣本
                toImage(k,v)--轉(zhuǎn)換為圖像
            end;
                
            --轉(zhuǎn)換圖片驗證碼到字符串的函數(shù)
            function ImgToString(img)
                function test(imgX) --test是一個被包含在函數(shù)中的內(nèi)部函數(shù)
                    sleep(0)
                    local limit = (60 * 20) + (60 * 20)--最小相似度 local關(guān)鍵字聲明為局部變量
                    local chr = "A"--讀取的字符
                
                
                    --testimg是一個被包含在函數(shù)中的內(nèi)部函數(shù),作為table.foreach的回調(diào)函數(shù),k參數(shù)表示鍵,v參數(shù)表示值
                    testimg = function(k,v)

                        --調(diào)用image.testXX()函數(shù)得出相似度,類似的函數(shù)還有image.testX() image.test() 
                        local n = imgX:testXX(timg[k])
                        if(n<limit)then --比較最小相似度
                              limit = n;
                              chr = k.."";
                        end;
                    end;
                
                    --遍歷timg表,并調(diào)用testimg函數(shù)
                    for k,v in pairs(timg) do  
                       testimg(k,v);  
                    end;

                    return string.left(chr,1)--返回讀取到的字符串首字符(如果每個字符有多個樣本)
                end;
                
                
                --修剪圖片    
                image.Crop(img, 4 ,3 , 56 ,18 )
                img:bpp(1);
                img:bpp(24);
                --上面的過程必須與下載樣本時的代碼完全一致。
                
                --使用split函數(shù)分割圖片
                local img2,img3,img4,img5 = img:split(1,4);
                win.messagePrint("正在檢測圖片,請稍候....");
                return test(img2)..test(img3)..test(img4)..test(img5);
             
            end;

            需要識別驗證碼的地方添加類似下面的代碼:

            img = image.new()
            img:getURL("http://www.***.com/test.asp","*.jpg")

            --因為刷新了驗證碼與頁面不一致,把驗證碼畫到屏幕上
            local x,y = mouse.getPos()
            img:paint(x,y,60 ,20 )

            local str = ImgToString(img);

            --下面我們把驗證碼的每個字符都轉(zhuǎn)換為大寫,并控制鍵盤順序按鍵
            code1 = string.upper( string.sub(str,1,1) ); 
            code2 = string.upper( string.sub(str,2,2) ); 
            code3 = string.upper( string.sub(str,3,3) ); 
            code4 = string.upper( string.sub(str,4,4) );
            key.press(100,code1,code2,code3,code4);

            上面我們用了模擬按鍵的方法輸入驗證碼。
            實際上大多時候可以用更簡單的方法,如下:

            ele = wb:getEle("驗證碼控件名字");
            ele:setAttribute("value",str)

             為什么我的驗證碼與頁面上不一樣

            因為我們使用img:getURL讀取驗證碼時已經(jīng)刷新了驗證碼。
            所以驗證碼與頁面上顯示的并不一樣,您只需要識別最新的驗證碼即可。

             如何直接獲取頁面的上圖片,而不是重新下載

            有些驗證碼是綁定頁面的,必須識別頁面上的驗證碼才行。
            那么可以使用image.capture函數(shù)直接抓屏屏幕上的圖片即可。
            請參考:image.capture函數(shù)

            更好的方法是使用ele:exec("Copy")函數(shù)直接拷貝頁面上的圖片到剪貼板。
            然后使用 img:getClipBD() 獲取圖片。 
            請參考:ele:exec("Copy")函數(shù) img:getClipBD()函數(shù)

            四、關(guān)于剪切圖片



            看上面的示意圖,Crop就是選取綠色方框內(nèi)的區(qū)域去清除綠色方框外面的區(qū)域.
            必須保證里面的面積正好可以平均分成四塊(假設(shè)這里是四個驗證碼字符)

            這樣以后調(diào)用 img:split(1,4) 就正好分成四個字符了
            分成四份的小圖片其寬度應(yīng)當(dāng)正好是上面的紅色小方塊的寬度。
            高度與綠色方框一樣,我這里畫的參次不齊是為了讓大家看清楚。

            如果你Crop的參數(shù)值不對,那么split就出錯了.
            下載驗證碼圖片以后,可以使用圖像編輯軟件打開高倍放大。

            五、使用種子填充算法去除驗證碼上的干擾線

            模擬精靈識別驗證碼的能用是強大的,一個函數(shù)即可以去除雜色雜點。

            img:bpp(1)
            img:bpp(24)

            經(jīng)過上面兩句代碼的處理,速度很快,所有背景、干擾點、雜色蕩然無存。

            但是有時候驗證碼中有大量的干擾線,并且位置隨機變動的太歷害,
            這時候我們在處理驗證碼以前首先去除這些干擾線并準(zhǔn)確的去除背景提取字符.

            下面是一個模擬精靈初步處理后的驗證碼圖片.已經(jīng)去除了雜色、雜點.但是上面還是有干擾線.

            一個可選的辦法是用中值濾波再處理一下。img:median(2); 一個函數(shù)調(diào)用就可以,但
            是這樣雖然去掉了干擾線,原來的字符也被少量的破壞了。

            下面是使用種子填充算法去除干擾線的源代碼,不但能去除雜點,
            而且可以去除周圍的空白(提取位置隨機變化的驗證碼),
            稍加修改還能有更多的用途.

            下面是自動處理以后的效果

            下面是全部的源代碼:

            --[[
            用一個table結(jié)構(gòu){x=0; y=0}表示圖像上的「坐標(biāo)點」
            用一組點構(gòu)成table結(jié)構(gòu)表示圖像上的一條「線」。所有相連的黑色的點被認為是一條「連通線」。
            找出最長的一條「連通線」,被認為是字符,其他的認為是雜點。
             
             
            算法原理與種子填充算法相似。
             
            首先讓用img:bpp函數(shù)處理為黑白圖片,并初步去除雜色。
             
            先找到一個黑點,創(chuàng)建一個表示「坐標(biāo)點」對象,并添加到「連通線」中。
            然后在黑點周圍8個點中,再找黑色的點,找到就添加到「連通線」,這樣一直遞歸下去
            直到遍歷圖像所有點,可能有幾塊。
             
            清除雜點使用方法
            image.scan(img);
             
            清除雜點并切去掉周圍的空白
            image.scan(img,true);
            --]]
            f
            unction image.scan(img,crop)
               
                --用一個table數(shù)組記錄所有的「連通線」
                 assert(img:ok(),"image.scan 的參數(shù)必須是一個有效的圖片");
                
                 local tlines ={}
                 
                 --首先計算出圖片的高度寬度,避免重復(fù)的調(diào)用
                 local w = img:width();
                 local h = img:height();
                      
              
                --[[以table形式定義一個數(shù)組,對應(yīng)圖象中的每個點。
                作用相當(dāng)一個開關(guān),首先值為false,但黑點首次被遍歷到時。把這個值變?yōu)閠rue。
                下次,再找到這個點時忽略。避免重復(fù)加入連通線。  
                --]]
                local tchked ={};
                for i=0,w,1  do
                    tchked[i]={};
                    for j=0,h, do
                        tchked[i][j]=false;
                    end;
                end;
                 
                -----去噪
                img:bpp(1);
                img:bpp(24);
                 
                --首先計算出各點的顏色值,避免在循環(huán)遞歸中重復(fù)的取
                local tcl={};
                for i=0,w, do
                    tcl[i]={};
                    for j=0,h,  do
                        tcl[i][j]=img:getPos(i,j);
                    end;
                end;
             
                
                --[[
                算點數(shù)函數(shù)
                參數(shù)x,y 坐標(biāo)
                參數(shù)tab 所屬連通線;
                --]] 
                local   function  seed(x,y,tab)
                
                    ---出界了則返回
                    if(x<0 or y<0 or x>w or y>h) then
                        return;
                    end;
                          
                    ---點的顏色為白色時,返回,不處理。
                    if(tcl[x][y]==16777215)  then
                        return;
                    end;
                    
                    ---值為1,則計數(shù)加1,返回
                    if ( tchked[x][y]) then
                        return ;
                    else
                        table.insert(tab,{x=x,y=y} );--添加到連通線里
                        tchked[x][y]=true;---當(dāng)值為0時,把值置為1。
                        seed(x+1,y-1,tab);
                        seed(x,y-1,tab);
                        seed(x-1,y-1,tab);
                        seed(x-1,y,tab);
                        seed(x+1,y,tab);
                        seed(x-1,y+1,tab);
                        seed(x,y+1,tab);
                        return seed(x+1,y+1,tab)--這里可以用一個尾調(diào)用(參考教程中的函數(shù)部份),加快遞歸的速度。
                    end;
                end;
             
                
                ---------------------------
                   
                ----遍歷圖像中的所有點
                for i=0,w,1   do
                    for j=0,h, do
                        ---如果是黑色的點,而且沒有被計過數(shù),則調(diào)用seed函數(shù)。
                        if(tcl[i][j]==0 and (not tchked[i][j])) then        
                            local tab = {}
                            seed(i,j,tab);
                            table.insert(tlines,tab)--添加一條連通線
                
                        end;
                    end;
                end;
                      
                --現(xiàn)在tlines 里記錄了的有的連通線,我們現(xiàn)在需要根據(jù)連通線的長度排序  
                sproc =  function(l,l2)   
                    return table.maxn(l) > table.maxn(l2);--長的連通線排到前面 
                end;
                table.sort(tlines,sproc)
                           
                --把圖像全部畫成白色的點      
                for i=0,w,1  do
                    for j=0,h,1  do
                        img:setPos( i , j, 16777215);
                    end;
                end;
                      
                --然后把最長的一條連通線畫上去
                for i,point in  ipairs(tlines[1])  do
                    img:setPos( point.x, point.y , 0);   
                end;
                
              
                --如果需要去掉周圍的空白
                if(crop)then
                    local n = table.maxn(tlines[1])
                        
                    --排序最長連通線中的所有坐標(biāo)點
                    sproc =  function(pt,pt2)   
                        return  (pt.x <pt2.x );--*左的排前面
                    end;
                    table.sort(tlines[1],sproc);
                    local x,x2 = tlines[1][1].x, tlines[1][n].x;
                
                    --排序最長連通線中的所有坐標(biāo)點
                    sproc =  function(pt,pt2)   
                        return (pt.y <pt2.y );--*上的排前面
                    end;
                    table.sort(tlines[1],sproc);
                    local y,y2 = tlines[1][1].y, tlines[1][n].y;
                    
                    img:Crop( x,y,x2+1,y2)
                end;
                
            end;
                

             

            posted on 2011-09-14 13:38 不會飛的鳥 閱讀(2290) 評論(0)  編輯 收藏 引用


            只有注冊用戶登錄后才能發(fā)表評論。
            網(wǎng)站導(dǎo)航: 博客園   IT新聞   BlogJava   博問   Chat2DB   管理


            久久久久久久97| 久久噜噜久久久精品66| 精品久久久久久综合日本| 韩国三级大全久久网站| 久久青青草原精品国产不卡| 国产69精品久久久久APP下载| 久久午夜夜伦鲁鲁片免费无码影视 | 综合久久国产九一剧情麻豆 | 国产精品天天影视久久综合网| 日本免费一区二区久久人人澡 | 香港aa三级久久三级老师2021国产三级精品三级在| 日产久久强奸免费的看| 777米奇久久最新地址| 亚洲美日韩Av中文字幕无码久久久妻妇 | 99精品国产免费久久久久久下载| av午夜福利一片免费看久久| 精品人妻伦一二三区久久| 久久婷婷五月综合国产尤物app| 久久亚洲精品无码播放| 久久香蕉一级毛片| 久久精品aⅴ无码中文字字幕重口 久久精品a亚洲国产v高清不卡 | 久久99国产综合精品| 亚洲人AV永久一区二区三区久久| 99久久国产综合精品麻豆| 久久伊人五月丁香狠狠色| 久久这里有精品| 久久精品无码专区免费| 欧美一区二区三区久久综| 77777亚洲午夜久久多人| 久久久久久久久波多野高潮| 亚洲日本va午夜中文字幕久久 | 99999久久久久久亚洲| 午夜精品久久久久久中宇| 色播久久人人爽人人爽人人片AV| 国产精品午夜久久| 伊人色综合久久| 国产精品九九久久精品女同亚洲欧美日韩综合区| 久久精品卫校国产小美女| 久久只有这里有精品4| 99久久综合国产精品免费| 久久人人爽人人爽人人片AV麻烦|