ExcelHome技术论坛

 找回密码
 免费注册

QQ登录

只需一步,快速开始

快捷登录

搜索
EH技术汇-专业的职场技能充电站 妙哉!函数段子手趣味讲函数 Excel服务器-会Excel,做管理系统 效率神器,一键搞定繁琐工作
HR薪酬管理数字化实战 Excel 2021函数公式学习大典 Excel数据透视表实战秘技 打造核心竞争力的职场宝典
让更多数据处理,一键完成 数据工作者的案头书 免费直播课集锦 ExcelHome出品 - VBA代码宝免费下载
用ChatGPT与VBA一键搞定Excel WPS表格从入门到精通 Excel VBA经典代码实践指南
查看: 857|回复: 11

[原创] vb.net+VBA+js网络图片ocr识别

[复制链接]

TA的精华主题

TA的得分主题

发表于 2024-1-7 06:29 | 显示全部楼层 |阅读模式
网友【wodewan】共享的文章《带带弟弟OCR,纯VBA本地获取网络验证码整体解决方案》,的确好。好就好在,代码开源、心思巧妙、对于不同类型的验证码图片,识别率在90%及以上。向网友【wodewan】和DdddOcr作者致以崇敬。


在【wodewan】共享代码下,彻底解决了:俗话说得,最后一公里。那就是最终得到了验证码文字。由于本人非专业码字,仅是业余爱好,所以代码部分是否美观简洁强悍不是俺的菜,俺信奉的是能否解决问题,其次才是去追求技术升级。第一步都踏不出去,何来其它,呵呵。

TA的精华主题

TA的得分主题

 楼主| 发表于 2024-1-7 06:30 | 显示全部楼层
[广告] VBA代码宝 - VBA编程加强工具 · VBA代码随查随用  · 内置多项VBA编程加强工具       ★ 免费下载 ★      ★使用手册
分步解决思路:
一、获取网络验证码图片
置于技术网友提出的那些个专业术语,例如“跨域、同源”俺技术不到位也不想看,管它咋滴,只要能够达到目的就行。
二、识别验证码图片中的内容为可编辑文字
主要针对【文字】类型图片验证码测试。其它的类型(相似图、拉动)暂不涉及。
三、自动填写三码(准考、身份、验证)【用户名、密码、验证码】,(查询)按钮一点击。
由于在该站没有实际查询需要,只能测试到这一步。至于编程获得查询结果,分析结果,这都不是问题。

编程环境:
系统:widows server 2022
语言:微软visual studio 2022(vb.net、c#)、VBA
64位浏览器控件:谷歌内核cefsharp (chromium_90.6.7_windows64)技术版(可以展示图文音视)。
为啥不用其他cefsharp版本呢?因为要考虑兼容windows 7(10),不支持xp。
为啥是64位而不是32位,或者兼有?能逮住老鼠的都是好猫,碰到哪个用哪个,不纠结
为啥不用微软的【WebBrowser 】控件呢?不是不想用,是有些网站不支持该浏览器控件,显示不出来网络验证码图片。
其它:网页js

TA的精华主题

TA的得分主题

 楼主| 发表于 2024-1-7 06:31 | 显示全部楼层
技术实现:

必须的引入语句
Imports System.IO
Imports System.Runtime.InteropServices
Imports CefSharp

窗体load阶段
System.Windows.Forms.Control.CheckForIllegalCrossThreadCalls = False
'程序初始化的时候设置了这个属性,而且在你的控件中使用的都是微软Framework类库中的控件的话,系统就不会再抛出错误了。

一、获取网页中的验证码图片或者URL
1、获取截图(略,也实现了)
2、通过元素ID属性(更简便)获取所需信息,以img为例获取它的src网址
JS语句 = "var divElement = document.getElementById('" + ID关键词 + "');divElement.src"
3、必要的转换过程,不能直接用PictureBox 控件使用获得的验证码图片网址获取图像,否则得到的是不停变换的网络验证码图片,而不是想要得到的那个正确的图片
代码(略)
提示:经过这三步,已经得到了网页显示的验证码图片,下一步就是使用网友【wodewan】共享的文章《带带弟弟OCR,纯VBA本地获取网络验证码整体解决方案》中的代码,去识别验证码图片转换为可编辑验证码文字
二、保存第一步获取的图片(也可以参考其他网友关于不保存直接识别的文章,这里首先实际解决获取图片,识别文字问题)
三、封装VBA,识别验证码
'调用VBA,获取识别后的验证码
CallVbaFunction()
提示:网友【wodewan】共享的Excel VBA,需要在原有基础上改写并增加一个新的Function 返回值(path As String)函数,以便vb.net从其函数中获取验证码返回值
四、分别获取三码(准考、身份、验证)【用户名、密码、验证码】元素,并进行自动填写
准考码填写框类型:input,ID=ksbh
身份码填写框类型:input,ID=zjhm
验证码填写框类型:input,ID=yzm

提示:自动填写代码,建议写入到Timer控件中,然后通过按钮开启
TM登录.Enabled = True

---------------------------
需要改进的部分:
1、由于网络验证码图片识别过程中,需要保存、需要调用Excel VBA,会造成返回值微妙的延迟。
暂时没有解决将网友【wodewan】共享的Excel VBA改写为vb.net直接执行
2、如果涉及多人查询,可以自行添加access数据库轮查
3、元素的ID查询,需要手工确认。如果没有ID,需要使用其它js语句(根据:name等)去准确定位
4、可以逐步添加【准考码、身份码】防错机制
5、有的网站网络验证码,并不是放在img元素中,而是放在div等容器中,实现图片提取过程无非就是先提取div的背景图片网址,然后新建一个img放入页面中,然后就可以了。
当然,也可以通过直接截取div等元素的图片方式获取到图片,实现过程也不复杂,无非就是定位获取。

TA的精华主题

TA的得分主题

 楼主| 发表于 2024-1-7 06:35 | 显示全部楼层
'详细vb.net代码:参见附件

2024-01-07 06 27 13.jpg

vb.net VBA js代码.zip

4.86 KB, 下载次数: 23

实际代码

TA的精华主题

TA的得分主题

 楼主| 发表于 2024-1-7 06:39 | 显示全部楼层
对以上类型的图片,ddddocr识别率相当高,经过测试,实际识别率90%以上。
不需要对获取的图片黑白处理,直接彩色模式下的识别率就足以了,所以也就省略了那些黑白化、二值化、分割的过程

TA的精华主题

TA的得分主题

 楼主| 发表于 2024-1-7 06:46 | 显示全部楼层
vb.net代码的过程实现,参考了诸多网友的c#代码,就不一一感谢了。都是开源共享的。本来想将全部代码改写,无奈水平所限,暂时没有实现。

TA的精华主题

TA的得分主题

 楼主| 发表于 2024-1-7 08:40 | 显示全部楼层
[广告] VBA代码宝 - VBA编程加强工具 · VBA代码随查随用  · 内置多项VBA编程加强工具       ★ 免费下载 ★      ★使用手册
提示:
vb.net获取div元素背景图片,分为以下几个步骤:

'0、因为要在网站的网页中插入一个新建的img元素(通过网址)用来显示div背景图片,为了防止生成多个相同ID的元素,首先检查是否存在指定的ID元素,如果有,就删除,以便新建
'因为id本身的对象不能删除自己 ,所以要先通过 idObject.parentNode得到父节点,然后把本id对象传入进行删除.

'1、获取div背景图片URL地址
'将获取的图片网址的无效部分去除,只保留网址部分
''前5个字符:url("
'后2个字符:")

'2、创建<img>元素
'将<img>元素添加到网页中的某个元素中,通常是用img,document.body.afterend,不扰乱验证码网页原来布局

'3、将指定ID元素中的图片,转换成base64编码,并显示到vb.net的PictureBox3图片控件中
'获取指定ID元素图片的base64编码
'将base64编码中的无效字符去除,前缀去除
' 去除前缀base64编码,转换为 byte[] 类型
' 创建内存流并加载图像数据,到PictureBox图片控件
'等比例放大图像,以便观察图片

其它识别、自动填写等代码,参照
《vb.net VBA js代码.zip》

TA的精华主题

TA的得分主题

 楼主| 发表于 2024-1-7 08:42 | 显示全部楼层
[广告] Excel易用宝 - 提升Excel的操作效率 · Excel / WPS表格插件       ★免费下载 ★       ★ 使用帮助
vb.net获取div背景图片地址

vb.net获取div背景图片地址.zip

2.89 KB, 下载次数: 14

TA的精华主题

TA的得分主题

 楼主| 发表于 2024-1-7 08:50 | 显示全部楼层
由于网友【wodewan】共享的文章《带带弟弟OCR,纯VBA本地获取网络验证码整体解决方案》中提供的单文件dll库DdddOcr.dll,本网站不支持容量较大文件上传,可以去本站网址https://club.excelhome.net/thread-1666823-1-1.html去下载那个分割压缩包

TA的精华主题

TA的得分主题

 楼主| 发表于 2024-1-7 20:11 | 显示全部楼层
[广告] VBA代码宝 - VBA编程加强工具 · VBA代码随查随用  · 内置多项VBA编程加强工具       ★ 免费下载 ★      ★使用手册
VBA设置外部DLL库(非系统函数库)和其他文件的相对路径
---------------------------
问题:在使用网友【wodewan】《带带弟弟OCR,纯VBA本地获取网络验证码整体解决方案》VBA时,我们会调用外部的Dll文件,而此DLL文件会随着打包程序的发放,而放在不同的目录。由于Dll文件就放置在执行文件的一个相对路径下,这时在程序内部定义调用Dll文件时,其定义的路径为相对路径。然而很多时候程序并不能识别到定义的Dll文件路径。如何让程序自动识别相对路径,即为本问题所在!

解决:设置指定路径为当前系统目录即可。使用的API函数为SetCurrentDirectoryA

例子:

'下面的例子是,在VBA要执行的代码里,需要调用外部Dll文件"DdddOcr.dll"里的三个函数【Init、Shutdown、Classification】,而外部这个Dll文件放在当前激活文件目录下"\DdddOcr.dll",在执行三个函数前,直接使用SetCurrentDirectoryA设置当前目录即可。
'另外,保存图片文件的目录【相对路径】也存储在当前目录之下
'DdddOcr.dll、DdddOcr-V2.xlsm、网络验证码图片(文件夹),要位于同一个文件内,也就是Excel文件DdddOcr-V2.xlsm所在的路径内
'系统函数无须指定所在路径

看代码:

'注意这是API函数SetCurrentDirectory 的申明
Public Declare Function SetCurrentDirectory Lib "kernel32" Alias "SetCurrentDirectoryA" (ByVal lpPathName As String) As Long


'注意当中相对路径的写法:.(英文句点)+\(斜杠)+DLL链接库全名(含.dll)

Declare PtrSafe Sub Init Lib ".\DdddOcr.dll" ()
Declare PtrSafe Sub Shutdown Lib ".\DdddOcr.dll" Alias "Close" ()
Declare PtrSafe Function Classification Lib ".\DdddOcr.dll" (ByRef aa As Byte) As LongPtr

'--------------------------------
'Sub main函数中要调用保存图片文件的【相对路径】
Sub main()
    Dim path As String, i As Long, pathbase As String

    '很重要,设置当前激活目录
    SetCurrentDirectory (Application.ActiveWorkbook.path)
    pathbase = ThisWorkbook.path

        'path = ThisWorkbook.path & "\pics\" & i & ".png"

        '保存图片的相对目录路径
        path = ".\网络验证码图片\网络验证码图片.jpg" '1.png
        'Debug.Print (GetStr(path))
        'ThisWorkbook.Sheet1.Cells(1, 1) = GetStr(path)
        Sheets("Sheet1").Cells(1, 1) = GetStr(path)

End Sub
'--------------------------------
'Function GetStr(path As String)函数中要调用DdddOcr.dll库的Init、Shutdown
'获取识别结果
Function GetStr(path As String)
    '很重要,设置当前激活目录
    SetCurrentDirectory (Application.ActiveWorkbook.path)

    Dim address, str As String, bytearr() As Byte
    str = Pic2Base64(path)
    bytearr = StrConv(str, vbFromUnicode)
   '调用DdddOcr.dll库函数Init
   Init
        address = Classification(bytearr(0))
        GetStr = StringFromPointerA(address)
    Shutdown
End Function

致谢:剑客Training
http://blog.163.com/shikang999@1 ... 896201510225924807/
您需要登录后才可以回帖 登录 | 免费注册

本版积分规则

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

GMT+8, 2024-11-19 11:42 , Processed in 0.040560 second(s), 11 queries , Gzip On, MemCache On.

Powered by Discuz! X3.4

© 1999-2023 Wooffice Inc.

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

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

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