一、背景
某投票活动依托著名低代码平台生成,未强绑定用户信息投票。
二、分析
(1)通过captcha/get
接口获取base64的二维码图片,需要依据wordList
字段按顺序点击对应文字。
![]()
(2)对用户点击的范围信息进行签名,通过/captcha/check
回传服务端进行验证。
![]()
(3)验证签名正确后,调用投票接口进行投票
![]()
因为验证码需要按固定顺序文字进行点击,这也意味着除了通过机器学习识别文字位置自动点击外,几乎没有能够自动化的方法了。
三、方案
即使是半自动运行,相对比手动一项项点选,半自动也可以提升不少效率。
整个投票流程如下:
- 选择N个投票项目。
- 点击投票按钮。
- 点击验证码。
- 投票成功进入结果页,点击再次点赞。
(1)第一版半动化脚本
策略:通过F12打开浏览器控制台,输入脚本实现自动选择项目+触发投票按钮。
![]()
这一版的脚本实现了第一步、第二步的自动功能,缺点是每次投票成功返回上一页后,需要重新在控制台输入代码。
(2)第二版半动化脚本
策略:通过浏览器的Oversides Content功能,手动往投票页面中注入JS脚本,实现在该页面的自动功能。
![]()
这一版遇到一个问题:在页面未完全加载时,脚本已经运行完毕(找不到元素而报错)。尝试了JQuery的ready方法和dom原生加载属性,但这俩都是页面文档下载完毕时就触发了,不满足等待页面元素渲染完成的需求。
解决办法也简单,增加一个Timer定时器,定时扫描页面上的元素是否存在,存在及触发点击即可。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| var isChecked = false; const scanTime = setInterval(function () { console.log('scaning...') if (document.querySelector('.image-vote-*** .vote-button') !== null && !isChecked) { console.log('scaning success! auto click!') clearInterval(scanTime) isChecked = true; document.querySelector('.image-vote-*** .vote-button').click(); setTimeout(() => { document.querySelector('.image-vote-*** .vote-button').click(); setTimeout(() => { document.querySelector('.popover-submit-btn div').click(); }, 100); }, 50); } }, 200);
|
但这时候又遇到一个问题,注入JS至页面后,每次提交都会出现”请刷新页面后重试”的报错。我怀疑每次投票时会对页面HTML进行md5签名提交至后端验证完整性,于是尝试注入至其他引用的JS文件中,测试后可行。
至此解决了每次投票后刷新页面,需要重新在控制台输入代码的问题。
(3)第三版半动化脚本
策略:目前第一、第二步已完成,第三步无法自动化,但第四步自动返回却是可以实现的。
又增加了一个Timer,监听页面的再次点赞按钮,出现时则自动点击返回上一页。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
| var isChecked = false; const scanTime = setInterval(function () { console.log('scaning...') if (document.querySelector('.image-vote-*** .vote-button') !== null && !isChecked) { console.log('scaning success! auto click!') clearInterval(scanTime) isChecked = true; document.querySelector('.image-vote-*** .vote-button').click(); setTimeout(() => { document.querySelector('.image-vote-*** .vote-button').click(); setTimeout(() => { document.querySelector('.popover-submit-btn div').click(); }, 100); }, 50); } }, 200);
var isChecked2 = false; const scanTime2 = setInterval(function () { console.log('scaning...') if (document.querySelector('.submit-again-keys') !== null && !isChecked2) { console.log('scaning success! auto click!') clearInterval(scanTime2) isChecked2 = true; document.querySelector('.submit-again-keys').click(); } }, 100)
|
至此已完成了1、2、4步骤的自动化,第三步验证码仍需要手动操作。但已经把完整投票流程精简到了无脑打码的复杂度,整个投票速度也大幅度上升。
![]()
四、拓展
直到活动最后,也没有用JS实现自动操作验证码,但这并不代表无法实现这个功能。在Github上有一些开源项目,实现了Python自动识别、点击的功能(如:captcha_crack)。虽然通过BrowerJS调用Python的想法不太现实,但是通过Chrome插件转发验证码却是可以尝试的,整个思路大致如下:
- 读取验证码:通过提取dom元素或通过验证码生成接口来获取Base64图片。
- 转发验证码:通过websoket进行图片转发,调用Python服务。
- 识别验证码:等待Python服务识别,再通过websocket返回文字及其位置。
- 点击验证码:通过Chrome插件API模拟点击指定位置。