证码是爬虫程序绕不过的坎,有各种各样的验证码挡在前进的道路上,比如本文将要重点介绍的旋转验证码,网上能找到不少关于这种验证码的逆向方法,整体思路都是一样的,首先需要通过深度学习模型识别出图片的旋转角度,接下来逆向分析加密旋转角度的一系列过程的js代码,根据逆向出的过程构造出对应的参数,模拟验证码验证接口调用实现旋转验证码的识别。
不得不说,独自搞定这一切相当耗时、耗力,而且还可能无功而返,怪不得逆向会经常伴随着掉头发的调侃,即使参照网上大佬们的技术文章,真正实践起来才发现每走一步都可能有坑,有可能是平台反爬策略更新导致和原文已不一致,也可能因为内容比较敏感导致关键细节被故意隐藏,还可能是技术实力欠缺等等。总之,这种逆向的方法让很多人倍感无力,也许硬着头皮研究下去最终可以搞定,但肯定需要花费不少的时间,而时间往往是不够用的。
这里提出另外一种经过验证可行的解决方案,那就是直接模拟用户鼠标操作去拖动滑块实现旋转验证码识别(其他验证码也可以使用这个思路)。简单分析下下面的旋转码操作就可以发现滑块滑到头,图片就旋转了一圈360°,它们之间是线性关系,可以计算出这个比例关系,一旦确定了图片的旋转角度就可以根据这个比例关系换算出滑块滑动的距离,然后模拟拖动滑块就完成了旋转验证码的验证。
这种处理验证码的方式完全不需要去逆向分析前端代码,完全是站在用户的视角在操作,当然它显得不够极客,可能性能也稍差点,但是真的不会掉太多头发,关键是它可以解决问题,不管黑猫白猫,能抓老鼠就是好猫。按照这个思路的话,只需要重点解决下面几个问题:
这一步的目的是提取旋转验证码图片数据,用于接下来使用深度学习模型识别旋转角度。可以通过JavaScript代码创建canvas画布并绘制验证码图像的方式来获取图片数据,如果你使用selenium、playwright这样的自动化框架的话,它们都支持直接执行js代码并获取返回结果。这里需要注意的地方,一是图像元素需要设置允许跨域,否则无法获取到图片数据,而且设置跨域属性会触发重新请求图片,如果设置跨域后立刻绘制图像是获取不到数据的,需要等待响应图片渲染完成。另外一个就是canvas.toDataURL需要指定图片格式为png,因为jpeg是不支持透明背景的,使用jpeg格式会导致旋转角度识别库识别旋转角度完全错误。
// img_selector表示验证码图片选择器
var imgelm=document.querySelector(img_selector);
// 设置允许跨域,否则无法获取图片数据
// TIP:设置跨域后会触发重新请求图片,
// 立刻获取图片尺寸结果为全0,需要等待一段时间重新获取
imgelm.setAttribute("crossOrigin","anonymous");
var canvas=document.createElement('canvas');
var ctx=canvas.getContext('2d');
canvas.width=imgelm.naturalWidth;
canvas.height=imgelm.naturalHeight;
ctx.drawImage(imgelm, 0, 0);
// 注意:jpeg格式不支持透明背景,这里使用png格式
var dataURL=canvas.toDataURL('image/png');
return dataURL;
关于旋转角度识别,可以使用https://github.com/Starry-OvO/rotate-captcha-crack这个模型,这里通过运行server.py开启一个web服务,通过调用接口,传入图片数据会返回识别出的旋转角度。
(使用指导参考:https://cloud.tencent.com/developer/article/2418786)
不过,由于百度旋转验证码图片已经升级,图片全部使用AI生成,更不易识别,当前的模型识别成功率有点低,不过可以通过增加重试来规避这个问题,如果你对深度学习比较熟悉的话也可以使用它的模型重新训练最新的验证码图片。
另外,百度除了会出现旋转验证码之外,有时候也会出现其他类型验证,比如滑块验证码,这种情况就需要同时处理滑块验证码和旋转验证码,思路也是一样的,至于滑块验证码的识别可以使用ddddocr这个库(https://gitee.com/fkgeek/ddddocr),官网文档给出了详细的使用方法。
不管是滑块验证码还是旋转验证码,识别出了图片滑块的距离、旋转角度之后都可以简单地通过线性关系得出拖动滑块的距离,接下来就是模拟滑块拖动指定距离就可以了,下面的js代码实现了模拟拖动滑块的功能。代码中滑动距离仅给出示例,实际运行时请改为换算后的动态值。
()=> {
// selector:滑块选择器 offsetX: 滑动距离
function slide(selector, offsetX) {
// 滑块定位
let slider=document.querySelector(selector);
// 计算滑块矩形区域对角坐标
let rect=slider.getBoundingClientRect(),
x0=rect.x || rect.left,
y0=rect.y || rect.top,
x1=x0 + offsetX,
y1=y0;
// 模拟鼠标按下动作
let mousedown=document.createEvent('MouseEvents');
mousedown.initMouseEvent('mousedown', true, true, window, 0, x0, y0, x0, y0, false, false, false, false, 0, null);
slider.dispatchEvent(mousedown);
//模拟鼠标拖动动作,将滑块移动距离简单拆分为4个相同距离的动作
let mousemove=document.createEvent('MouseEvents');
mousemove.initMouseEvent('mousemove', true, true, window, 0, x0+offsetX/4, y1, x0+offsetX/4, y1, false, false, false, false, 0, null);
slider.dispatchEvent(mousemove);
mousemove.initMouseEvent('mousemove', true, true, window, 0, x0+offsetX/2, y1, x0+offsetX/2, y1, false, false, false, false, 0, null);
slider.dispatchEvent(mousemove);
mousemove.initMouseEvent('mousemove', true, true, window, 0, x0+3*offsetX/4, y1, x0+3*offsetX/4, y1, false, false, false, false, 0, null);
slider.dispatchEvent(mousemove);
mousemove.initMouseEvent('mousemove', true, true, window, 0, x0+offsetX, y1, x0+offsetX, y1, false, false, false, false, 0, null);
slider.dispatchEvent(mousemove);
// 模拟鼠标释放动作
let mouseout=document.createEvent('MouseEvents');
mouseout.initMouseEvent('mouseup', true, true, window, 0, x1, y1, x1, y1, false, false, false, false, 0, null);
slider.dispatchEvent(mouseout);
}
// 执行滑块拖动,以下distance和滑块选择器只是示例,根据实际情况进行调整
var distance=200;
slide('div.passMod_slide-btn', distance);
}
最后,展示一下通过上面的思路使用playwright实现的旋转验证码的识别过程,本次出现了两次验证码,第一次是滑块验证码,通过后又出现了旋转验证码,可以发现旋转验证码识别了3次才成功,就是因为模型对于最新的百度旋转验证码图片角度识别率变差导致的,实现上通过增加重试次数进行规避。经测试,无界面模式也可以正常运行。
参考文献:
[1] https://cloud.tencent.com/developer/article/2418786
[2] https://github.com/Starry-OvO/rotate-captcha-crack
[3] https://gitee.com/fkgeek/ddddocr
[4] https://blog.csdn.net/m0_58618019/article/details/132918404
网页设计工作中,我们可以给很多元素添加发光的动画效果,举几个例子,“输入框”、“文字”、“进度条”等。给这些元素加上的发光特效会让整个网页变得更加炫酷。今天陕西优就业小编就为大家搜集整理了8款炫酷的HTML发光动画,这些都可以用作Web前端开发工作中,可以为你节省很多开发时间。
1.HTML5 Canvas五彩缤纷的3D发光水晶球动画
这是一款基于HTML5 Canvas的超绚丽发光水晶球动画,就像是酒吧里的那种水晶球射灯一样,不停地随机变换射出光线的颜色,给人一种非常动感的视觉效果。整个水晶球是在Canvas画布上绘制而成,利用CSS3的相关特性使其能够出现五彩缤纷的发光动画,而且可以通过鼠标滚轮来放大缩小这个水晶球,不得不说HTML5真的是非常强大。
2.jQuery/CSS3实现漂亮字体发光特效
今天我们要来分享一款很酷的jQuery/CSS3文字发光特效,首先是加载了谷歌的公共字体库,因此字体非常特别和漂亮,另外利用了jQuery和CSS3的相关特性,当鼠标滑过文字时,文字将会出现发光的动画特效,非常漂亮。
3.超绚丽CSS3多色彩发光立方体旋转动画
之前我们分享过几个不错的CSS3立方体动画,比如这款HTML5 3D立方体旋转动画和HTML5 3D立方体图片切换动画。今天要分享的也是一款基于CSS3的3D立方体旋转动画,不同的是,这款立方体的每一个面都有不同的色彩,并且会带有绚丽的发光特效。
4.纯CSS3实现发光开关切换按钮
前段时间我们向大家分享过一款牛奶般剔透的CSS3 3D开关按钮,效果相当赞。今天我们要来分享一款类似的纯CSS3发光开关切换按钮,它的外观就像一个电灯的开关,可以左右切换。另外开关上的文字还有发光的特效,整体看上去很有立体感。
5.纯CSS3和SVG鼠标滑过灯泡发光特效
这次要分享一款利用纯CSS3和SVG实现的灯泡发光效果,我们只需要将鼠标滑过灯泡,整个灯泡就会出现发光发亮的动画特效,效果相当逼真。CSS3的运用,让灯泡外围有一层淡淡的光晕。并且在灯光点亮和熄灭的时候有淡入淡出的效果。
6.HTML5 Canvas发光Loading动画
之前我们分享过很多基于CSS3的Loading动画效果,相信大家都很喜欢。今天我们要来分享一款基于HTML5 Canvas的发光Loading加载动画特效。Loading旋转图标是在canvas画布上绘制的,整个loading动画是发光3D的视觉效果,HTML5非常强大。
7.CSS3发光Loading加载动画
今天我们要分享一款与众不同的CSS3 Loading动画效果,它是由几个不同的动画效果组合而成的,像文字打印效果、发光效果、飞入飞出效果,这几种效果都非常酷。另外我们可以再回顾一下其他的CSS3 Loading效果:HTML5 Canvas实现超酷Loading动画、很有个性的CSS3弹跳Loading动画。
8.纯CSS3实现发光动画按钮特效
这是一款基于纯CSS3的发光按钮,按钮发光的颜色是随机的,这样一排按钮就显得五彩缤纷,非常绚丽。之前我们也介绍过不少样式很独特的CSS3按钮,比如纯CSS3 3D开关按钮、纯CSS3实现动感弹性按钮等,都非常不错,也有HTML5动画按钮,大家可以自己看看。
陕西优就业:http://www.ujiuye.com/shaanxi/
IT学习交流:468910291
源于公众号前埔寨 ,
作者荣顶
我们想在画布上画个基本的简单形状的时候,使用 Canvas 不会觉得有什么繁琐。但当画布上需要任何形式的互动,绘制复杂的图形和在特定情况需要改变图片的时候,使用原生 canvas API 将会变得很困难。
而 Fabric 旨在解决这个问题。
Fabric.js 是一个强大而简单的 Javascript HTML5 画布库 Fabric 在画布元素之上提供交互式对象模型 Fabric 还具有 SVG-to-canvas(和 canvas-to-SVG)解析器
为了方便,下面我将通过 vue项目 为大家讲解如何使用 Fabric
yarn add fabric -S
#or
npm i fabric -S
也可以在 官网 下载最新 js 文件,通过 script 标签引入
<!-- html -->
<canvas id="canvas" width="500" height="500"></canvas>
Fabric 提供了 7 种基础形状:
fabric.Circle (圆)
fabric.Ellipse (椭圆)
fabric.Line (线)
fabric.Polyline (多条线绘制成图形)
fabric.triangle (三角形)
fabric.Rect (矩形)
fabric.Polygon (多边形)
//引入fabric
import { fabric } from "fabric";
// 创建一个fabric实例
let canvas=new fabric.Canvas("canvas"); //可以通过鼠标方法缩小,旋转
// or
// let canvas=new fabric.StaticCanvas("canvas");//没有鼠标交互的fabric对象
// 创建一个矩形对象
let rect=new fabric.Rect({
left: 200, //距离左边的距离
top: 200, //距离上边的距离
fill: "green", //填充的颜色
width: 200, //矩形宽度
height: 200, //矩形高度
});
// 将矩形添加到canvas画布上
canvas.add(rect);
可以看到界面中填充了一个可以通过鼠标放大缩小且可以旋转的绿色矩形
通过对象的形式配置元素样式,非常的方便!
let circle=new fabric.Circle({
left: 0, //距离左边的距离
top: 0, //距离上边的距离
fill: "red", //填充的颜色
radius: 50, //圆的半径
});
// 创建一个三角形对象
let triangle=new fabric.Triangle({
left: 200, //距离左边的距离
top: 0, //距离上边的距离
fill: "blue", //填充的颜色
width: 100, //宽度
height: 100, //高度
});
// 将图形形添加到canvas画布上
canvas.add(circle, triangle);
我们可以通过以下属性设置,决定是否可以对相关元素进行交互
rect.set("selectable", false); // 只是禁止这个矩形选中
主要有通过 url 和 img 标签绘制两种方式
fabric.Image.fromURL(
//本地图片需要通过require来引入,require("./xxx.jpeg")
"https://gimg2.baidu.com/image_search/src=http%3A%2F%2Fimg.thaihot.com.cn%2Fuploadimg%2Fico%2F2021%2F0711%2F1625982535739193.jpg&refer=http%3A%2F%2Fimg.thaihot.com.cn&app=2002&size=f9999,10000&q=a80&n=0&g=0n&fmt=jpeg?sec=1630940858&t=e1d24ff0a7eaeea2ff89cedf656a9374",
(img)=> {
img.scale(0.5);
canvas.add(img);
}
);
//也可以通过标签绘制
let img=document.getElementById("img");
let image=new fabric.Image(img, {
left: 100,
top: 100,
opacity: 0.8,
});
canvas.add(image);
在此之前我们需要了解几个参数的含义
customPath.set({
left: 100,
top: 100,
fill: "green",
});
canvas.add(customPath);
"M 0 0 L 300 100 L 170 100 L 70 300 L 20 200 C136.19,2.98,128.98,0,121.32,0 z"
);
可以看到通过路径绘制,我们可以制作非常复杂的图形(但是一般用不到,我们一般用它来解析 SVG 后拿到 path 复原图形)
第一个参数是动画的属性,第二个参数是动画的最终位置,第三个参数是一个可选的对象,指定动画的细节:持续时间,回调,动效等。
第三个参数主要有
duration 默认为 500ms。可以用来改变动画的持续时间。
from 允许指定动画属性的起始值(如果我们不希望使用当前值)。
onComplete 动画结束之后的回调。
easing 动效函数。
let rect=new fabric.Rect({
left: 400, //距离左边的距离
top: 200, //距离上边的距离
fill: "green", //填充的颜色
width: 200, //宽度
height: 200, //高度
});
rect.animate("left", 100, {
onChange: canvas.renderAll.bind(canvas),
duration: 1000,
});
canvas.add(rect);
onChange: canvas.renderAll.bind(canvas),
duration: 1000,
});
rect.animate("angle", "-=90", {
onChange: canvas.renderAll.bind(canvas),
duration: 2000,
});
默认情况下,动画使用“easeInSine”动效执行。如果这不是你需要的,fabric 为我们提供了很多内置动画效果, fabric.util.ease 下有一大堆动效的选项。
常用的有easeOutBounce,easeInCubic,easeOutCubic,easeInElastic,easeOutElastic,easeInBounce 和 easeOutExpo等
onChange: canvas.renderAll.bind(canvas),
duration: 1000,
easing: fabric.util.ease.easeOutBounce,
});
目前 Fabric 为我们提供了以下内置滤镜
img.scale(0.5);
canvas.add(img);
});
fabric.Image.fromURL(require("./aaa.jpeg"), (img)=> {
img.scale(0.5);
// 添加滤镜
img.filters.push(new fabric.Image.filters.Grayscale());
// 图片加载完成之后,应用滤镜效果
img.applyFilters();
img.set({
left: 300,
top: 250,
});
canvas.add(img);
});
“filters”属性是一个数组,我们可以用数组方法执行任何所需的操作:移除滤镜(pop,splice,shift),添加滤镜(push,unshift,splice),甚至可以组合多个滤镜。当我们调用 applyFilters 时,“filters”数组中存在的任何滤镜将逐个应用,所以让我们尝试创建一个既色偏又明亮(Brightness)的图像。
img.scale(0.5);
// 添加滤镜
img.filters.push(
new fabric.Image.filters.Grayscale(),
new fabric.Image.filters.Sepia(), //色偏
new fabric.Image.filters.Brightness({ brightness: 0.2 }) //亮度
);
// 图片加载完成之后,应用滤镜效果
img.applyFilters();
img.set({
left: 300,
top: 250,
});
canvas.add(img);
});
可以看到多个滤镜的效果叠加显示了,当然 Fabric 还支持自定义滤镜,在本篇文章点赞过 500 后我将更新 fabric 高级篇,感谢大家的支持~
无论你是使用十六进制,RGB 或 RGBA 颜色,Fabric 都能处理的很好
new fabric.Color("#aa3123");
new fabric.Color("356333");
new fabric.Color("rgb(100,50,100)");
new fabric.Color("rgba(100, 200, 30, 0.5)");
new fabric.Color('rgb(100,100,100)').toHex(); // "646464"
new fabric.Color('fff').toHex(); // "FFFFFF"
我们还可以用另一种颜色叠加,或将其转换为灰度版本。
let greenish=new fabric.Color("#5f5");
redish.overlayWith(greenish).toHex(); // "AAAA55"
redish.toGrayscale().toHex(); // "A1A1A1"
Fabric 通过 setGradient 方法支持渐变,在所有对象上定义。调用 setGradient('fill', { ... })就像设置一个对象的“fill”值一样。
left: 100,
top: 100,
radius: 50
});
circle.setGradient("fill", {
// 渐变开始的位置
x1: 0,
y1: 0,
// 渐变结束的位置
x2: circle.width,
y2: 0,
//渐变的颜色
colorStops: {
// 渐变的范围(0,0.1,0.3,0.5,0.75,1)0-1之间都可以
0: "red",
0.2: "orange",
0.4: "yellow",
0.6: "green",
0.8: "blue",
1: "purple"
},
});
fabric.Text 对象对于文本,提供了比 canvas 更丰富的功能,包括:
支持多行 Multiline support 不幸的是,原生文本方法忽略了新建一行。
文本对齐 Text alignment 左,中,右。使用多行文本时很有用。
文本背景 Text background 背景也支持文本对齐。
文字装饰 Text decoration 下划线,上划线,贯穿线。
行高 Line Height 在使用多行文本时有用。
字符间距 Char spacing 使文本更紧凑或更间隔。
子范围 Subranges 将颜色和属性应用到文本对象的子对象中。
多字节 Multibyte 支持表情符号。
交互式画布编辑 On canvas editing 可以直接在画布上键入文本。
"大家好~这里是前埔寨\n我是荣顶~\n一个要成为开发王的男人!",
{
left: 0,
top: 200,
fontFamily: "Comic Sans", //字体
fontSize: 50, //字号
fontWeight: 800, //字体粗细,可以使用关键字(“normal”,“bold”)或数字(100,200,400,600,800)
shadow: "green 3px 3px 2px", //文字阴影,颜色,水平偏移,垂直偏移和模糊大小。
underline: true, //下划线
linethrough: true, //删除线
overline: true, //上划线
fontStyle: "italic", //字体风格,normal(正常)或italic(斜体)
stroke: "#c3bfbf", //描边的颜色
strokeWidth: 1, //描边的宽度
textAlign: "center", //文本对齐方式
lineHeight: 1.5, //行高
textBackgroundColor: "#91A8D0", //文本背景颜色
}
);
canvas.add(text);
fabric 中通过 on 方法来初始化事件,off 方法用来删除事件。常用的事件有以下
还有一大堆:
鼠标事件:“mouse:down” ,“mouse:move”和“mouse:up...” 选择相关的事件:“before:selection:cleared”, “selection:created”, 详细的可以查看 官方文档
canvas.clear();
let text=new fabric.Text("你点我啦~", {
left: 200,
top: 200,
});
canvas.add(text);
console.log(options.e.clientX, options.e.clientY);
});
canvas.on("mouse:up", function(options) {
this.text="你没点我0.0";
canvas.clear();
let text=new fabric.Text("你没点我0.0", {
left: 200,
top: 200,
});
canvas.add(text);
console.log(options.e.clientX, options.e.clientY);
});
Fabric 允许将侦听器直接附加到 canvas 画布中的对象上。
rect.on("selected", function() {
console.log("哦吼~你选择了我");
});
let circle=new fabric.Circle({ radius: 75, fill: "blue" });
circle.on("selected", function() {
console.log("哈哈哈~你选择了我");
});
Fabric canvas 的 isDrawingMode 属性设置为 true 即可实现自由绘制模式.
这样画布上的点击和移动就会被立刻解释为铅笔或刷子。
canvas.isDrawingMode=true;
canvas.freeDrawingBrush.color="blue";
canvas.freeDrawingBrush.width=5;
很开心写下这篇文章,它是我用来总结归纳 fabric 的知识点,并且非常用心的一篇文章,希望这篇文章对你有所帮助。目前 fabric 在国内还不是很火,但是 github 上已经有 19.2k 的 star 了,也算是一个明星项目。我们日常开发经常会用到 canvas,但是它的 api 对于处理复杂的业务逻辑会令人感到非常的劳累,分享这篇文章,希望对大家有所帮助!
*请认真填写需求信息,我们会在24小时内与您取得联系。