抱歉,你查看的文章不存在

突破有赞后台滑块验证码实现自动登陆,内附Python代码 | 州的先生

一、前言

背景:运营方面需要做份数据报表统计发给领导,涉及到有赞后台数据的统计,如下图所示:

可是运营不想自己弄,有赞方面没有提供相应的数据接口。所以准备用模拟登陆的方式获取这些数据。采用Python3+selenium3实现,本人做PHP程序开发的,python小白一个,大牛请略过此文。

二、破解

登陆入口:

https://account.youzan.com/login

点击登陆:

selenium可以实现对网页元素的定位,通过谷歌浏览器开发者工具获取。我是通过xpath获取的,如下图所示:

鼠标右键单击选中Copy→Copy XPath,通过findelementby_xpath方法获取,部分代码如下图所示:

滑块验证

经过多次尝试,发现有赞后台登陆的滑块“缺口”部分的位置基本上都在靠右侧的一面,而且每次需要拖动的距离都有一定范围。所以只需要设置大概的滑动范围,失败的时候可以通过增减移动距离进行重试即可。

模拟拖动

通过谷歌开发者工具可以看到拖动滑块其实是通过iframe加载进来的,先获取其xpath:

再通过switch_to方法切换frame,通过selenium.webdriver的ActionChains类实现拖动操作部分代码如下所示:

构造移动轨迹

模仿人的滑动行为,先匀加速后匀减速,具体实现代码如下:

验证成功

通过对滑动验证的提示信息可以得知验证是否成功。如下图所示:

通过findelementbyclassname('tcaptcha-title').text来判断验证是否成功。

失败重试

通过设置一个初始距离移动滑块,移动的距离过长的话则减小距离重试滑动,所以需要通过循环处理。具体代码如下:

# coding=utf-8from selenium import webdriverfrom selenium.webdriver.common.by import Byfrom selenium.webdriver import ActionChains  # 滑动验证码from selenium.webdriver.support.ui import WebDriverWait  # available since 2.4.0from selenium.webdriver.support import expected_conditions as EC  # available since 2.26.0from time import sleep
url = "https://account.youzan.com/login"# 登录名和密码username = xxxxx passwd = "xxxx"
# 滑动破解之模拟构造移动轨迹def get_track(distance):    '''    拿到移动轨迹,模仿人的滑动行为,先匀加速后匀减速    匀变速运动基本公式:    ①v=v0+at    ②s=v0t+½at²    ③v²-v0²=2as    :param distance: 需要移动的距离    :return: 存放每0.3秒移动的距离    '''
    v = 0 # 初速度    t = 0.3 # 单位时间为0.2s来统计轨迹,轨迹即0.2内的位移    tracks = [] # 位移/轨迹列表,列表内的一个元素代表0.2s的位移    current = 0 # 当前的位移    mid = distance * 4 / 5 # 到达mid值开始减速
    while current < distance:        if current < mid:            a = 2  # 加速度越小,单位时间的位移越小,模拟的轨迹就越多越详细        else:            a = -3
        v0 = v # 初速度        s = v0 * t + 0.5 * a * (t ** 2) # 0.2秒时间内的位移        current += s # 当前的位置        tracks.append(round(s)) # 添加到轨迹列表        v = v0 + a * t # 速度已经达到v,该速度作为下次的初速度    return tracks

def main():    driver = webdriver.Chrome(executable_path=r"D:\softwares\chromedriver\chromedriver.exe")    driver.set_window_position(900, 10)    driver.get(url)    sleep(1)    # 输入用户名和密码    driver.find_element_by_xpath('//*[@id="app"]/div/div[2]/div[1]/div/div[2]/div/form/div[1]/div/div/input').clear()    driver.find_element_by_xpath('//*[@id="app"]/div/div[2]/div[1]/div/div[2]/div/form/div[1]/div/div/input').send_keys(username)    driver.find_element_by_xpath('//*[@id="app"]/div/div[2]/div[1]/div/div[2]/div/form/div[2]/div/div/input').clear()    driver.find_element_by_xpath('//*[@id="app"]/div/div[2]/div[1]/div/div[2]/div/form/div[2]/div/div/input').send_keys(passwd)    sleep(1)    # 点击登录    driver.find_element_by_xpath('//*[@id="app"]/div/div[2]/div[1]/div/div[2]/div/form/div[3]/div[2]/button').click()    # 检测id为"TCaptcha"的元素是否加在DOM树中,如果出现了才能正常向下执行    element = WebDriverWait(driver, 5, 0.5).until(        EC.presence_of_element_located((By.ID, "TCaptcha"))    )    element.click()    sleep(5)    # 切换iframe    try:        iframe = driver.find_element_by_xpath('//*[@id="TCaptcha"]/iframe')    except Exception as e:        pass    sleep(2)  # 等待资源加载    driver.switch_to.frame(iframe)    # 等待图片加载出来    WebDriverWait(driver, 5, 0.5).until(        EC.presence_of_element_located((By.ID, "tcaptcha_drag_button"))    )    try:        button = driver.find_element_by_id('tcaptcha_drag_button')  # 找到蓝色滑块    except Exception as e:        pass    sleep(1)    # 开始拖动 perform()用来执行ActionChains中存储的行为    flag = 0    distance = 185    offset = 5    times = 0    while 1:        action = ActionChains(driver)        action.click_and_hold(button).perform()        action.reset_actions()  # 清除之前的action        print(distance)        track = get_track(distance)        for i in track:            action.move_by_offset(xoffset=i, yoffset=0).perform()            action.reset_actions()        sleep(0.5)        action.release().perform()        sleep(5)
        try:            alert = driver.find_element_by_class_name('tcaptcha-title').text        except Exception as e:            pass            alert = ''        if alert:            print(u'滑块位移需要调整: %s' % alert)            distance -= offset            times += 1            sleep(5)        else:            print('滑块验证通过')            flag = 1            driver.switch_to.parent_frame()  # 验证成功后跳回最外层页面            break    sleep(2)    driver.quit()    print("success~~")    return flag
if __name__ == '__main__':    main()

三、小结

需要注意一点是,由于受到网络环境影响,有时候加载网页信息比较慢,所以要在程序中加判断条件。还有在多次滑动失败后,会弹出输入验证码,这块验证暂时还没处理。网上还找到一种通过OpenCV识别缺口位置滑动登陆的方式。还有其他的可以看知乎这里大牛的解决思路:https://www.zhihu.com/question/32209043

原文发布于微信公众号 - 州的先生(zmister2016)

原文发表时间:2019-03-02

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

编辑于

州的先生

1 篇文章54 人订阅

扫码关注云+社区

领取腾讯云代金券