博客来源于: /wyh0923/p/16528354.html
# -*- coding: utf-8 -*-# /1. import io2. import json3. from pathlib import Path4. from PIL import Image5. import base646. import cv27. import time8. import requests9. sess = requests.session()11. class SlideCrack(object):12.def __init__(self, front, bg, out=None):13. """14. init code15. :param front: 缺口图片16. :param bg: 背景图片17. :param out: 输出图片18. """19. self.front = front20. self.bg = bg21. self.out = out25.@staticmethod26.def clear_white(img):27. # 清除图片的空白区域,这里主要清除滑块的空白28. img = cv2.imread(img)29. rows, cols, channel = img.shape30. min_x = 25531. min_y = 25532. max_x = 033. max_y = 034. for x in range(1, rows):35. for y in range(1, cols):36. t = set(img[x, y])37. if len(t) >= 2:38. if x <= min_x:39.min_x = x40. elif x >= max_x:41.max_x = x42. if y <= min_y:43.min_y = y44. elif y >= max_y:45.max_y = y46. img1 = img[min_x:max_x, min_y: max_y]47. return img149.def template_match(self, tpl, target):50. th, tw = tpl.shape[:2]51. result = cv2.matchTemplate(target, tpl, cv2.TM_CCOEFF_NORMED)52. # 寻找矩阵(一维数组当作向量,用Mat定义) 中最小值和最大值的位置53. min_val, max_val, min_loc, max_loc = cv2.minMaxLoc(result)54. tl = max_loc55. br = (tl[0] + tw, tl[1] + th)56. # 绘制矩形边框,将匹配区域标注出来57. # target:目标图像58. # tl:矩形定点59. # br:矩形的宽高60. # (0,0,255):矩形边框颜色61. # 1:矩形边框大小62. cv2.rectangle(target, tl, br, (0, 0, 255), 2)63. return tl[0]65.@staticmethod66.def image_edge_detection(img):67. edges = cv2.Canny(img, 100, 200)68. return edges70.def discern(self):71. img1 = self.clear_white(self.front)72. img1 = cv2.cvtColor(img1, cv2.COLOR_RGB2GRAY)73. slide = self.image_edge_detection(img1)75. back = cv2.imread(self.bg, 0)76. back = self.image_edge_detection(back)78. slide_pic = cv2.cvtColor(slide, cv2.COLOR_GRAY2RGB)79. back_pic = cv2.cvtColor(back, cv2.COLOR_GRAY2RGB)80. x = self.template_match(slide_pic, back_pic)81. # 输出横坐标, 即 滑块在图片上的位置82. return int(x)85. def bg_captcha_0(img,bgarray:list):86."""87.滑块背景图还原88."""89.if isinstance(img, (str, Path)):90. _img = Image.open(img)91.elif isinstance(img, bytes):92. _img = Image.open(io.BytesIO(img))93.else:94. return95.# 创建一个新图96.new_img = Image.new('RGB', (300, 200))98.# 图片还原顺序99.__imgx = 300100.__imgy = 200101._cutX = int(__imgx / 10)102._cutY = int(__imgy / 2)103.for i in range(len(bgarray)):104. # 从背景图中裁剪出对应位置的小块 Image.crop(左,上,右,下)坐标的4元组105. if i<10:106. crop_tuple = (int(i*_cutX),0,int((i+1)*_cutX),100)107. else:108. crop_tuple = (int((i-10)*_cutX),100,int((i-10+1)*_cutX),200)109. img_cut = _img.crop(crop_tuple)111. # 将小块拼接到新图中,按bgarray数组给的位置来写坐标。112. if bgarray[i]<10:113. new_img.paste(img_cut,(bgarray[i]*30,0))114. else:115. new_img.paste(img_cut, ((bgarray[i]-10)*30,100))117.new_img.save('./image/bg.png')118.return new_img121. def indexOf(arr,str_):122.if arr and arr.index:123. return arr.index(str_)124.lenarr = len(arr)125.for i in range(lenarr):126. if arr[i] == str_:127. return i128.return -1130. # 生成轨迹131. def get_tracks(distance, rate=0.5, t=0.2, v=0):132."""133.将distance分割成小段的距离134.:param distance: 总距离135.:param rate: 加速减速的临界比例136.:param a1: 加速度137.:param a2: 减速度138.:param t: 单位时间139.:param t: 初始速度140.:return: 小段的距离集合141."""142.tracks = []143.# 加速减速的临界值144.mid = rate * distance145.# 当前位移146.s = 0147.# 循环148.while s < distance:149. # 初始速度150. v0 = v151. if s < mid:152. a = 3. else:154. a = -3155. # 计算当前t时间段走的距离156. s0 = v0 * t + 0.5 * a * t * t157. # 计算当前速度158. v = v0 + a * t159. # 四舍五入距离,因为像素没有小数160. tracks.append(round(s0))161. # 计算当前距离162. s += s0164.datelist = ''165.distance = 0166.for i in tracks[1:]:167. distance += i168. datelist_time = round(time.time() * 1000)169. datelist += str(distance) + ',' + str(datelist_time) + '|'170. time.sleep(0.005)171.return datelist[:-1]174. # 注册和校验175. def check_request(data):176.headers = {177. 'Cookie': '_SessionId=qnfya5nvtn2b3pkycs5hs1zv; gr_user_id=f0c2c220-c9b3-4d70-96dd-1ee89e08a87f; gr_session_id_81eec0d0f0be2df1=da98e241-8c1a-4496-a734-61ad1907ef90; gr_session_id_81eec0d0f0be2df1_da98e241-8c1a-4496-a734-61ad1907ef90=true; xCloseNew=27; redSpot=false',178. 'Host': '',179. 'Origin': '',180. 'Pragma': 'no-cache',181. 'Referer': '/',182. 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/101.0.4951.67 Safari/537.36',183. 'X-Requested-With': 'XMLHttpRequest',184.}185.url = '/VerificationCode/GetVerifiCodeResult'186.res = sess.post(url,headers=headers,data=data)187.return res190. def process_main():191.register_data = {192. 'act': 'getcode',193. 'spec': '300*200'194.}195.data = json.loads(json.loads(check_request(register_data).text))196.bgarray = [int(i) for i in data['array'].split(',')]197.# 分割字符串198.normal = data['normal'].split(',')[1]199.small = data['small'].split(',')[1]201.# base64解码202.b64decode = base64.b64decode(normal)203.# 背景还原204.bg_captcha_0(b64decode, bgarray=bgarray)205.# 滑块图片206.hk_image = base64.b64decode(small)207.with open('./image/hk.png', 'wb') as f:208. f.write(hk_image)209.# 获取缺口距离210.sc = SlideCrack('./image/bg.png','./image/hk.png')211.slide_s = sc.discern()212.check_data = {213. 'act': 'check',214. 'point': str(slide_s),215. 'timespan': '452',216. 'datelist': get_tracks(slide_s),217.}218.print(check_request(check_data).text)221. process_main()