参考博客
参考博主不温卜火
博客:爬虫入门经典(十八) | 滑动验证码识别。
在上一章中遗留了一个问题:就是在使用用户名自动化登陆百度的时候,出现了滑动验证码的验证问题,导致了“半自动化”的登录。
今天本篇文章来解决这个问题。
分析
首先是定位标签元素,找到滑块标签block = driver.find_element_by_xpath('//body/div/div/div/div[2]/div[2]/p')
:
然后摁下滑块ActionChains(driver).click_and_hold(block).perform()
,
然后移动距离ActionChains(driver).move_by_offset(165, 0).perform()
165是移动的像素点,
最后释放滑块ActionChains(driver).release().perform()
。
源码
# author: LiuShihao
# data: 2020/12/3 9:55 下午
# youknow: 各位老铁,我的这套代码曾经有人出价三个亿我没有卖,如今拿出来和大家分享,不求别的,只求大家免费的小红心帮忙点一点,这里谢过了。
# desc:
"""
Selenium(浏览器自动化测试框架) 是一个用于Web应用程序测试的工具。
pip3 install selenium -i https://pypi.tuna.tsinghua.edu.cn/simple
下载浏览器驱动,Selenium3.x调用浏览器必须有一个webdriver驱动文件
Chrome : https://chromedriver.storage.googleapis.com/index.html?path=2.35/
FileFox:https://github.com/mozilla/geckodriver/releases
Bug : 驱动浏览器是 Chorme显示正受到自动测试软件的控制
"""
from selenium import webdriver
import time
# 驱动文件路径 字母前加r表示raw string,也叫原始字符串常量。一般用在一下两个方面:
# 1、正则表达式
# 用于处理正则表达式时,规避反斜杠的转义
# 2、系统路径
# 如下面的路径,使用r就防止了\t的转义
from selenium.webdriver import ActionChains
driverfile_path = r'/Users/LiuShihao/PycharmProjects/SpiderPython/Browser/Baidu/chromedriver'
def get_tracks(distance, rate=0.6, t=0.2, v=0):
"""
将distance分割成小段的距离
:param distance: 总距离
:param rate: 加速减速的临界比例
:param a1: 加速度
:param a2: 减速度
:param t: 单位时间
:param v: 初始速度
:return: 小段的距离集合
"""
tracks = []
# 加速减速的临界值
mid = rate * distance
# 当前位移
s = 0
# 循环
while s < distance:
# 初始速度
v0 = v
if s < mid:
a = 20
else:
a = -3
# 计算当前t时间段走的距离
s0 = v0 * t + 0.5 * a * t * t
# 计算当前速度
v = v0 + a * t
# 四舍五入距离,因为像素没有小数
tracks.append(round(s0))
# 计算当前距离
s += s0
return tracks
# 通过用户名登陆
def loginByUsernameAndPwd():
driver.get("https://www.baidu.com/")
# content = driver.page_source
# print("网页内容:", content)
# 使用//a[@name="tj_login"]这种写法虽然在页面可以找到但是 却不可交互 不知道为什么 换下面的写法
# tj_login=driver.find_element_by_xpath('//a[@name="tj_login"]')
tj_login=driver.find_element_by_xpath('//body/div/div/div[@id="u1"]/a')
print("点击登陆按钮")
tj_login.click()
time.sleep(2)
"""
大概意思是程序无法定位到“用户名登录”,
我们可以确定我们写的xpath路径是正确的,
那是为什么呢?原因是程序执行的很快,
在浏览器没加载出“用户名登录”的时候我们程序就开始点击了,
那么我们可以在点击前暂停程序2秒钟等待加载完页面,
"""
usernameLogin=driver.find_element_by_xpath('//div/p[@title="用户名登录"]')
# 获得用户名登陆
# usernameLogin=driver.find_element_by_xpath('//body/div/div[2]/div[2]/div/div/div/div/div/div[3]/p[2]')
usernameLogin.click()
# 获得用户名输入框
driver.find_element_by_xpath('//form/p/input[@name="userName"]').send_keys('用户名')
# 获得密码输入框
driver.find_element_by_xpath('//form/p/input[@name="password"]').send_keys('密码')
# 获得登陆按钮
login = driver.find_element_by_xpath('//form/p/input[@type="submit"]')
# 登录 滑动
login.click()
#
time.sleep(2)
# driver.switch_to.frame(1)
# time.sleep(2)
block = driver.find_element_by_xpath('//body/div/div/div/div[2]/div[2]/p')
while True:
# 摁下滑块
ActionChains(driver).click_and_hold(block).perform()
# 移动
# ActionChains(driver).move_by_offset(212*0.71, 0).perform()
ActionChains(driver).move_by_offset(165, 0).perform()
# # 获取位移
# tracks = get_tracks(212*0.71)
# for track in tracks:
# # 移动
# ActionChains(driver).move_by_offset(track, 0).perform()
# 释放
ActionChains(driver).release().perform()
time.sleep(2)
def loginByQQ():
# 获取不到元素有可能是因为页面还未加载完成,需要将程序睡眠两秒。
driver.get("https://www.baidu.com/") # //a[@name="tj_login"] 百度页面 登陆按钮
# 获取网页内容Elements
# content = driver.page_source
# print("网页内容:",content)
login = driver.find_element_by_xpath('//div[@id="u1"]/a')
# 点击登陆按钮
login.click()
time.sleep(2)
# 定位 qq登陆按钮
qq = driver.find_element_by_xpath('//div/ul/li[@class="bd-acc-qzone"]/a')
# 点击qq登陆
qq.click()
time.sleep(2)
# 此行代码用来新窗口
windows = driver.window_handles
driver.switch_to.window(windows[1])# //a[@id="switcher_plogin"]
driver.find_element_by_id('ptlogin_iframe').click()
driver.maximize_window()
# 切换至账户密码框 irrame框架标签
driver.switch_to.frame('ptlogin_iframe')
# 选择账号密码登陆
driver.find_element_by_id('switcher_plogin').click()
#qq用户
driver.find_element_by_id('u').send_keys('qq账号')
# qq密码
driver.find_element_by_id('p').send_keys('qq密码')
# 登陆
driver.find_element_by_id('login_button').click()
if __name__ == '__main__':
# 不再让Chorme浏览器显示'正受到自动测试软件的控制'
option = webdriver.ChromeOptions()
option.add_experimental_option('useAutomationExtension', False)
option.add_experimental_option('excludeSwitches', ['enable-automation'])
# 启动浏览器
driver = webdriver.Chrome(executable_path=driverfile_path,options=option)
# 最大化
driver.maximize_window()
loginByUsernameAndPwd()
# loginByQQ()
Bug 滑动的距离
这个百度滑动验证码的方式是如果当前失败了会换下一幅图片,拖动的距离每次都不一样,所以很难控制距离。目前代码中将滑动的距离写"死"了,所以只能死循环来碰运气。如果有什么更好的方法,欢迎写在评论区中评论。