订阅:新手可以订阅我的其他专栏。免费阶段订阅量1000+
说明:本专栏持续更新中,订阅本专栏前必读关于专栏〖Python网络爬虫实战〗转为付费专栏的订阅说明
作者:爱吃饼干的小白鼠。Python领域优质创作者,2022年度博客新星top100入围,荣获多家平台专家称号。
最近更新
极验验证码
目前,许多网站采取各种各样的措施来反爬虫,其中一个措施便是使用验证码。随着技术的发展,验证码的花样越来越多。验证码最初是几个数字组合的简单的图形验证码,后来加入了英文字母和混淆曲线。有的网站还可能看到中文字符的验证码,这使得识别愈发困难。我们今天来介绍极验验证码。
前言
我们上一篇和大家介绍了怎么去处理图片的还原,今天,我们来说说怎么去计算滑块移动的距离,我们可以通过open-cv来识别,或者其他识别库来识别,我们还可以对比两个图片的像素点。这些都可以直接用别人写好的代码,我这里就不过多赘述。
滑块距离计算
第一种是cv2方法,我找到别人写的比较好的,亲测可用,至于相关库的安装,自己去搜教程。
python
import io
from PIL import Image
import cv2
import numpy as np
# 将 Image 转换为 Mat,通过 flag 可以控制颜色
def pilImgToCv2(img: Image.Image, flag=cv2.COLOR_RGB2BGR):
return cv2.cvtColor(np.asarray(img), flag)
# 弹窗查看图片
def showImg(bg: cv2.Mat, name='test', delay=0):
cv2.imshow(name, bg)
cv2.waitKey(delay)
cv2.destroyAllWindows()
def getDistance(img: Image.Image, slice: Image.Image):
# 通过 pilImgToCv2 将图片置灰
# 背景图和滑块图都需要做相同处理
grayImg = pilImgToCv2(img, cv2.COLOR_BGR2GRAY)
# showImg(grayImg) # 可以通过它来看处理后的图片效果
graySlice = pilImgToCv2(slice, cv2.COLOR_BGR2GRAY)
# 做边缘检测进一步降低干扰,阈值可以自行调整
grayImg = cv2.Canny(grayImg, 255, 255)
# showImg(grayImg) # 可以通过它来看处理后的图片效果
graySlice = cv2.Canny(graySlice, 255, 255)
# 通过模板匹配两张图片,找出缺口的位置
result = cv2.matchTemplate(grayImg, graySlice, cv2.TM_CCOEFF_NORMED)
maxLoc = cv2.minMaxLoc(result)[3]
# 匹配出来的滑动距离
distance = maxLoc[0]
# 下面的逻辑是在图片画出一个矩形框来标记匹配到的位置,可以直观的看到匹配结果,去掉也可以的
sliceHeight, sliceWidth = graySlice.shape[:2]
# 左上角
x, y = maxLoc
# 右下角
x2, y2 = x + sliceWidth, y + sliceHeight
resultBg = pilImgToCv2(img, cv2.COLOR_RGB2BGR)
cv2.rectangle(resultBg, (x, y), (x2, y2), (0, 0, 255), 2)
# showImg(resultBg) # 可以通过它来看处理后的图片效果
print(distance)
return distance, resultBg
sliceimgpath = './slice.png'
imgpath = './缺口背景图片.png'
getDistance(Image.open(imgpath), Image.open(sliceimgpath))
我们来介绍第二种方法,也是本案例所使用的方法,由于不同电脑的分辨率不一样,导致会有一点点误差,大家要自己在代码中修改合适的数值,我这里改的是-6。
python
def is_pixel_equal(image1, image2, x, y):
"""
判断两个像素是否相同
:param image1: 有缺口图片1
:param image2: 无缺口图片2
:param x: 位置x
:param y: 位置y
:return: 判断同一位置像素是否相同
"""
pixel1 = image1.load()[x, y]
pixel2 = image2.load()[x, y]
threshold = 60
if abs(pixel1[0] - pixel2[0]) < threshold and abs(pixel1[1] - pixel2[1]) < threshold and abs(
pixel1[2] - pixel2[2]) < threshold:
return True
else:
return False
def get_gap(image1, image2):
"""
获取缺口偏移量
:param image1: 不带缺口图片
:param image2: 带缺口图片
:return:返回缺口位置
"""
image1 = Image.open(image1)
image2 = Image.open(image2)
left = 60
print('验证码图片宽度和高度:', image1.size)
for i in range(left, image1.size[0]):
for j in range(image1.size[1]):
judge_value = is_pixel_equal(image1, image2, i, j)
if judge_value is False:
left = i-6
return left
在这里,left = i - 6,我这里测试的是减6,你可能不用调整。
我这里运行之后,计算的结果是55,在后面w的逆向会用到。我们这里传入的是一个完整的图片和一个有缺口的图片做对比,而cv2的思路是把滑块也要拿下来和带缺口的图片做对比,因为每个缺口的朝向都不一样,我个人还是倾向于第二种,如果你喜欢第一种,可以自行修改相关代码。
滑块轨迹的代码
我看了很多大佬写的代码,我这里也贴一份大佬写的滑块轨迹代码,目前可用,是没有问题的。
python
import random
def __ease_out_expo(sep):
'''
轨迹相关操作
'''
if sep == 1:
return 1
else:
return 1 - pow(2, -10 * sep)
def get_slide_track(distance):
"""
根据滑动距离生成滑动轨迹
:param distance: 需要滑动的距离
:return: 滑动轨迹<type 'list'>: [[x,y,t], ...]
x: 已滑动的横向距离
y: 已滑动的纵向距离, 除起点外, 均为0
t: 滑动过程消耗的时间, 单位: 毫秒
"""
if not isinstance(distance, int) or distance < 0:
raise ValueError(f"distance类型必须是大于等于0的整数: distance: {distance}, type: {type(distance)}")
# 初始化轨迹列表
slide_track = [
[random.randint(-50, -10), random.randint(-50, -10), 0],
[0, 0, 0],
]
# 共记录count次滑块位置信息
count = 40 + int(distance / 2)
# 初始化滑动时间
t = random.randint(50, 100)
# 记录上一次滑动的距离
_x = 0
_y = 0
for i in range(count):
# 已滑动的横向距离
x = round(__ease_out_expo(i / count) * distance)
# y = round(__ease_out_expo(i / count) * 14)
# 滑动过程消耗的时间
t += random.randint(10, 50)
if x == _x:
continue
slide_track.append([x, _y, t])
_x = x
slide_track.append(slide_track[-1])
return slide_track
这个轨迹虽然说有点小瑕疵,但是,能过平台的检测就行,你们在运行的时候会发现它的y值都是0,而网页上实际生成的不是这样的,y值是有波动的。这里的代码,我们只要传入距离的参数就可以了。就是我们上面识别计算出来的距离。在这里,我们还可以拿到passtime,这里的值也特别重要,后面也会说的。
总结
我们今天主要说了关于滑块距离的计算,还有滑块距离的计算,我们下一篇,重点来逆向那个w的值,我在这里澄清之前说前两个w的值可以置空,但是,我这里试了一下,是不可以置空的,我看了大部分教学视频都说可以置空,是不对的,至少,我把前两个w的值补全之后,就不会报错。
python
geetest_1701956570696({"success": 0, "message": "forbidden"})
即使我们第三个w的值是对的,也是报forbidden,我一开始还以为我w的值扣错了,还怀疑过滑块轨迹有问题,这个前前后后花了我一周的时间,我希望大家少踩坑,我们在扣w的值的时候,有个随机数,前后也要一致,也是个坑。
下节预告:
接下来,我的思路是重点讲w的生成,因为也有不少博主发了,思路都差不多,可能就是函数名发生改变,加密的内容有一些稍微的变化,我会把三个w逆向都会分析过程都会发出来。由于版权问题,我不会把完整的js代码发出来,你跟着我思路扣,是没有问题的。我这里先给大家看看我成功的图片吧。
我还去测试了某平台手机发送验证码的滑块,这个网站只要最后一个w就可以,等大家学完这个官网的逆向,其他js基本上简单修改就可以使用了。
严正声明:本文仅供交流学习,勿用于非法用途