0


python selenium模块联合带带弟弟破解滑块验证码

兄弟们肯定在搞爬虫时经常遇到滑块验证码的反爬措施,这苦恼了我几天,好在有dddd和selenium模块助我前行

第一个函数是登录函数,主要就是输入用户名和密码后自动弹出滑块验证码

主要用到selenium模块

导入模块:

from selenium import webdriver

from selenium.webdriver.common.by import By

知识点:

drive = webdriver.Firefox()

#创建实例,浏览器为火狐

element = driver.find_element(By.XPATH,"这里锁定元素输入xpath路径就行")

#利用By.XPATH锁定元素当然还有By.CLASSNAME、By.ID等等,提供不同元素名锁定元素

element.send_keys("111")

#向锁定的element元素输入111值

element.click()

#点击该元素

如果遇到同一CLASSBNAME有两个元素

可以使用

element = driver.find_elements(By.CLASSNAME)[1]

这样的方式锁定第二个元素位置 注意:element后面有个s

​
def login(driver,uname,pwd):
    """
    某系统登录框输入手机号和密码,并点击成功
    """
    driver.get("https://user.xxxx.com/user/ut=1&style=1#/pages/white-hat/login/login")
    # 等待页面加载完成,设置超时停止加载
    try:
        driver.set_page_load_timeout(10)
    except:
        pass
    # 点击同意按钮
    ty = driver.find_element(By.XPATH,"/html/body/div/div/div[2]/div[2]/div/div[1]/div[2]/div/div[1]/div/div[2]/div[1]/div[1]/form/div[3]/label/span[1]/span")
    ty.click()
    #输入手机号
    phone = driver.find_element(By.XPATH,"/html/body/div/div/div[2]/div[2]/div/div[1]/div[2]/div/div[1]/div/div[2]/div[1]/div[1]/form/div[1]/div/div[2]/input")
    phone.send_keys(uname)
    #输入密码
    passwd = driver.find_element(By.XPATH,"/html/body/div/div/div[2]/div[2]/div/div[1]/div[2]/div/div[1]/div/div[2]/div[1]/div[1]/form/div[2]/div/div[2]/input")
    passwd.send_keys(pwd)
    #点击登录
    dl = driver.find_element(By.XPATH,"/html/body/div/div/div[2]/div[2]/div/div[1]/div[2]/div/div[1]/div/div[2]/div[1]/div[1]/form/div[4]/div/button")
    dl.click()

​

接下来silder_imgs函数主要是提取出滑动模块的三个图片,主要是为了计算移动距离而准备

def slider_imgs(driver):
    """
    保存每次滑动验证码的三个图片
    """
    #定位背景图元素的位置
    active = True
    while active:
        try:
            time.sleep(1)
            img_element = driver.find_element(By.XPATH,"/html/body/div[2]/div[2]/div[6]/div/div[1]/div[1]/div/a/div[1]/div/canvas[1]")
            hk_element = driver.find_element(By.XPATH,"/html/body/div[2]/div[2]/div[6]/div/div[1]/div[1]/div/a/div[1]/div/canvas[2]")
            yt_element = driver.find_element(By.XPATH,"/html/body/div[2]/div[2]/div[6]/div/div[1]/div[1]/div/a/div[1]/canvas")
            active = False
        except:
            continue
    # 执行js 获取改元素的data:url
    img_data_b64 = driver.execute_script("return arguments[0].toDataURL('image/png').substring(22);",img_element)
    hk_data_b64 = driver.execute_script("return arguments[0].toDataURL('image/png').substring(22);",hk_element)
    yt_data_b64 = driver.execute_script("return arguments[0].toDataURL('image/png').substring(22);",yt_element)
    #解码
    img_data = base64.b64decode(img_data_b64)
    hk_data = base64.b64decode(hk_data_b64)
    yt_data = base64.b64decode(yt_data_b64)
    #以二进制保存
    with open("./imgs/bg.png","wb") as f:
        f.write(img_data)
        #print("[*]滑块验证码背景图已保存")
    with open("./imgs/hk.png","wb") as f:
        f.write(hk_data)
        #print("[*]滑块验证码滑块图片已保存")
    with open("./imgs/yt.png","wb") as f:
        f.write(yt_data)
        #print("[*]滑块验证码原图已保存")
    print("[*]保存滑动验证码成功")

提取出来如下图所示,(hk_jg.png是下一个模块处理后的结果,不用管)

计算距离的主要需要图片就是通过hk.png处理后的hk_jg.png和bg.png两个图片

接下来处理hk.png为hk_jg.png

直接传入hk.png这种图片的路径,可以实现将带有白框的图片截取成只有图片的最小方框,例如:

这么多白框的图片变成下图这种

代码实现如下所示

def hk_chuli(hk_img):
    """
    处理滑块图片
    :return:
    """
    image = Image.open(hk_img)  # 打开tiff图像
    ImageArray = np.array(image)
    row = ImageArray.shape[0]
    col = ImageArray.shape[1]
    # 先计算所有图片的裁剪范围,然后再统一裁剪并输出图片
    x_left = row
    x_top = col
    x_right = 0
    x_bottom = 0

    for r in range(row):
        for c in range(col):
            # if ImageArray[row][col][0] < 255 or ImageArray[row][col][0] ==0:
            if ImageArray[r][c][0] < 255 and ImageArray[r][c][0] != 0:  # 外框有个黑色边框,增加条件判断
                if x_top > r:
                    x_top = r  # 获取最小x_top
                if x_bottom < r:
                    x_bottom = r  # 获取最大x_bottom
                if x_left > c:
                    x_left = c  # 获取最小x_left
                if x_right < c:
                    x_right = c  # 获取最大x_right
    #print(x_left, x_top, x_right, x_bottom)
    cropped = image.crop((x_left - 5, x_top - 5, x_right + 5, x_bottom + 5))  # (left, upper, right, lower)
    cropped.save(r".\imgs\{}.png".format("hk_jg"))
    print("[*]处理滑块图片成功")

现在开始引入带带弟弟(ddddocr)模块计算滑动距离了

模块引用:
import ddddocr

知识点:

det = ddddocr.Dddd0cr(det=False,show_ad=False)

#创建实例

det.slide_match(hk_jg,bgsimple_target=True)

#传入处理好的滑块图片和有缺口的背景图片,实现计算距离,准确度很高,但是可能固定查5左右,要自己调试

def get_len(hk,bg):
    """
    调用ddddocr获取滑动距离
    """
    det = ddddocr.DdddOcr(det=False,ocr=False,show_ad=False)
    with open(hk,"rb") as f:
        hk = f.read()
    with open(bg,"rb") as f:
        bg = f.read()

    res = det.slide_match(hk,bg,simple_target=True)
    return res["target"][0]

下一步就是利用selenium模块拖动滑块元素移动了

具体解释都在代码块里,这里再提一点,由于极验的滑块验证码会检验鼠标轨迹,所以必须模拟人手的鼠标滑动轨迹,所以我搞了一个加速的函数

get_tracks就是加速函数,这个函数各位直接拿去用就行,不用理解,在自动滑动的时候引用就行

def get_tracks(distance):
    """
    拿到移动轨迹,模拟人的滑动行为,先匀加速后匀减速
    匀变速运动基本公式:
    1.v=v₀+at
    2.s=v₀t+1/2*at²
    :param distance:滑块一次性快速移动到某一位置后剩下的距离,进行五等分
    :return:位置/轨迹列表,列表内的一个元素代表0.3s的位移
    """
    v = 0  # 初速度
    t = 0.3  # 单位时间为0.3s来统计轨迹,轨迹即0.3内的位移
    tracks = []  # 位置/轨迹列表,列表内的一个元素代表0.3s的位移
    current = 0  # 当前的位移
    mid = distance * 4 / 5  # 到达mid值开始减速,前4/5匀加速,后1/5匀减速
    while current < distance:
        if current < mid:  # 加速度越小,单位时间内的位移越小,模拟的轨迹就越多越详细
            a = 2
        else:
            a = -3
        v0 = v  # 初速度
        s = v0 * t + 0.5 * a * (t ** 2)  # 0.3s内的位移
        current += s  # 当前的位置
        tracks.append(round(s))  # 添加到轨迹列表
        v = v0 + a * t  # 速度已经达到v,该速度作为下次的初速度
    return tracks  # tracks:[第1个0.3s的移动距离,第2个0.3s的移动距离,......]

滑动函数如下所示

def slider_verification_code(driver,length):
    """
    滑动滑块验证码
    """
    #按住滑块按钮
    silder = driver.find_element(By.XPATH,"/html/body/div[2]/div[2]/div[6]/div/div[1]/div[2]/div[2]")
    # 创建鼠标动态链,
    subiao = ActionChains(driver)
    # 点击指定元素并保持
    subiao.click_and_hold(on_element=silder).perform()
    # 滑动指定单位  xoffset代表水平方向的移动 正数为向右
    subiao.move_to_element_with_offset(to_element=silder,xoffset=15,yoffset=15).perform()
    time.sleep(0.5)
    #使用加速度
    tracks = get_tracks(length-15)
    for track in tracks:
        subiao.move_by_offset(xoffset=track,yoffset=0).perform()
    # 放开鼠标
    time.sleep(1)
    subiao.release().perform()
    #网络不给力情况
    try:
        continue_element = driver.find_element(By.XPATH, "/html/body/div[2]/div[2]/div[4]/div[3]")
        if continue_element:
            print("[*]出现网络不给力情况,立马开始重试")
            continue_element.click()
            main()
    except:
        pass
    # 没绕过情况
    try:
        #检测滑动验证码是否还存在
        huadon = driver.find_element(By.CLASS_NAME,"geetest_slider_button")
        if huadon:
            # 刷新
            sx = driver.find_element(By.XPATH, "/html/body/div[2]/div[2]/div[6]/div/div[2]/div/a[2]")
            sx.click()
            print("[*]绕过滑动验证码失败,开始下一次尝试\n")
            main()
        try:
        #检测是否出现多次尝试失败情况
            hk_anniu_element = driver.find_element(By.CLASS_NAME,"geetest_slider_button")
        except:
            print("[*]ERROR:多次尝试绕过验证码失败,立马开始重试\n")
            conshi_element = driver.find_element(By.XPATH,"/html/body/div[2]/div[2]/div[4]/div[3]")
            conshi_element.click()
            time.sleep(2)
            main()
    except:
        print("[*]滑动验证码bypass成功\n")
        pass

破解效果视频如下所示

滑动验证码绕过效果视频


本文转载自: https://blog.csdn.net/weixin_67289581/article/details/137020217
版权归原作者 网安_秋刀鱼 所有, 如有侵权,请联系我们删除。

“python selenium模块联合带带弟弟破解滑块验证码”的评论:

还没有评论