- 删除 requirements.txt,pyproject.toml 为唯一依赖源(含 requests[socks] extra) - core/geetest 下 5 处 print() 替换为 loguru logger.debug() - api/modules.ts 新增 13 个响应接口,消除所有 api.xxx<any, any> - 新建 utils/error.ts 提供 getErrorMessage(e: unknown) 安全取消息 - 11 个页面组件 catch (e: any) 改为 catch (e: unknown) - useState<any[]>、columns: any[]、render 参数全部类型化 - TypeScript 类型检查零错误通过
91 lines
3.5 KiB
Python
91 lines
3.5 KiB
Python
import requests
|
|
import cv2
|
|
import numpy as np
|
|
from PIL import Image
|
|
from loguru import logger
|
|
|
|
REQUEST_TIMEOUT = (3.05, 12)
|
|
|
|
|
|
# 将 Image 转换为 Mat,通过 flag 可以控制颜色
|
|
def pilImgToCv2(img: Image.Image, flag=cv2.COLOR_RGB2BGR):
|
|
return cv2.cvtColor(np.asarray(img), flag)
|
|
|
|
# 识别图片缺口返回滑块距离
|
|
def shibie(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) # 可以通过它来看处理后的图片效果
|
|
return distance
|
|
|
|
# 还原图片
|
|
def restore_geetest_image(input_path:str, output_path:str) -> None:
|
|
"""
|
|
还原极验打乱的验证码图像
|
|
"""
|
|
Ut = [
|
|
39, 38, 48, 49, 41, 40, 46, 47, 35, 34, 50, 51, 33, 32, 28, 29,
|
|
27, 26, 36, 37, 31, 30, 44, 45, 43, 42, 12, 13, 23, 22, 14, 15,
|
|
21, 20, 8, 9, 25, 24, 6, 7, 3, 2, 0, 1, 11, 10, 4, 5, 19, 18, 16, 17
|
|
]
|
|
|
|
# 打开混淆图像
|
|
img = Image.open(input_path)
|
|
new_img = Image.new("RGB", (260,160))
|
|
r = 160
|
|
for _ in range(len(Ut)):
|
|
a = r / 2
|
|
c = Ut[_] % 26 * 12 + 1
|
|
u = 80 if Ut[_] > 25 else 0
|
|
l = img.crop(box=(c, u, c + 10, u + 80))
|
|
new_img.paste(l, box=(_ % 26 * 10, 80 if _ > 25 else 0))
|
|
|
|
new_img.save(output_path)
|
|
logger.debug("图像已还原并保存到: {}", output_path)
|
|
|
|
# 下载图片
|
|
def download_picture(bg:str, fullbg:str, slice:str) -> int:
|
|
for i in range(3):
|
|
if i == 0:
|
|
url = "https://static.geetest.com/"+bg
|
|
response = requests.get(url, timeout=REQUEST_TIMEOUT)
|
|
response.raise_for_status()
|
|
with open("bg.jpg", "wb") as f:
|
|
f.write(response.content)
|
|
restore_geetest_image("bg.jpg", "bg.jpg")
|
|
else:
|
|
if i == 1:
|
|
url = "https://static.geetest.com/" + fullbg
|
|
response = requests.get(url, timeout=REQUEST_TIMEOUT)
|
|
response.raise_for_status()
|
|
with open("fullbg.jpg", "wb") as f:
|
|
f.write(response.content)
|
|
restore_geetest_image("fullbg.jpg", "fullbg.jpg")
|
|
else:
|
|
url = "https://static.geetest.com/" + slice
|
|
response = requests.get(url, timeout=REQUEST_TIMEOUT)
|
|
response.raise_for_status()
|
|
with open("slice.jpg", "wb") as f:
|
|
f.write(response.content)
|
|
return shibie(Image.open('fullbg.jpg'), Image.open('slice.jpg'))
|