python实现过顶象滑块
前言
看了网上很多博主都有过顶象滑块的方案,要么是代码不全,要么就是写的不够详细,自己研究了下把整个实现过程记录下来。
实现步骤
- 下载bg图与icon图;
- 还原bg图;
- 使用icon图匹配bg图缺口位置,获得坐标;
- 模拟请求参数,获取返回信息;
下载bg图与icon图
url前缀网址是一样的,只需要获取返回的图片后缀
bg_url = f'https://static.dingxiang-inc.com/picture{p1}'
icon_url = f'https://static.dingxiang-inc.com/picture{p2}'
问题来了,怎样获取前缀,使用api 携带ak 与c参数获取
api:https://cap.dingxiang-inc.com/api/v1
请求param
参考代码
import requests
def get_img():
# 返回的aid_dx ,sid后面需要用到
# p1、p2 是bg 与 icon图
headers = {
'Accept': '*/*',
'Accept-Language': 'zh-CN,zh;q=0.9',
'Cache-Control': 'no-cache',
'Connection': 'keep-alive',
'Origin': 'https://m.airchina.com.cn',
'Pragma': 'no-cache',
'Referer': 'https://m.airchina.com.cn/',
'Sec-Fetch-Dest': 'empty',
'Sec-Fetch-Mode': 'cors',
'Sec-Fetch-Site': 'cross-site',
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/102.0.0.0 Safari/537.36',
'sec-ch-ua': '" Not A;Brand";v="99", "Chromium";v="102", "Google Chrome";v="102"',
'sec-ch-ua-mobile': '?0',
'sec-ch-ua-platform': '"Windows"',
}
random.random() * 100000000
aid_dx = f'dx-{str(int(time.time() * 1000))}-{str(int(random.random() * 100000000))}-1'
params = (
('w', '300'),
('h', '150'),
('s', '50'),
('ak', '5f6727ec854786a86cd4c3c171d13499'),
('c', '63490534hEK47XdXUPbCVcFE1MpdpRs4blnVT8w1'),
('jsv', '1.5.28.117'),
('aid', aid_dx),
('wp', '1'),
('de', '0'),
('uid', ''),
('lf', '0'),
('tpc', ''),
('cid', '78726764'),
('_r', '0.24678465468631372'),
)
response = requests.get('https://cap.dingxiang-inc.com/api/a', headers=headers, params=params)
res = response.json()
return [aid_dx, res['sid'], res['p1'], res['p2']]
返回的数据,其实只有sid,p1, p2有用
还原bg图
下载的bg图,实际上是乱序的,是由一定的规则排序,可以理解成打乱成12条图片
- 下载的原图
- 还原后的图
还原算法是用js实现,有兴趣的可以去看下算法,原理是用图片编号,生成对应的一个数组,对应的算法用python改写
1.用图片编号,生成数组
-
path_code,就是p1后面那一串字符
-
贴python实现代码,python还原算法自己写的,可以自己敲一遍,想下怎样实现的
-
贴上js原生实现方法,下面就是生成的数组
2.使用数组还原完整图片
- 还原图片的代码
import time import re from urllib.parse import urlencode import random import requests import cv2 import numpy as np from PIL import Image import matplotlib.pyplot as plt import execjs import json # 读取bg图 img = Image.open('./img/bg.jpg') # _seq 是 上面返回的数组 def gen(_seq, _img): a = 200 np_image = np.array(_img) new_np_img = np.zeros((200, 400, 3), dtype=np.uint8) for u in range(0, 32): c = _seq[u] % 32 * 12 xpos = u % 32 * 12 slice_img = np_image[0:(0 + a), c:(c + 12)] n = len(slice_img[0]) new_np_img[0:(0 + a), xpos:(xpos + n)] = slice_img return new_np_img new_img = gen(seq, img) # 保存还原图片 cv2.imwrite('./img/new_bg.png', new_img)
- 代码中 200,400,是新图片的尺寸,12是原图片被切成12块,需要还原
使用icon图匹配bg图缺口位置,获得坐标
1.生成坐标
- 贴识别代码
# 顶象滑块识别 def dXImgSlider(origin, sliderImg): slider = cv2.imread(sliderImg) originImg = cv2.imread(origin) bgImg = cv2.cvtColor(originImg, cv2.COLOR_BGR2GRAY) sliderImg = cv2.cvtColor(slider, cv2.COLOR_BGR2GRAY) # 反相 frame_gray_c = sliderImg.copy() height, width = frame_gray_c.shape for i in range(height): for j in range(width): pv = frame_gray_c[i, j] frame_gray_c[i][j] = 255 - pv # 高斯滤波 imgGaussianBlur1 = cv2.GaussianBlur(frame_gray_c, (3, 3), 0) imgGaussianBlur2 = cv2.GaussianBlur(bgImg, (7, 7), 0) # 获取模板图像的高和宽 th, tw = sliderImg.shape[:2] # 使用标准相关系数匹配,1表示完美匹配,-1表示糟糕的匹配,0表示没有任何相关性 result = cv2.matchTemplate(imgGaussianBlur2, imgGaussianBlur1, cv2.TM_CCOEFF_NORMED) min_val, max_val, min_loc, max_loc = cv2.minMaxLoc(result) tl = max_loc br = (tl[0] + tw, tl[1] + th) # 绘制识别框 im = cv2.rectangle(originImg, tl, br, (0, 0, 255), 2) t = time.time() - 60 * 60 * 24 * 30 time_string = time.strftime("%Y%m%d%H%M%S", time.localtime(t)) # save_path = "./img/result" + time_string + ".jpg" save_path = "./img/result1.jpg" cv2.imwrite(save_path, im) resObj = [tl[0], tl[1], br[0], br[1]] # 需要与实际提交的尺寸匹配,上面生成的 新bg图尺寸与实际尺寸不一样,需要把坐标转换 # 新坐标 resObj = [int(x * 300/400) for x in resObj] print(resObj) return save_path, resObj
- 识别效果
模拟请求参数,获取返回信息
上面获取到了坐标,但距离成功还差了一步,需要生成 最重要的ac参数
- 请求参数如下
- 请求代码
def send_verify(sid, aid_dx, x,y,ac):
headers = {
'Accept': '*/*',
'Accept-Language': 'zh-CN,zh;q=0.9',
'Cache-Control': 'no-cache',
'Connection': 'keep-alive',
'Content-type': 'application/x-www-form-urlencoded',
'Origin': 'https://m.airchina.com.cn',
'Pragma': 'no-cache',
'Referer': 'https://m.airchina.com.cn/',
'Sec-Fetch-Dest': 'empty',
'Sec-Fetch-Mode': 'cors',
'Sec-Fetch-Site': 'cross-site',
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/102.0.0.0 Safari/537.36',
'sec-ch-ua': '" Not A;Brand";v="99", "Chromium";v="102", "Google Chrome";v="102"',
'sec-ch-ua-mobile': '?0',
'sec-ch-ua-platform': '"Windows"',
}
data = urlencode({
'ac': ac,
'ak': "5f6727ec854786a86cd4c3c171d13499",
'c': "63490534hEK47XdXUPbCVcFE1MpdpRs4blnVT8w1",
'uid': '',
'jsv': '1.5.28.117',
'sid': sid,
'aid': aid_dx,
'x': str(x),
'y': str(y)
})
response = requests.post('https://cap.dingxiang-inc.com/api/v1', headers=headers, data=data)
return response
2.ac 生成
- ac是由 这个这个js 生成
https://cdn.dingxiang-inc.com/ctu-group/ctu-greenseer/greenseer.js - 通过补环境,传入x、y、sid三个参数,获取ac,相信这个应该是人均都会的水平