基于python实现新版正方系统滑动验证码识别
这篇文章主要介绍了基于python实现新版正方系统滑动验证码识别算法和方案,文中示例代码对我们的学习和工作有一定的帮助,感兴趣的可以了解一下
Python实现新版正方系统滑动验证码识别算法和方案
步骤一:点击数据分析
点击滑动按钮,将发送一个请求到 /zfcaptchaLogin
请求内容"type": "verify" "rtk": "6cfab177-afb2-434e-bacf-06840c12e7af" "time": "1624611806948" "mt": "W3sieCI6OTY1LCJ5IjoxNjksInQiOjE2MjQ2MTE4MDY4Njh9LHsieCI6OTY1LCJ5IjoxNjksInQiOjE2MjQ2MTE4MDY5NDh9XQ==" "instanceId": "zfcaptchaLogin" "extend": "eyJhcHBOYW1lIjoiTmV0c2NhcGUiLCJ1c2VyQWdlbnQiOiJNb3ppbGxhLzUuMCAoTWFjaW50b3NoOyBJbnRlbCBNYWMgT1MgWCAxMF8xNV83KSBBcHBsZVdlYktpdC81MzcuMzYgKEtIVE1MLCBsaWtlIEdlY2tvKSBDaHJvbWUvOTEuMC40NDcyLjEwNiBTYWZhcmkvNTM3LjM2IiwiYXBwVmVyc2lvbiI6IjUuMCAoTWFjaW50b3NoOyBJbnRlbCBNYWMgT1MgWCAxMF8xNV83KSBBcHBsZVdlYktpdC81MzcuMzYgKEtIVE1MLCBsaWtlIEdlY2tvKSBDaHJvbWUvOTEuMC40NDcyLjEwNiBTYWZhcmkvNTM3LjM2In0="
通过 base64 解密 mt和 extend 得出解密的数值# mt [{"x":965,"y":169,"t":1624611806868},{"x":965,"y":169,"t":1624611806948}] # extend {"appName":"Netscape","userAgent":"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.106 Safari/537.36","appVersion":"5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.106 Safari/537.36"}
mt 为用户的点击行为,x为X轴上的值,y为Y轴上的值,t为时间戳。通过大量点击分析,发现x值最小值为 950,得出950 为 X轴的起点,y值随机无固定值。
extend 为请求头部内容步骤二:滑动验证码图像分析,计算滑动距离x值
将图像灰度化,通过getpixel可以获取图像某一点的颜色值, 颜色值越高代表图像越浅,所以寻找纵向连续50个像素点均是 getpixel(x+1, y) > getpixel(x, y)(X轴=x 比 X轴=x+1 颜色浅)
并扫描图像,当x=130、扫描高度=50时,的颜色比x+1时深。
from PIL import Image import matplotlib.pyplot as plt import numpy as np scanf_height= 50 # 扫描的高度 img = Image.open("zfcaptchaLogin.png") def contrast(imgl, x, y,scanf_height): # 黄框颜色值比红框颜色值浅的个数 count = 0 for i in range(scanf_height): if imgl.getpixel((x+1, y+i)) > imgl.getpixel((x, y+i)): count += 1 # 当 count = scanf_height, 代表黄条区域 整体 红条区域 颜色值浅,则是验证码框位置 return count def scanf(img): imgx, imgy = img.size imgl = img.convert("L") # 图像灰度化 plt.yticks([]) plt.xticks([i for i in range(0, imgx, 25)]) plt.imshow(img) plt.pause(0.5) for y in range(0, imgy-scanf_height, 10): plt.pause(0.01) plt.clf() plt.yticks([]) plt.xticks([i for i in range(0, imgx, 25)]) plt.imshow(imgl, cmap=plt.cm.gray) for x in range(1, imgx-1, 1): plt.pause(0.0001) plt.plot([x-1,x-1], [y, y+scanf_height], color="white") plt.plot([x,x], [y, y+scanf_height], color="red") plt.plot([x+1,x+1], [y, y+scanf_height], color="yellow") count = contrast(imgl, x,y, scanf_height) plt.title("count: {}".format(count) ) print("x,y=[{}, {}], 黄条区域值比红条区域颜色值浅的个数:{}".format(x,y, count)) if count == scanf_height: return scanf(img) plt.show()
优化代码计算x,y值
import json import random import time from io import BytesIO from PIL import Image class ZfCaptchaRecognit(object): def __init__(self, img_path): self.img = Image.open(img_path) def _get_xy(self): # 计算 x,y 值 def _is_piding_line(img_l, x, y): for n in range(50): # 寻找纵向连续50个像素点均是 X=x 比 X=x+1 颜色深 if y + n >= img_l.size[1] or x >= img_l.size[0] - 1: return False if img_l.getpixel((x + 1, y + n)) - img_l.getpixel((x, y + n)) < 2: return False return True img_l = self.img.convert("L") for x in range(img_l.size[0]): for y in range(img_l.size[1]): if _is_piding_line(img_l, x, y): return (x, y) def show_tag(self): # 展示 切分点 X, Y = self._get_xy() img2 = Image.new("RGB", self.img.size, (255, 255, 255)) for x in range(self.img.size[0]): for y in range(self.img.size[1]): pix = self.img.getpixel((x, y)) img2.putpixel((x, y), pix) if x == X or y == Y: img2.putpixel((x, y), 225) img2.save("show_tag.png") img2.show() captcha = ZfCaptchaRecognit("zfcaptchaLogin.png") captcha.show_tag()步骤三:生成提交参数
通过 步骤一得出x值最小为950,y值无规律
则提交参数mt的大致格式数据是[{ "x":950+ 滑动距离 + 浮动值, # 浮动值的范围通过分析提交参数得出在10~20内 "y":random.randint(150, 190), # 无规律,暂定150到190范围内 "t":int(time.time() * 1000)}, # 时间戳 ...]
获取mt 参数import json import random import time from io import BytesIO from PIL import Image class ZfCaptchaRecognit(object): def __init__(self, img_stream): obj = BytesIO(img_stream) self.img = Image.open(obj) def _get_xy(self): ... def generate_payload(self): base_x = 950 X, Y = self._get_xy() payloads = [{"x": base_x + random.randint(5, 20), "y": random.randint(150, 190), "t": int(time.time() * 1000)}] for i in range(random.randint(15, 30)): # 在上一个参数基础下浮动 last_payload = payloads[-1].copy() payloads[0]["x"] += random.choice([0] * 8 + [1, -1] * 2 + [2, -2]) last_payload["t"] += random.randint(1, 20) last_payload["y"] += random.choice([0] * 8 + [1, -1] * 2 + [2, -2]) payloads.append(last_payload) payloads[-1]["x"] = base_x + random.randint(10, 20) + X return json.dumps(payloads) captcha = ZfCaptchaRecognit("zfcaptchaLogin.png") captcha. generate_payload()
5800mAh新机爆发,6。52英寸天玑700!8256G才1499,值吗?由于天玑处理器开始进军高端市场,今年涌现出了一大批性价比机型,尤其是23千价位段,不仅子品牌之间打得火热,OPPO小米也下场了,今年买手机还是比较好的,因为选择更多。除了这些大厂,
提升孩子的自信,试试做到这四点孩子缺乏自信,遇事犹豫不决,面对困难只想逃避,该怎么办?看了一些关于如何提升孩子自信心的文章和讲座,我总结了一些实操的方法,决定试一下。一每天找出孩子做得好的一件事,狠狠地表扬,针
幸运的人用童年治愈一生,不幸的人用一生治愈童年因为疫情隔离在家,孩子听话时,真的感觉自己孩子为什么这么可爱,不听话时,整天电视开着,玩具玩着,也不想学,又想拼命的吼,吼过后,看到懵懂眼神又后悔这无法控制的脾气。想起网络上一句名
春末长个冲刺期,多给孩子喝4道高钙汤,营养美味又解馋春末长个冲刺期,多给孩子喝4道高钙汤,鲜香美味,快乐成长众所周知孩子要想长身体,钙质的补充是必不可少的,而孩子一天营养的摄入来源大都来自于食物,进入春末后,孩子长个期也进入了倒计时
父母不要嫌烦36岁的孩子首先父母一定要接受幼儿这阶段的多话现象。语言的发达必须经过听与说的阶段才能完成,所以大人应为小孩确立正确的说话典范,同时也要当幼儿忠实的听众。尤其是不要抑制幼儿说话的欲望,父母对他
团队出行两日游,旅行攻略注意事项歌德在不经意间这样说过,决定一个人的一生,以及整个命运的,只是一瞬之间。为什么是在不经意间,因为我也不确定他有没有说过。野三坡竹里三天小院当然团队出行,整体是决定不了命运,但是旅行
揭秘北京环球度假区如何让游客常来常新开园六个月以来,北京环球度假区陆续推出多场季节性体验活动。记者近日从北京环球度假区娱乐副总裁兼首席制作人兰哲森(JasonRamsburg)获悉,在北京环球度假区,除了已有的七大主
荣耀Magic4值不值得买?来看看首批购买用户怎么说手机中国新闻3月25日,荣耀Magic4系列正式开启首销,截至当天1800,斩获了京东天猫单品销量冠军,受欢迎程度可见一斑。对于还没有购买的用户来说,首批购买用户的评价很重要。现在
一起来看海接着上一篇Mullaghmorebeach观光完悬崖步道,我们驾车一个钟头的时间来到了下一个海滩。这个海滩有一个好听的名字Mullaghmorebeach。它是一片宁静的海。那青色
深山建民宿,想法好,效果差现在旅游城市的民宿已经有很多,各种档次的民宿都有,有几十元一晚一间的,也有几千元一晚一间的,对比起星级酒店来,民宿在硬件与软件上巨大的对比差之下,还是受众有限。不过在城市之外的民宿
现代又奢华!这间超美玻璃房让你来了就不想走小布带你探民宿天空清澈白云朵朵微风阵阵你知道吗?在毗邻迪士尼乐园和野生动物园的宣桥镇藏着这样一间极具设计感的轻奢玻璃小屋丽芸民宿度假团建过生日办婚礼这里都可以满足你的要求快跟着小布一起走进这间民