经常刷网页版的抖音,但隔一段时间就会出现验证码,有滑块和文字点选。今天尝试开发一个自动完成验证的插件,但遇到了跨域图片不能直接获得base64数据的问题。

准备插件工具:https://pan.baidu.com/s/1IiSvK8DuftEqeaXI9fZIyg?pwd=j1dm 提取码:j1dm

工具使用说明:

post方式向http://127.0.0.1:2000提交数据
{type:"ocrCode",img:图形base64}      识别文字字母等
{type:"detection",img:图形base64}         识别点选文字范围
{type:"slide",targetImg:滑块base64,backgroundImg:背景base64}        识别滑块
{type:"clickImage",key:"窗口关键字",img:按钮base64}         点击图形按钮
{type:"passKey",key:按键}                   模拟键盘按键
{type:"activityWindow",window:"要激活的窗口标题关键字",key:按键【可选】}          激活窗口并按键
{type:"click"}               点击鼠标
{type:"clickPoint",x:X坐标,y:Y坐标}        指定坐标点击鼠标
{type:"move",x:X坐标,y:Y坐标}               移动鼠标
{type:"moveAndClick",x:X坐标,y:Y坐标}                       移动鼠标到指定坐标再点击
{type:"write",text:"要输入的内容"}           模拟键盘输入文字

第一种:通常获取图片数据直接用canvas drawImage简单直接快速。
但在部分网站中是禁止使用canvas的,所以我就用
第二种:  使用 XMLHttpRequest异步(注意只能异步)读取blob数据转base64。
但如果图片是跨域的,第一、二种都会失效
第三种(支持跨域): 在浏览器插件的background.js中使用 XMLHttpRequest读取图片然后传给inject_script.js 。也可以用于其它数据的读取。
以下代码示例,过抖音验证(文字点选类识别率较低,需要训练模型然后更新到识别程序中才能完善)。

//识别验证码
function ocrFormApi(_data) {
var _code = "本地未开启P娃儿猫验证码识别工具的web服务。";
try {
console.log("提交后台识别中...");
$.ajax({
type: "POST",
url: "http://127.0.0.1:2000/",
timeout: 2 * 1000,
async: false,
data: _data,
success: function (data) {
_code = data;
},
error: function (_d) {
_code = "识别错误";
}
});
} catch (e) {
 
}
return _code;
}
//滑块操作(滑块元素ID,要滑动的距离)
function mockVerify(_imgId, _distance) {
var btn = document.querySelector("#" + _imgId);
var mousedown = document.createEvent('MouseEvents');
var rect = btn.getBoundingClientRect();
var x = rect.x;
var y = rect.y;
mousedown.initMouseEvent('mousedown', true, true, window, 0,
x, y, x, y, false, false, false, false, 0, null);
btn.dispatchEvent(mousedown);
 
var dx = 0;
var dy = 0;
var interval = setInterval(function () {
var mousemove = document.createEvent('MouseEvents');
var _x = x + dx;
var _y = y + dy;
mousemove.initMouseEvent('mousemove', true, true, window, 0,
_x, _y, _x, _y, false, false, false, false, 0, null);
btn.dispatchEvent(mousemove);
console.log("MOVE");
btn.dispatchEvent(mousemove);
if (_x - x >= _distance) {
clearInterval(interval);
var mouseup = document.createEvent('MouseEvents');
mouseup.initMouseEvent('mouseup', true, true, window, 0,
_x, _y, _x, _y, false, false, false, false, 0, null);
btn.dispatchEvent(mouseup);
console.log("END");
}
else {
dx += Math.ceil(Math.random() * 50);
 
}
}, 60);
}
//传入图像元素通过canvas转换
function getImgBase64(_img) {
var canvas = document.createElement("canvas");
canvas.width = _img.naturalWidth;
canvas.height = _img.naturalHeight;
var ctx = canvas.getContext("2d");
ctx.drawImage(_img, 0, 0);
return canvas.toDataURL("image/png").replace("data:image/png;base64,", "");
}
//传入图片地址(不能跨域),通过blob转换(只能异步)
function getImgBase64ByUrl(_url, _success) {
var xhr = new XMLHttpRequest();
xhr.responseType = "blob";
xhr.open("POST", _url, true);
xhr.onload = function (data, textStatus, request) {// 请求完成处理函数
if (this.status === 200) {
var _blob = this.response;// 获取返回值
let _f = new FileReader();
_f.onload = function (_e) {
console.log(_e.target.result);
_success(_e.target.result);
}
_f.readAsDataURL(_blob);
} else {
console.log(this.status);
}
};
xhr.send();
}
function checkCodeOut() {
if ($("#captcha-verify-image:visible").length) {
//获取跨域图片数据(把  getImgBase64ByUrl 中的方法放到插件的background中,因为background没有跨域问题)
window.sendMessage({ type: "getDataFromUrl", data: { url: $("#captcha-verify-image:visible").attr("src"), blob: 1, type: "GET" } }, function (_base64) {
var _backgroundImg = _base64.replace("data:image/jpeg;base64,", "");
//点选文字
if ($("#verify-bar-code:visible").length) {
window.sendMessage({ type: "getDataFromUrl", data: { url: $("#verify-bar-code:visible").attr("src"), blob: 1, type: "GET" } }, function (_base64) {
var _targetImg = _base64.replace("data:image/jpeg;base64,", "");
//识别出要求点选的文字
var _data = ocrFormApi({ type: "ocrCode", img: _targetImg });
//_data = JSON.parse(_data);
var _txt = _data.code;
//识别背景图上的文字及对应坐标
_data = ocrFormApi({ type: "detection", img: _backgroundImg });
console.log(_data)
_data = _data.code;
for (var _i = 0; _i < _txt.length; _i++) {
if (_data[_txt.charAt(_i)]) {
console.log("“" + _txt.charAt(_i) + "”字点击范围:", _data[_txt.charAt(_i)])
} else {
console.log("“" + _txt.charAt(_i) + "”字范围未能识别成功,请刷新。");
$(".secsdk_captcha_refresh--text").click();
}
}
});
}
//滑块
if ($(".captcha_verify_img_slide:visible").length) {
window.sendMessage({ type: "getDataFromUrl", data: { url: $(".captcha_verify_img_slide:visible").attr("src"), blob: 1, type: "GET" } }, function (_base64) {
var _targetImg = _base64.replace("data:image/jpeg;base64,", "");
var _data = ocrFormApi("slide", { type: "slide", targetImg: _targetImg, backgroundImg: _backgroundImg });
console.log("滑块需要操作的数据:", _data);
$(".captcha_verify_img_slide:visible").attr("id", "52pj_slide");
mockVerify("52pj_slide", _data.x);
});
}
});
return;
}
setTimeout(checkCodeOut, 1000);
}
function init() {
var _l = location.href;
if (_l.indexOf("www.douyin.com") != -1) {
checkCodeOut();
return;
}
return;
}
if (typeof $ == 'undefined') {
var s = document.createElement("script");
s.onload = init;
s.src = "https://cdn.bootcss.com/jquery/2.1.4/jquery.min.js";
document.getElementsByTagName("HEAD")[0].appendChild(s);
} else {
init();
}