完整代码我放文末
这里的有缺口图片我指的是这种类型的哈(验证码网站:https://pintia.cn/auth/login)
第一步:先创建一个driver对象访问该网站,并配置一些信息防止网站识别出是驱动的
def __init__(self):
"""构造方法设置配置一些启动项"""
super(CrackSlider, self).__init__()
self.opts = webdriver.ChromeOptions()
self.opts.add_experimental_option('excludeSwitches', ['enable-logging'])
self.opts.add_experimental_option('useAutomationExtension', False) # 禁用Chrome的自动化拓展程序
self.opts.add_experimental_option('excludeSwitches', ['enable-automation']) # 确保浏览器不会因为启用自动化模式而出现不必要的错误或异常。
self.opts.add_argument("--disable-blink-features=AutomationControlled") # 禁用由自动化测试或脚本控制的 Blink 功能。
chrome_path = r"chromedriver.exe" # google驱动路径
self.driver = webdriver.Chrome(chrome_path, options=self.opts)
self.url = 'https://pintia.cn/auth/login' # 滑块验证码的地址
self.wait = WebDriverWait(self.driver, 10)
第二步:就点点到有验证码的页面呗,然后保存两张图片
def get_pic(self):
self.driver.get(self.url) # 访问地址
time.sleep(3)
self.driver.find_element(by=By.XPATH, value='//*[@id="username"]').send_keys("2313859086@qq.com")
self.driver.find_element(by=By.XPATH, value='//*[@id="password"]').send_keys("bo18212410475")
self.driver.find_element(by=By.XPATH,
value='//*[@id="sparkling-daydream"]/div[2]/div/div[2]/div[2]/button/div/div').click()
time.sleep(3) # 可以设置久一些,方便页面充分加载出来
target_link = self.driver.find_element(By.CLASS_NAME, "yidun_bg-img").get_attribute('src') # 缺口图片地址
template_link = self.driver.find_element(By.CLASS_NAME, "yidun_jigsaw").get_attribute('src') # 待滑块图片地址
target_img = Image.open(BytesIO(requests.get(target_link).content)) # 访问图片链接
template_img = Image.open(BytesIO(requests.get(template_link).content))
target_img.save('PTA_A.jpg') # 保存图片
template_img.save('PTA_B.png')
也就是图片一(含缺口图片)
还有图片二(滑块的图片)
第三步:就到了我们利用深度学习的opencv库读取我们两个图片然后识别出他们之间的距离
def match(img_jpg_path, img_png_path):
# 读取图像
img_jpg = cv2.imread(img_jpg_path, cv2.IMREAD_UNCHANGED)
img_png = cv2.imread(img_png_path, cv2.IMREAD_UNCHANGED)
# 判断jpg图像是否已经为4通道(提高去噪效果,支持透明度)
if img_jpg.shape[2] == 3:
"""如果是三通道就用add_alpha_channel转为4通道"""
img_jpg = add_alpha_channel(img_jpg)
img = handel_img(img_jpg)
small_img = handel_img(img_png)
res_TM_CCOEFF_NORMED = cv2.matchTemplate(img, small_img, 3) # 计算输入图像 img 与模板图像 small_img 的相似度
value = cv2.minMaxLoc(res_TM_CCOEFF_NORMED) # 计算输入图像与模板图像的相似度,并找到相似度最高的区域
value = value[3][0] # 获取到移动距离
下面这两个函数不是我们的主线,这段代码只是为了让识别率变得高(深度学习的知识,我也在代码中解释了)
def add_alpha_channel(img):
""" 为jpg图像添加alpha通道 """
r_channel, g_channel, b_channel = cv2.split(img) # 剥离jpg图像通道
alpha_channel = np.ones(b_channel.shape, dtype=b_channel.dtype) * 255 # 创建Alpha通道
img_new = cv2.merge((r_channel, g_channel, b_channel, alpha_channel)) # 融合通道
return img_new
def handel_img(img):
"""主要是为了提高图像处理的效率和效果"""
imgGray = cv2.cvtColor(img, cv2.COLOR_RGBA2GRAY) # 转灰度图
imgBlur = cv2.GaussianBlur(imgGray, (5, 5), 1) # 高斯模糊
imgCanny = cv2.Canny(imgBlur, 60, 60) # Canny算子边缘检测
return imgCanny
第四步:不要学网上那种什么魔幻滑动公式s = v * t + 0.5 * a * (t ** 2),直接在滑动的时候添加抖动就可以了(也就是yoffset设置小数点)
def crack_slider(self, distance):
"""得到了需要向右滑动的距离distance值"""
slider = self.wait.until(EC.element_to_be_clickable((By.CLASS_NAME, 'yidun_slider__icon'))) # 等待滑块出来
ActionChains(self.driver).click_and_hold(slider).perform() # 按住滑块
# 魔幻运动
ActionChains(self.driver).move_by_offset(xoffset=distance - 5, yoffset=0.81).perform()
ActionChains(self.driver).move_by_offset(xoffset=3, yoffset=0.77).perform()
ActionChains(self.driver).move_by_offset(xoffset=2, yoffset=-1.3).perform()
ActionChains(self.driver).pause(1).perform()
# 松开鼠标
ActionChains(self.driver).release().perform() # 松开鼠标
time.sleep(0.5)
try:
wait = WebDriverWait(self.driver, 5) # 设置最长等待时间为20秒
# 大概意思就是设置20秒的等待时间,然后如果滑动准确,就会找到其他地方,然后跳转
slider = wait.until(EC.presence_of_element_located((By.XPATH,
'//*[@id="sparkling-daydream"]/div[1]/div/div[1]/a[2]/div/divxxx')))
slider.click()
print('yes')
except TimeoutException:
cs = CrackSlider()
cs.get_pic()
# 2. 对比图片,计算距离
img_jpg_path = 'a.jpg' # 读者可自行修改文件路径(我保存的是在本地)
img_png_path = 'b.png'
distance = match(img_jpg_path, img_png_path) # 可以得到需要滑动的值
distance = distance + 9 # 距离的进一步特殊处理
# 3. 移动
cs.crack_slider(distance)
finally:
self.driver.quit()
另外添加了一个滑动不过就继续重新滑处理,不过我一般在滑动所有这种类似网站的验证码都是一遍过
第五步:差点忘记提醒一个地方了,最后识别出距离了,然后查看照片的分辨率和页面上的分辨率是否一致,
如果不一致就转换一下,如果某些网站精度要较高,则可以加减一些数字,微调
distance = distance / 图片实际的x * 页面上的x
如果图片实际为30*15
页面上为48*36
则distance = distance/30*48
完整代码如下
import requests
import time
from io import BytesIO
import cv2
import numpy as np
from PIL import Image
from selenium import webdriver # selenium版本3.141.0配合urllib3版本1.26.0(其他包默认最新)
from selenium.common.exceptions import TimeoutException
from selenium.webdriver import ActionChains
from selenium.webdriver.common.by import By
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.support.wait import WebDriverWait
class CrackSlider():
# 通过浏览器截图,识别验证码中缺口位置,获取需要滑动距离,并破解滑动验证码
def __init__(self):
"""构造方法设置配置一些启动项"""
super(CrackSlider, self).__init__()
self.opts = webdriver.ChromeOptions()
self.opts.add_experimental_option('excludeSwitches', ['enable-logging'])
self.opts.add_experimental_option('useAutomationExtension', False) # 禁用Chrome的自动化拓展程序
self.opts.add_experimental_option('excludeSwitches', ['enable-automation']) # 确保浏览器不会因为启用自动化模式而出现不必要的错误或异常。
self.opts.add_argument("--disable-blink-features=AutomationControlled") # 禁用由自动化测试或脚本控制的 Blink 功能。
chrome_path = r"./Selenium/chromedriver.exe" # google驱动路径
self.driver = webdriver.Chrome(chrome_path, options=self.opts)
self.url = 'https://pintia.cn/auth/login' # 滑块验证码的地址
self.wait = WebDriverWait(self.driver, 10)
def get_pic(self):
self.driver.get(self.url) # 访问地址
time.sleep(3)
self.driver.find_element(by=By.XPATH, value='//*[@id="username"]').send_keys("2313859086@qq.com")
self.driver.find_element(by=By.XPATH, value='//*[@id="password"]').send_keys("bo18212410475")
self.driver.find_element(by=By.XPATH,
value='//*[@id="sparkling-daydream"]/div[2]/div/div[2]/div[2]/button/div/div').click()
time.sleep(3) # 可以设置久一些,方便页面充分加载出来
target_link = self.driver.find_element(By.CLASS_NAME, "yidun_bg-img").get_attribute('src') # 缺口图片地址
template_link = self.driver.find_element(By.CLASS_NAME, "yidun_jigsaw").get_attribute('src') # 待滑块图片地址
target_img = Image.open(BytesIO(requests.get(target_link).content)) # 访问图片链接
template_img = Image.open(BytesIO(requests.get(template_link).content))
target_img.save('PTA_A.jpg') # 保存图片
template_img.save('PTA_B.png')
def crack_slider(self, distance):
"""得到了需要向右滑动的距离distance值"""
slider = self.wait.until(EC.element_to_be_clickable((By.CLASS_NAME, 'yidun_slider__icon'))) # 等待滑块出来
ActionChains(self.driver).click_and_hold(slider).perform() # 按住滑块
# 魔幻运动
ActionChains(self.driver).move_by_offset(xoffset=distance - 5, yoffset=0.81).perform()
ActionChains(self.driver).move_by_offset(xoffset=3, yoffset=0.77).perform()
ActionChains(self.driver).move_by_offset(xoffset=2, yoffset=-1.3).perform()
ActionChains(self.driver).pause(1).perform()
# 松开鼠标
ActionChains(self.driver).release().perform() # 松开鼠标
time.sleep(0.5)
try:
wait = WebDriverWait(self.driver, 5) # 设置最长等待时间为20秒
# 大概意思就是设置20秒的等待时间,然后如果滑动准确,就会找到其他地方,然后跳转
slider = wait.until(EC.presence_of_element_located((By.XPATH,
'//*[@id="sparkling-daydream"]/div[1]/div/div[1]/a[2]/div/divxxx')))
slider.click()
print('yes')
except TimeoutException:
cs = CrackSlider()
cs.get_pic()
# 2. 对比图片,计算距离
img_jpg_path = 'PTA_A.jpg' # 读者可自行修改文件路径(我保存的是在本地)
img_png_path = 'PTA_B.png'
distance = match(img_jpg_path, img_png_path) # 可以得到需要滑动的值
distance = distance + 9 # 距离的进一步特殊处理
# 3. 移动
cs.crack_slider(distance)
finally:
self.driver.quit()
def add_alpha_channel(img):
""" 为jpg图像添加alpha通道 """
r_channel, g_channel, b_channel = cv2.split(img) # 剥离jpg图像通道
alpha_channel = np.ones(b_channel.shape, dtype=b_channel.dtype) * 255 # 创建Alpha通道
img_new = cv2.merge((r_channel, g_channel, b_channel, alpha_channel)) # 融合通道
return img_new
def handel_img(img):
"""主要是为了提高图像处理的效率和效果"""
imgGray = cv2.cvtColor(img, cv2.COLOR_RGBA2GRAY) # 转灰度图
imgBlur = cv2.GaussianBlur(imgGray, (5, 5), 1) # 高斯模糊
imgCanny = cv2.Canny(imgBlur, 60, 60) # Canny算子边缘检测
return imgCanny
def match(img_jpg_path, img_png_path):
# 读取图像
img_jpg = cv2.imread(img_jpg_path, cv2.IMREAD_UNCHANGED)
img_png = cv2.imread(img_png_path, cv2.IMREAD_UNCHANGED)
# 判断jpg图像是否已经为4通道(提高去噪效果,支持透明度)
if img_jpg.shape[2] == 3:
"""如果是三通道就用add_alpha_channel转为4通道"""
img_jpg = add_alpha_channel(img_jpg)
img = handel_img(img_jpg)
small_img = handel_img(img_png)
res_TM_CCOEFF_NORMED = cv2.matchTemplate(img, small_img, 3) # 计算输入图像 img 与模板图像 small_img 的相似度
value = cv2.minMaxLoc(res_TM_CCOEFF_NORMED) # 计算输入图像与模板图像的相似度,并找到相似度最高的区域
value = value[3][0] # 获取到移动距离
return value
if __name__ == '__main__':
cs = CrackSlider()
cs.get_pic()
# 2. 对比图片,计算距离
img_jpg_path = 'PTA_A.jpg' # 读者可自行修改文件路径(我保存的是在本地)
img_png_path = 'PTA_B.png'
distance = match(img_jpg_path, img_png_path) # 可以得到需要滑动的值
distance = distance + 9 # 距离的进一步特殊处理
# 3. 移动
cs.crack_slider(distance)