1500字范文,内容丰富有趣,写作好帮手!
1500字范文 > 使用opencv破解滑块验证码:以今日头条PC端登录页面滑块验证码为例

使用opencv破解滑块验证码:以今日头条PC端登录页面滑块验证码为例

时间:2018-10-18 02:15:42

相关推荐

使用opencv破解滑块验证码:以今日头条PC端登录页面滑块验证码为例

本文目标人群:python爬虫工程师

一、首先看看破解的效果图

二、滑块验证码的破解

滑块验证码的破解的难点主要有两个:计算出滑块到缺口的距离和模拟人拖动滑块的轨迹。

如何计算出滑块到缺口的距离?从网上的资料来看,主要有两种方式:自己使用Pillow库实现算法,使用OpenCV库提供的现成方法。本文就使用后者,简单而又强大、成功率高。

本文主要参考https://juejin.im/post/5cf4cbd4f265da1b8e7089b4,但是由于它的注释太少,也未给出完整代码。所以,决定写这篇博客。

三、什么是OpenCV?什么是opencv-python?

OpenCV(Open Source Computer Vision Library)是一个开源的计算机视觉库,提供了很多处理图片、视频的方法。虽然是C/C++开发的,但是提供了 Python、Java、MATLAB 等其他语言的接口。

OpenCV-python库就是使用pthon操作OpenCV的一个库。

四、为什么要用OpenCV-python库?

说白了,就是OpenCV库提供了一个方法(matchTemplate()):从一张较大的图片中搜索一张较小图片,计算出这张大图上各个区域和小图相似度。调用这个方法后返回一个二维数组(numpy库中ndarray对象),从中就能拿到最佳匹配区域的坐标。换到滑块验证码上面,滑块背景图片是大图,滑块是小图。

opencv-python参见官网:/4.0.0/index.html

cv.matchTemplate()方法参见:

https://opencv-python-tutroals.readthedocs.io/en/latest/py_tutorials/py_imgproc/py_template_matchin/py_template_matching.html

今日头条PC端登录页面: /

五、环境

首先,selenium、谷歌浏览器、谷歌浏览器驱动等环境是必须的。

安装OpenCV-python库

pip installopencv-python

或者使用阿里源:

pip install -i /pypi/simple/ --trusted-host opencv-python

六、代码

源码也可以在我的github找到/chushiyan/slide_captcha_cracking

# create by chushiyan# date: 0926# email: Y2h1c2hpeWFuMDQxNUAxNjMuY29t(base64)import cv2 as cvfrom selenium import webdriverfrom mon.exceptions import StaleElementReferenceExceptionfrom selenium.webdriver import ActionChainsfrom selenium.webdriver.chrome.options import Optionsfrom mon.by import Byfrom mon.keys import Keysfrom selenium.webdriver.support.ui import WebDriverWaitfrom selenium.webdriver.support import expected_conditionsimport timeimport urllib.requestimport random# 传入滑块背景图片本地路径和滑块本地路径,返回滑块到缺口的距离def findPic(img_bg_path, img_slider_path):"""找出图像中最佳匹配位置:param img_bg_path: 滑块背景图本地路径:param img_slider_path: 滑块图片本地路径:return: 返回最差匹配、最佳匹配对应的x坐标"""# 读取滑块背景图片,参数是图片路径,OpenCV默认使用BGR模式# cv.imread()是 image read的简写# img_bg 是一个numpy库ndarray数组对象img_bg = cv.imread(img_bg_path)# 对滑块背景图片进行处理,由BGR模式转为gray模式(即灰度模式,也就是黑白图片)# 为什么要处理? BGR模式(彩色图片)的数据比黑白图片的数据大,处理后可以加快算法的计算# BGR模式:常见的是RGB模式# R代表红,red; G代表绿,green; B代表蓝,blue。# RGB模式就是,色彩数据模式,R在高位,G在中间,B在低位。BGR正好相反。# 如红色:RGB模式是(255,0,0),BGR模式是(0,0,255)img_bg_gray = cv.cvtColor(img_bg, cv.COLOR_BGR2GRAY)# 读取滑块,参数1是图片路径,参数2是使用灰度模式img_slider_gray = cv.imread(img_slider_path, 0)# 在滑块背景图中匹配滑块。参数cv.TM_CCOEFF_NORMED是opencv中的一种算法res = cv.matchTemplate(img_bg_gray, img_slider_gray, cv.TM_CCOEFF_NORMED)print('#' * 50)print(type(res)) # 打印:<class 'numpy.ndarray'>print(res)# 打印:一个二维的ndarray数组# [[0.05604218 0.05557462 0.06844381... - 0.1784117 - 0.1811338 - 0.18415523]# [0.06151756 0.04408009 0.07010461... - 0.18493137 - 0.18440475 - 0.1843424]# [0.0643926 0.06221284 0.0719175... - 0.18742703 - 0.18535161 - 0.1823346]# ...# [-0.07755355 - 0.08177952 - 0.08642308... - 0.16476074 - 0.16210903 - 0.15467581]# [-0.06975575 - 0.07566144 - 0.07783117... - 0.1412715 - 0.15145643 - 0.14800543]# [-0.08476129 - 0.08415948 - 0.0949327... - 0.1371379 - 0.14271489 - 0.14166716]]print('#' * 50)# cv2.minMaxLoc() 从ndarray数组中找到最小值、最大值及他们的坐标value = cv.minMaxLoc(res)# 得到的value,如:(-0.1653602570295334, 0.6102921366691589, (144, 1), (141, 56))print(value, "#" * 30)# 获取x坐标,如上面的144、141return value[2:][0][0], value[2:][1][0]# 返回两个数组:一个用于加速拖动滑块,一个用于减速拖动滑块def generate_tracks(distance):# 给距离加上20,这20像素用在滑块滑过缺口后,减速折返回到缺口distance += 20v = 0t = 0.2forward_tracks = []current = 0mid = distance * 3 / 5 # 减速阀值while current < distance:if current < mid:a = 2 # 加速度为+2else:a = -3 # 加速度-3s = v * t + 0.5 * a * (t ** 2)v = v + a * tcurrent += sforward_tracks.append(round(s))back_tracks = [-3, -3, -2, -2, -2, -2, -2, -1, -1, -1, -1]return forward_tracks, back_tracksdef main():# 创建一个参数对象,用来控制谷歌浏览器以无界面模式打开chrome_options = Options()# chrome_options.add_argument('--headless')# chrome_options.add_argument('--disable-gpu')driver = webdriver.Chrome(chrome_options=chrome_options)# 设置浏览器宽高driver.set_window_size(width=2000, height=3000)wait = WebDriverWait(driver, 10)driver.get("/")try:# 获取手机号码输入框text_box = wait.until(expected_conditions.presence_of_element_located((By.ID, "user-mobile")))print(text_box)# 获取发送验证按钮send_btn = wait.until(expected_conditions.presence_of_element_located((By.ID, "mobile-code-get")))print(send_btn)except Exception as e:print(e)raise RuntimeError("获取 手机号码输入框 或者 发送验证按钮 失败,程序结束")text_box.send_keys("18812345678")# time.sleep(random.uniform(2, 3))try:action = ActionChains(driver)action.click(send_btn).perform()except Exception as e:print(e)else:time.sleep(1.5)# 获取 滑块背景图bg_image = wait.until(expected_conditions.presence_of_element_located((By.XPATH, '//div[@class="validate-main"]/img[1]')))print("\n背景:")print(bg_image)bg_image_url = bg_image.get_attribute('src')print(bg_image_url)# 使用urllib下载背景图# 原因是:使用bg_image.screenshot()程序卡在这里,也不报错urllib.request.urlretrieve(bg_image_url, "./img_bg.png")# 获取 滑块slider = wait.until(expected_conditions.presence_of_element_located((By.XPATH, '//div[@class="validate-main"]/img[2]')))print("\n滑块:")print(slider)# 注意:千万不能通过截图获取滑块,因为滑块不是规则的图形# 而截图截出的是矩形,会把滑块周围的滑块背景图一起截取,势必影响匹配# slider.screenshot('./img_slider.png')slider_url = slider.get_attribute('src')urllib.request.urlretrieve(slider_url, "./img_slider.png")value_1, value_2 = findPic('./img_bg.png', './img_slider.png')print("#" * 30)print("最差匹配和最佳匹配对应的x坐标分别是:")print(value_1)print(value_2)print("#" * 30)# 获取滑动按钮button = wait.until(expected_conditions.presence_of_element_located((By.XPATH, '//div[@class="validate-drag-button"]/img')))action = ActionChains(driver)try:action.click_and_hold(button).perform()except StaleElementReferenceException as e:print(e)action.reset_actions()forward_tracks, back_tracks = generate_tracks(value_2)for x in forward_tracks:action.move_by_offset(x, 0) # 前进移动滑块print(x)print('#' * 50)for x in back_tracks:action.move_by_offset(x, 0) # 后退移动滑块print(x)action.release().perform()finally:# time.sleep(10000)driver.close()if __name__ == '__main__':main()

本文仅作为技术交流,如有侵权请联系我。

邮箱:Y2h1c2hpeWFuMDQxNUAxNjMuY29t(base64编码)

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。