小红书旋转验证码自动校验系统:实现与分析
仅为自己粗浅的理解,各位大佬求指正勿喷
简介
在现代的网页应用中,验证码作为一种有效的反爬虫手段被广泛应用。滑动以及旋转验证码是一种较为流行的验证码类型,本项目旨在通过构建一个自动化系统,利用卷积神经网络(CNN)来识别验证码图片的旋转角度,并使用 playwright
库模拟人类滑动行为,最终实现滑动验证码的自动校验。
项目主要模块
项目结构简洁明了,主要包含以下几个部分:
-
依赖文件
rotate_model.pth
:训练好的旋转角度识别模型stealth.min.js
:防止被反爬虫检测的脚本
-
函数
get_angle
调用CNN模型预测角度get_tracks
根据角度映射出的距离模拟人获取滑动轨迹correct_angle
使用浏览器自动化工具测试验证码验证
项目主要思路与实现
1. 定义 CNN 模型
首先,项目定义了一个简单的卷积神经网络(CNN),用于识别验证码图片的旋转角度。模型包含三个卷积层和两个全连接层:
通过逐层卷积和池化,逐步提取图像的低级到高级特征,最后通过全连接层输出结果
class CNN(nn.Module):
def __init__(self):
super(CNN, self).__init__()
self.conv1 = nn.Conv2d(3, 16, kernel_size=3, padding=1)
self.conv2 = nn.Conv2d(16, 32, kernel_size=3, padding=1)
self.conv3 = nn.Conv2d(32, 64, kernel_size=3, padding=1)
self.pool = nn.MaxPool2d(2, 2)
self.fc1 = nn.Linear(64 * 5 * 5, 128)
self.fc2 = nn.Linear(128, 360) # 360 classes for 0-359 degrees rotation
def forward(self, x: torch.Tensor) -> torch.Tensor:
x = self.pool(torch.relu(self.conv1(x)))
x = self.pool(torch.relu(self.conv2(x)))
x = self.pool(torch.relu(self.conv3(x)))
x = x.view(-1, 64 * 5 * 5)
x = torch.relu(self.fc1(x))
x = self.fc2(x)
return x
2. 获取图片旋转角度
接下来,通过 get_angle
函数加载并应用模型来预测图片的旋转角度:
def get_angle(image: Image) -> int:
transform = transforms.Compose([
transforms.Resize((40, 40)),
transforms.ToTensor(),
])
image = image.convert('RGB')
image = transform(image).unsqueeze(0)
model = CNN()
model.load_state_dict(torch.load('libs/rotate_model.pth'))
model.eval() # 设置为评估模式
with torch.no_grad():
output = model(image)
_, predicted = torch.max(output, 1)
return predicted.item()
3. 获取移动轨迹
为了 模拟人类滑动行为
以使得滑动行为更加自然,避免被识别为机器操作,get_tracks
函数根据给定的距离通,过随机加速度和分阶段的滑动距离计算,其中包含加速和减速阶段,生成的移动轨迹会更接近人类滑动的特性:
def get_tracks(distance: int) -> list[int]:
tracks = []
current = 0
mid = distance * 4 / 5
t = 0.2
v = 0
while current < distance:
if current < mid:
a = random.randint(3, 5)
else:
a = random.randint(-5, -3)
v0 = v
v = v0 + a * t
move = v0 * t + 1 / 2 * a * t * t
current += move
tracks.append(round(current))
return tracks
4. 验证码校验
核心功能 correct_angle
是一个异步函数,利用 playwright
库来进行网页交互,模拟滑动行为以完成验证码校验:
注: 最终实际测试的函数由于自己的项目需要采用了协程异步实现,可以自行改为同步进行实验
@retry(stop=stop_after_attempt(10), wait=wait_fixed(2), retry=retry_if_result(lambda value: value is False))
async def correct_angle(context_page: Page) -> bool:
if await context_page.query_selector('//div[@class="red-captcha-slider"]') is None:
return True
await context_page.wait_for_selector('//div[@id="red-captcha-rotate"]/img')
img_url = await context_page.get_attribute('//div[@id="red-captcha-rotate"]/img', 'src')
response = httpx.get(img_url)
img = Image.open(BytesIO(response.content))
correction_angle = get_angle(img)
await context_page.wait_for_selector('//div[@class="red-captcha-slider"]')
slider = await context_page.query_selector('//div[@class="red-captcha-slider"]')
slider_box = await slider.bounding_box()
move_x = correction_angle * 0.79
await context_page.mouse.move((slider_box['x'] + slider_box['width'] / 2), (slider_box['y'] + slider_box['height'] / 2))
await context_page.mouse.down()
tracks = get_tracks(move_x)
for track in tracks:
target_X = track + slider_box['x'] + slider_box['width'] / 2
target_Y = slider_box['y'] + slider_box['height'] / 2
await context_page.mouse.move(target_X, target_Y)
await context_page.mouse.up()
time.sleep(3)
if await context_page.query_selector('//div[@class="red-captcha-slider"]') is None:
utils.logger.info("[XiaoHongShuClient.correct_angle] verify success.")
return True
else:
utils.logger.info("[XiaoHongShuClient.correct_angle] verify failed.")
return False
总结
本项目通过深度学习模型和浏览器自动化技术,结合了 CNN 图像识别和 playwright
库的网页自动化技术。实现了滑动验证码的自动校验。项目只做一种验证思路仅供学习使用,严禁其他操作。