滑动验证码的解决方案

一 :可以获取到带有缺口的背景图片和缺口图片

1图片的获取保存滑动验证码的解决方案_第1张图片

以查询shunfeng快递为例子,使用selenium来进行滑块的验证

# 显示等待
wait = WebDriverWait(driver, 30)
# 等待验证码模块加载完成
wait.until(EC.presence_of_element_located((By.ID, 'tcaptcha_iframe')))
# 切换iframe
driver.switch_to.frame('tcaptcha_iframe')
# 等待图片加载完成
wait.until(EC.presence_of_element_located((By.ID, 'slideBg')))
# 然后就可以定位提取url进行图片的保存

2获取滑动的距离

使用opencv可以很好的解决

pip install opencv-python
def get_long():
    # 背景图片处理
    # 灰度图片
    bg_img = cv2.imread('cpt1.png', 0)
    # 高斯滤波,模糊化
    bg_img = cv2.GaussianBlur(bg_img, (3, 3), 0)
    # 边缘检测, 后两个参数为阈值,一般50,150即可
    bg_img = cv2.Canny(bg_img, 50, 150)

    slide_img = cv2.imread('cpt2.png', 0)
    slide_img = cv2.GaussianBlur(slide_img, (3, 3), 0)
    slide_img = cv2.Canny(slide_img, 50, 150)

    # 寻找最佳匹配
    res = cv2.matchTemplate(bg_img, slide_img, cv2.TM_CCORR_NORMED)

    min_val, max_val, min_loc, max_loc = cv2.minMaxLoc(res)

    top_left = max_loc[0]
    return top_left

3模拟人类运动轨迹

def get_track(distance):
    # 记录滑动轨迹
    tracks = []
    # 从0开始
    current = 0
    # 何时开始减速
    mid = distance*4/5
    # 时间
    t = 0.2
    # 速度
    v = 0
    while current < distance:
        # 加速度
        if current < mid:
            a = 3
        else:
            a = -3
        v0 = v
        v = v0 + a*t
        move = v0*t + 1/2 * a * t * t
        tracks.append(round(move))
        current += move
    tracks.append(distance-sum(tracks))
    return tracks

distance即为要滑动的距离,传参数时还需要减去滑块本身所处位置的距离

4滑动

# 按钮定位
button = driver.find_element_by_id('tcaptcha_drag_button')
# 事件处理
webdriver.ActionChains(driver).click_and_hold(button).perform()
# 按照轨迹滑动,perform() 依次执行任务
for t in tmp_track:
    webdriver.ActionChains(driver).move_by_offset(xoffset=t, yoffset=0).perform()
# 释放按钮
webdriver.ActionChains(driver).release(button).perform()

二:不能获取到两张图片

滑动验证码的解决方案_第2张图片
以qidian登陆为例,这里可以看到是无法单独获取到滑块图片,和之前不同的是图片的获取和获取滑动距离,其他都一致

1图片的获取

还是和之前一样,等待滑动验证码的加载完成,这里就不多做注释

wait = WebDriverWait(browser, 30)
wait.until(EC.presence_of_element_located((By.ID, 'loginIfr')))
browser.switch_to.frame('loginIfr')

browser.find_element_by_xpath('//*[@id="username"]').send_keys('qeqwewd')
browser.find_element_by_xpath('//*[@id="password"]').send_keys('qweqwe')
browser.find_element_by_xpath('//*[@id="j-inputMode"]/div[2]/a').click()

wait.until(EC.presence_of_element_located((By.ID, 'tcaptcha_iframe_dy')))
browser.switch_to.frame('tcaptcha_iframe_dy')
# 定位截屏得到图片
browser.find_element_by_id('slideBg').screenshot('captch.png')

滑动验证码的解决方案_第3张图片

2获取滑动距离

def get_long():
    bg_img = cv2.imread('captch.png', 0)
    bg_img = cv2.GaussianBlur(bg_img, (3, 3), 0)
    canny = cv2.Canny(bg_img, 220, 500)
	# 图象的边缘显示
    # cv2.imshow('Canny', canny)
    # cv2.waitKey(10000)
    # 轮廓检测
    contours, hierarchy = cv2.findContours(canny, cv2.RETR_CCOMP, cv2.CHAIN_APPROX_SIMPLE)

    for i, contour in enumerate(contours):  # 所有轮廓
   	    # 面积和周长,可以找一个区间尝试
        if 500 < cv2.contourArea(contour) <= 2000 and 100 < cv2.arcLength(contour, True) < 300:
            # 外接矩形,x,y是矩形左上角的坐标,w,h为宽高
            x, y, w, h = cv2.boundingRect(contour)  
            # print(x, y, w, h)
            # 绘制矩形
            # cv2.rectangle(bg_img, (x, y), (x + w, y + h), (0, 0, 255), 2)
            # cv2.imshow('image', bg_img)
            # cv2.waitKey(10000)
            # 找目标缺口,第一个可能是滑块
            if x <= 200:
                continue
            return int(x-30)

后面就是计算模仿人类移动轨迹,然后进行按钮定位进行滑动即可

三:可以获取到完整的背景图和带有缺口的背景图

这里获取到图片后可以使用pillow来获取滑动的距离

from PIL import Image, ImageChops

img_a  = Image.open(path)
img_b  = Image.open(path)
x = ImageChops.difference(img_a, img_b).getbbox()

x为缺口坐标(left, top, right, bottom)
x[0]即为滑动的距离,记得要减去滑块之前的距离

你可能感兴趣的:(爬虫,python)