ExcelHome技术论坛

 找回密码
 免费注册

QQ登录

只需一步,快速开始

快捷登录

搜索
EH技术汇-专业的职场技能充电站 妙哉!函数段子手趣味讲函数 Excel服务器-会Excel,做管理系统 Excel Home精品图文教程库
HR薪酬管理数字化实战 Excel 2021函数公式学习大典 Excel数据透视表实战秘技 打造核心竞争力的职场宝典
300集Office 2010微视频教程 数据工作者的案头书 免费直播课集锦 ExcelHome出品 - VBA代码宝免费下载
用ChatGPT与VBA一键搞定Excel WPS表格从入门到精通 Excel VBA经典代码实践指南
楼主: 蓝天630902

[分享] 验证码识别讲座

  [复制链接]

TA的精华主题

TA的得分主题

发表于 2012-8-4 20:42 | 显示全部楼层
本帖已被收录到知识树中,索引项:图像处理和GDI
不好意思,刚才http://user.kdnet.net/login_new.asp试了试,很纳闷,这个网站的验证码比较简单,不知怎么却测不出,我对验证码了解比较少,可能你的代码要稍微加已改进。很高兴能欣赏你的作品。
DV_getcode.jpg

TA的精华主题

TA的得分主题

 楼主| 发表于 2012-8-5 06:52 | 显示全部楼层
cumulonimbus 发表于 2012-8-4 20:42
不好意思,刚才http://user.kdnet.net/login_new.asp试了试,很纳闷,这个网站的验证码比较简单,不知怎么却 ...

凯迪是一个比较反动的网站,如果你有高于常人的主见,浏览一下凯迪是非常有好处的。否则还是不看要好些。

对于这个3534比较特殊,下面是代码:

Public Declare Function GetClipboardData Lib "user32" (ByVal wFormat As Long) As Long
Public Declare Function CloseClipboard Lib "user32" () As Long
Public Declare Function OpenClipboard Lib "user32" (ByVal hwnd As Long) As Long
Public Declare Function GlobalLock Lib "kernel32" (ByVal hMem As Long) As Long
Public Declare Function GlobalSize Lib "kernel32" (ByVal hMem As Long) As Long
Public Declare Function GlobalUnlock Lib "kernel32" (ByVal hMem As Long) As Long
Public Declare Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" (Destination As Any, Source As Any, ByVal Length As Long)
Public Const CF_TEXT = 1
Public Const CF_BITMAP = 2
Public Const CF_DIB = 8
Sub 验证码识别()
    Dim img
    Dim CtrlRange
    Dim bytClipData() As Byte
    Dim arr() As String
    Dim b(1 To 30)
    Dim c(1 To 30)
    Dim a(1 To 4)
    Dim tmp()
    Dim temp As String
    Dim ts As Integer
    Cells.Clear
    b(1) = ""
    b(2) = ""
    b(3) = ""
    b(4) = "223337"
    b(5) = "2233a2"
    b(6) = "633335"
    b(7) = ""
    b(8) = ""
    b(9) = ""
    b(10) = ""
    c(1) = ""
    c(2) = ""
    c(3) = ""
    c(4) = "3"
    c(5) = "4"
    c(6) = "5"
    c(7) = ""
    c(8) = ""
    c(9) = ""
    c(10) = ""
    Range("A1:A1").NumberFormatLocal = "@"
    On Error Resume Next
    With CreateObject("InternetExplorer.application")
        .Visible = True
        .Navigate "http://club.excelhome.net/thread-896161-4-1.html"
        Do Until .ReadyState = 4
            DoEvents
        Loop
        Set img = .Document.All.tags("img")(15)
        Set CtrlRange = .Document.body.createControlRange()
        CtrlRange.Add img
        CtrlRange.execCommand "Copy", True
        Dim hMem As Long, lpData As Long
        OpenClipboard 0&
        hMem = GetClipboardData(8)
        If CBool(hMem) Then
            lpData = GlobalLock(hMem)
            lClipSize = GlobalSize(hMem)
            If lpData <> 0 And lClipSize > 0 Then
                ReDim bytClipData(0 To lClipSize - 1)
                CopyMemory bytClipData(0), ByVal lpData, lClipSize
            End If
            GlobalUnlock hMem
        End If
        CloseClipboard
        a1 = bytClipData(0)
        a2 = bytClipData(4)
        a3 = bytClipData(8)
        a4 = lClipSize - 40
        a5 = a4 / a2 / a3
        ReDim arr(1 To a2 * a3)
        For i = 1 To a2 * a3
            arr(i) = 1
            ts = 0
            For j = 0 To a5 - 1
                ts = ts + Val(bytClipData((i - 1) * a5 + a1 + j))
            Next j
            ts = ts / a5
            If ts > 200 Then
                arr(i) = ""
            End If
        Next i
        For i = 1 To a3
            For j = 1 To a2
                Cells(a3 + 1 - i, j) = arr((i - 1) * a2 + j)
            Next j
        Next i
        temp = ""
        For i = 1 To a2
            For j = 1 To a3
                Cells(a3 + 1, i) = Cells(a3 + 1, i) + arr((j - 1) * a2 + i)
            Next j
            If Cells(a3 + 1, i) = 10 Then Cells(a3 + 1, i) = "a"
            If Cells(a3 + 1, i) <> "" Then
                temp = temp & Cells(a3 + 1, i)
            Else
                temp = temp & ","
                temp = Replace(temp, ",,", ",")
            End If
        Next i
        Cells.Clear
        For j = 1 To 10
            temp = Replace(temp, b(j), c(j))
        Next j
        Cells(1, 1) = Format(Replace(temp, ",", ""), "0000")
        .Quit
    End With
End Sub

TA的精华主题

TA的得分主题

 楼主| 发表于 2012-8-5 08:07 | 显示全部楼层
虽然不推荐凯迪,但还是帮你写好了。

Public Declare Function GetClipboardData Lib "user32" (ByVal wFormat As Long) As Long
Public Declare Function CloseClipboard Lib "user32" () As Long
Public Declare Function OpenClipboard Lib "user32" (ByVal hwnd As Long) As Long
Public Declare Function GlobalLock Lib "kernel32" (ByVal hMem As Long) As Long
Public Declare Function GlobalSize Lib "kernel32" (ByVal hMem As Long) As Long
Public Declare Function GlobalUnlock Lib "kernel32" (ByVal hMem As Long) As Long
Public Declare Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" (Destination As Any, Source As Any, ByVal Length As Long)
Public Const CF_TEXT = 1
Public Const CF_BITMAP = 2
Public Const CF_DIB = 8
Sub 验证码识别()
    Dim img
    Dim CtrlRange
    Dim bytClipData() As Byte
    Dim arr() As String
    Dim b(0 To 10)
    Dim c(0 To 10)
    Dim a(1 To 4)
    Dim tmp()
    Dim temp As String
    Dim ts As Integer
    Cells.Clear
    b(0) = "822228"
    b(1) = "22a11"
    b(2) = "333334"
    b(3) = "223337"
    b(4) = "2233a2"
    b(5) = "633335"
    b(6) = "733334"
    b(7) = "233332"
    b(8) = "733337"
    b(9) = "433337"
    c(0) = "0"
    c(1) = "1"
    c(2) = "2"
    c(3) = "3"
    c(4) = "4"
    c(5) = "5"
    c(6) = "6"
    c(7) = "7"
    c(8) = "8"
    c(9) = "9"
    Range("A1:A1").NumberFormatLocal = "@"
    On Error Resume Next
    With CreateObject("InternetExplorer.application")
        .Visible = True
        .Navigate "http://user.kdnet.net/login_new.asp"
        Do Until .ReadyState = 4
            DoEvents
        Loop
        Set img = .Document.all.tags("img")(0)
        Set CtrlRange = .Document.body.createControlRange()
        CtrlRange.Add img
        CtrlRange.execCommand "Copy", True
        Dim hMem As Long, lpData As Long
        OpenClipboard 0&
        hMem = GetClipboardData(8)
        If CBool(hMem) Then
            lpData = GlobalLock(hMem)
            lClipSize = GlobalSize(hMem)
            If lpData <> 0 And lClipSize > 0 Then
                ReDim bytClipData(0 To lClipSize - 1)
                CopyMemory bytClipData(0), ByVal lpData, lClipSize
            End If
            GlobalUnlock hMem
        End If
        CloseClipboard
        a1 = bytClipData(0)
        a2 = bytClipData(4)
        a3 = bytClipData(8)
        a4 = lClipSize - 40
        a5 = a4 / a2 / a3
        ReDim arr(1 To a2 * a3)
        For i = 1 To a2 * a3
            arr(i) = 1
            ts = 0
            For j = 0 To a5 - 1
                ts = ts + Val(bytClipData((i - 1) * a5 + a1 + j))
            Next j
            ts = ts / a5
            If ts > 200 Then
                arr(i) = ""
            End If
        Next i
        For i = 1 To a3
            For j = 1 To a2
                Cells(a3 + 1 - i, j) = arr((i - 1) * a2 + j)
            Next j
        Next i
        temp = ""
        For i = 1 To a2
            For j = 1 To a3
                Cells(a3 + 1, i) = Cells(a3 + 1, i) + arr((j - 1) * a2 + i)
            Next j
            If Cells(a3 + 1, i) = 10 Then Cells(a3 + 1, i) = "a"
            If Cells(a3 + 1, i) <> "" Then
                temp = temp & Cells(a3 + 1, i)
            Else
                temp = temp & ","
                temp = Replace(temp, ",,", ",")
            End If
        Next i
        Cells.Clear
        For j = 0 To 9
            temp = Replace(temp, b(j), c(j))
        Next j
        .Document.all("codestr").Value = Format(Replace(temp, ",", ""), "0000")
        '.Quit
    End With
End Sub

TA的精华主题

TA的得分主题

 楼主| 发表于 2012-8-5 09:15 | 显示全部楼层
本帖最后由 蓝天630902 于 2013-1-31 17:18 编辑

登录凯迪:

登录凯迪.rar

11.59 KB, 下载次数: 163

湖北发票.rar

127.62 KB, 下载次数: 137

TA的精华主题

TA的得分主题

发表于 2012-8-5 15:10 | 显示全部楼层
本帖最后由 cumulonimbus 于 2012-8-5 15:11 编辑
蓝天630902 发表于 2012-8-5 08:07
虽然不推荐凯迪,但还是帮你写好了。

Public Declare Function GetClipboardData Lib "user32" (ByVal w ...


呵呵,只是找了一个网站测试一下你的代码而已。很想知道你的代码辨认验证码的原理是什么?

TA的精华主题

TA的得分主题

发表于 2012-8-5 15:18 | 显示全部楼层
蓝天630902 发表于 2012-8-5 09:15
登录凯迪:

谢谢。很想知道验证码识别技术可否把扫描文件的文字变成文档文字?扫描表格文件变成文档文件?

TA的精华主题

TA的得分主题

发表于 2012-8-5 16:18 | 显示全部楼层
cumulonimbus 发表于 2012-8-5 15:18
谢谢。很想知道验证码识别技术可否把扫描文件的文字变成文档文字?扫描表格文件变成文档文件?

实在是无语了...

顶楼上

TA的精华主题

TA的得分主题

 楼主| 发表于 2012-8-5 17:21 | 显示全部楼层
cumulonimbus 发表于 2012-8-5 15:18
谢谢。很想知道验证码识别技术可否把扫描文件的文字变成文档文字?扫描表格文件变成文档文件?

这些活,已经有很好的工具可以使用。比如说国产的“汉王OCR”、“尚书OCR”等等
外国也有许多非常出色的OCR。

TA的精华主题

TA的得分主题

 楼主| 发表于 2012-8-5 17:28 | 显示全部楼层
cumulonimbus 发表于 2012-8-5 15:10
呵呵,只是找了一个网站测试一下你的代码而已。很想知道你的代码辨认验证码的原理是什么?

不过,还是要谢谢你,你给的目标图片的 biSizeImage=0
我必须在以后写代码时要注意这一点。

TA的精华主题

TA的得分主题

 楼主| 发表于 2012-8-5 17:43 | 显示全部楼层
GetClipboardData(8)方法,所得到的数据,是设备无关位图数据,即我们通常所见到的BMP文件存储结构的格式。
任何格式的图片,Copy后,用GetClipboardData(8)方法,都得到BMP格式。
所以,我们就要了解BMP文件存储结构。

BMP文件存储结构的格式可以在Windows中的WINGDI.h文件中找到定义。(可以到网上下载一个WINGDI.h文件)
DIB 是标准的 Windows 位图格式,设备无关位图,BMP 文件包含了一个 DIB。
一个 BMP 文件包括 4个部分:
1、位图文件头结构 BITMAPFILEHEADER
2、位图信息头结构 BITMAPINFOHEADER
3、调色板 PALETTE
4、位图像素数据
在 WINGDI.h 中定义了前3 个结构(可以用WinHex.exe观察):

第一部分为位图文件头结构BITMAPFILEHEADER,其结构为:
typedef struct tagBITMAPFILEHEADER
{
WORD bfType;  //指定文件类型,必须是0x424D,即字符串“BM”,也就是说所有.bmp 文件的头两个字节都是“BM”。(占2字节)
DWORD bfSize;  //指定文件大小,包括这14 个字节。(占4字节)
WORD bfReserved1;  //为保留字,不用考虑。(占2字节)
WORD bfReserved2;  //为保留字,不用考虑。(占2字节)
DWORD bfOffBits;  //为从文件头到实际的位图数据的偏移字节数,也就是BMP 文件 4个部分中的前三个部分的长度之和。(占4字节)
} BITMAPFILEHEADER, FAR *LPBITMAPFILEHEADER, *PBITMAPFILEHEADER
这个结构的长度是固定的,为14 个字节(WORD 为无符号16 位整数,DWORD 为无符号32 位整数)

第二部分为位图信息头BITMAPINFOHEADER,也是一个结构,其定义如下:
typedef struct tagBITMAPINFOHEADER
{
DWORD biSize;  //指定这个结构(位图信息头BITMAPINFOHEADER)的长度,为40,单位是字节。(占4字节)
LONG biWidth;  //指定图像的宽度,单位是像素。(占4字节)
LONG biHeight;  //指定图像的高度,单位是像素。(占4字节)
WORD biPlanes;  //必须是1。(占2字节)
WORD biBitCount ; //指定表示颜色时要用到的位数,常用的值为1(黑白二色图)、4(16 色图)、8(256 色)、24(真彩色图)新的.bmp格式支持32位色(占2字节)
DWORD biCompression;  //指定位图是否压缩,有效的值为BI_RGB,BI_RLE8,BI_RLE4,BI_BITFIELDS(都是一些Windows定义好的常量)。要说明的是,Windows 位图可以采用RLE4 和RLE8 的压缩格式,但用的不多。(占4字节)
DWORD biSizeImage;  //指定实际的位图数据占用的字节数,其实也可以从以下的公式中计算出来:biSizeImage=biWidth’× biHeight(=4×int((biWidth+3)/4)× biHeight) 要注意的是:上述公式中的biWidth’必须是4 的整倍数(所以不是biWidth,而是biWidth’,表示大于或等于biWidth 的、离4最近的整倍数。举个例子,如果biWidth=240,则biWidth’=240;如果biWidth=241,则biWidth’=244)。如果biCompression 为BI_RGB,则该项可能为零。(占4字节)
LONG biXPelsPerMeter;  //指定目标设备的水平分辨率,单位是每米的像素个数。(占4字节)
LONG biYPelsPerMeter;  //指定目标设备的垂直分辨率,单位同上。(占4字节)
DWORD biClrUsed;  //指定本图像实际用到的颜色数,如果该值为零,则用到的颜色数为2 的biBitCount 次方。(占4字节)
DWORD biClrImportant;  //指定本图像中重要的颜色数,如果该值为零,则认为所有的颜色都是重要的。(占4字节)
} BITMAPINFOHEADER;
这个结构的长度是固定的,为40 个字节(WORD 为无符号16 位整数,DWORD 无符号32 位整数,LONG 为32 位整数)

第三部分为调色板(Palette),当然,这里是对那些需要调色板的位图文件而言的。有些位图,如真彩色图,前面已经讲过,是不需要调色板的,BITMAPINFOHEADER 后直接是位图数据。调色板实际上是一个数组,共有biClrUsed 个元素(如果该值为零,则有2 的biBitCount 次方个元素)。数组中每个元素的类型是一个RGBQUAD 结构,占4 个字节,其定义如下:
typedef struct tagRGBQUAD
{
BYTE rgbBlue; //该颜色的蓝色分量(占1字节)
BYTE rgbGreen; //该颜色的绿色分量(占1字节)
BYTE rgbRed; //该颜色的红色分量(占1字节)
BYTE rgbReserved; //保留值(占1字节)
} RGBQUAD;

第四部分就是实际的图像数据了。对于用到调色板的位图,图像数据就是该像素值在调色板中的索引值,对于真彩色图,图像数据就是实际的R、G、B 值。下面对2 色、16 色、256 色位图和真彩色位图分别介绍。
对于2 色位图,用1 位就可以表示该像素的颜色(一般0 表示黑,1 表示白),所以一个字节可以表示8 个像素。
对于16 色位图,用4 位可以表示一个像素的颜色,所以一个字节可以表示2 个像素。
对于256 色位图,一个字节刚好可以表示1 个像素。
对于真彩色图,三个字节才能表示1 个像素。

注意:
1.每一行的字节数必须是4 的整倍数,如果不是,则需要补齐。这在前面介绍biSizeImage时已经提到了。
2.一般来说,BMP 文件的数据从下到上,从左到右。也就是说,从文件中最先读到的是图像最下面一行的左边第一个像素,然后是左边第二个像素?接下来是倒数第二行左边第一个像素,左边第二个像素?依次类推 ,最后得到的是最上面一行的最右一个像素。
您需要登录后才可以回帖 登录 | 免费注册

本版积分规则

手机版|关于我们|联系我们|ExcelHome

GMT+8, 2024-4-30 21:30 , Processed in 0.041590 second(s), 9 queries , Gzip On, MemCache On.

Powered by Discuz! X3.4

© 1999-2023 Wooffice Inc.

沪公网安备 31011702000001号 沪ICP备11019229号-2

本论坛言论纯属发表者个人意见,任何违反国家相关法律的言论,本站将协助国家相关部门追究发言者责任!     本站特聘法律顾问:李志群律师

快速回复 返回顶部 返回列表