声明:本文只作学习研究,禁止用于非法用途,否则后果自负,如有侵权,请告知删除,谢谢!
项目场景:
这次给大家带来的是知乎的selenium自动登入,使用的是qq授权的登入入口,链接在此,之前有尝试使用登入的API接口进行模拟登入,但是没有成功 ~,所以还是老老实实先用浏览器登入吧。
解决方案:
1.OK,现在开始尝试吧,点击qq授权图标,再点击账号密码登入,输入qq账号密码后,就会跳出补缺口的滑块类型验证码.
2.乍一看补缺块的验证码很头痛,这个网站还好,并没有生物行为特征的检测,只要计算出滑块需要滑动的距离即可。具体验证思路如下:
- 先获取两张图片,一张是有缺口的完整图,一张是缺块图。
- 然后进行二值化处理。
- 接着使用cv2.matchTemplate去匹配滑块所在缺口图的位置,返回距离x,再去浏览器上获取实际滑动的距离distance。
- 这个时候拿到的x并不是selenium去模拟滑动的距离,需要多测几组(x,distance),然后再用曲线拟合工具,来计算出实际需要滑动距离的公式。
- 最后获取的距离才是selenium实际滑动的距离。
3.先说两张图片的获取方法,两个图片地址OK。
4.计算缺块位置。
def get_diff_location():
# 获取图片并灰度化
block = cv2.imread("block.jpg", 0) # 缺块图片
index = cv2.imread("index.jpg", 0) # 背景图片
# 二值化后的图片名称
block1 = "block1.jpg"
index1 = "index1.jpg"
# 将二值化后的图片进行保存
cv2.imwrite(block1, block)
cv2.imwrite(index1, index)
block = cv2.imread(block1)
block = cv2.cvtColor(block, cv2.COLOR_RGB2GRAY)
block = abs(255 - block)
cv2.imwrite(block1, block)
block = cv2.imread(block1)
template = cv2.imread(index1)
# 获取偏移量
result = cv2.matchTemplate(block, template, cv2.TM_CCOEFF_NORMED) # 查找block在template中的位置,返回result是一个矩阵,是每个点的匹配结果
x, y = np.unravel_index(result.argmax(), result.shape)
# print("x方向的偏移", int(y * 0.4 + 18), 'x:', x, 'y:', y)
return y
5.获取实际滑动距离,两个值减一下。
6.然后4,5步骤多取几组数据放到曲线拟合的网站来输出换算的公式,最后我们用selenium测试一下,一般1-3次就会成功!
7.最后贴下完整的代码!
import cv2
import numpy as np
import time
import requests
from selenium import webdriver
from selenium.webdriver import ActionChains
from selenium.webdriver.common.desired_capabilities import DesiredCapabilities
def get_diff_location():
# 获取图片并灰度化
block = cv2.imread("block.jpg", 0) # 缺块图片
index = cv2.imread("index.jpg", 0) # 背景图片
# 二值化后的图片名称
block1 = "block1.jpg"
index1 = "index1.jpg"
# 将二值化后的图片进行保存
cv2.imwrite(block1, block)
cv2.imwrite(index1, index)
block = cv2.imread(block1)
block = cv2.cvtColor(block, cv2.COLOR_RGB2GRAY)
block = abs(255 - block)
cv2.imwrite(block1, block)
block = cv2.imread(block1)
template = cv2.imread(index1)
# 获取偏移量
result = cv2.matchTemplate(block, template, cv2.TM_CCOEFF_NORMED) # 查找block在template中的位置,返回result是一个矩阵,是每个点的匹配结果
x, y = np.unravel_index(result.argmax(), result.shape)
# print("x方向的偏移", int(y * 0.4 + 18), 'x:', x, 'y:', y)
return y
def run():
url = 'https://www.zhihu.com/signin?next=%2F'
option = webdriver.ChromeOptions()
option.add_experimental_option('excludeSwitches', ['enable-automation']) # webdriver防检测
option.add_argument("--no-sandbox")
option.add_argument("--disable-dev-usage")
desired_capabilities = DesiredCapabilities.CHROME # 修改页面加载策略
desired_capabilities["pageLoadStrategy"] = "none" # 注释这两行会导致最后输出结果的延迟,即等待页面加载完成再输出
driver = webdriver.Chrome(options=option)
driver.get(url)
time.sleep(2)
driver.find_element_by_xpath('//*[@id="root"]/div/main/div/div/div/div[3]/span[2]/button[2]').click() # 点击qq授权登入
time.sleep(2)
driver.switch_to.window(driver.window_handles[-1]) # 切换句柄
time.sleep(1)
driver.switch_to.frame("ptlogin_iframe")
driver.find_element_by_id('switcher_plogin').click() # 点击密码登入
time.sleep(2)
#输入账号密码
driver.find_element_by_id('u').send_keys('123123123')
driver.find_element_by_id('p').send_keys('123123123')
time.sleep(1)
# 点击登入
driver.find_element_by_id('login_button').click()
time.sleep(3)
driver.switch_to.frame('tcaptcha_iframe')
while True:
# 保存带缺块的背景图
with open('index.jpg','wb') as f:
url = driver.find_element_by_id('slideBg').get_attribute('src')
f.write(requests.get(url).content)
# 保存缺块图
with open('block.jpg','wb') as f:
url = driver.find_element_by_id('slideBlock').get_attribute('src')
f.write(requests.get(url).content)
#获取滑块
button = driver.find_element_by_id('tcaptcha_drag_thumb')
# 滑动滑块
ActionChains(driver).click_and_hold(button).perform()
x = get_diff_location()
print('拟合前的距离',x)
if x > 500:
# 刷新验证码
print('拟合前的距离有误')
ActionChains(driver).release().perform() # 释放鼠标
driver.find_element_by_id('e_reload').click()
time.sleep(2)
continue
distance = int(-0.002886710239855681*x*x*x+4.044880174577657*x*x-1888.1544118978823*x+293800.78433441074)
if (distance > 200) and (distance < 300):
distance -= 100
elif distance > 300:
print('距离出错')
# 刷新验证码
ActionChains(driver).release().perform() # 释放鼠标
driver.find_element_by_id('e_reload').click()
time.sleep(2)
continue
print('需要滑动的大概距离',distance)
ActionChains(driver).move_by_offset(xoffset=distance, yoffset=0).perform()
time.sleep(1)
ActionChains(driver).release().perform() # 释放鼠标
time.sleep(2)
# 检测是否滑动成功
try:
driver.find_element_by_id('tcaptcha_drag_thumb')
print('滑动失败,即将再次尝试!')
# 刷新验证码
driver.find_element_by_id('e_reload').click()
time.sleep(2)
except Exception:
break
print('验证成功!')
time.sleep(11111)
if __name__ == '__main__':
run()