接上篇《38、selenium關(guān)于Chrome handless的基本使用》
上一篇我們介紹了selenium中有關(guān)Chrome的無頭版瀏覽器Chrome Handless的使用。本篇我們使用selenium做一些常見的復(fù)雜驗證功能,首先我們來講解如何進行滑塊自動驗證的操作。
一、測試用例介紹
我們要通過selenium來實現(xiàn)目前常見的滑塊驗證碼的驗證,以豆瓣的登錄頁面為例:
其操作步驟就是:
(1)打開登錄頁面https://accounts.douban.com/passport/login:
(2)點擊頁面上的“密碼登錄”:
(3)輸入賬號密碼之后,點擊“登錄豆瓣”按鈕:
(4)拼接好彈出的滑塊進行登錄驗證:
二、需要用到的技術(shù)
1、python語言
這里不再贅述,本篇主要還是使用python技術(shù)來實現(xiàn)。
2、selenium庫
selenium是一個用于測試Web應(yīng)用程序的Python庫。它可以模擬用戶在瀏覽器中的操作,例如點擊、填寫表單等。Selenium可以與各種瀏覽器交互,并提供了豐富的API來控制瀏覽器行為和獲取網(wǎng)頁內(nèi)容。
3、urllib庫
urllib是Python標準庫之一,用于處理URL相關(guān)的操作。它包含多個子模塊,例如urllib.request用于發(fā)送HTTP請求并獲取響應(yīng),urllib.parse用于解析和構(gòu)建URL,urllib.error用于處理URL相關(guān)的錯誤等。urllib常用于網(wǎng)絡(luò)數(shù)據(jù)抓取、訪問API等任務(wù)。
4、cv2庫
cv2是OpenCV(Open Source Computer Vision)庫的Python綁定。OpenCV是一個廣泛使用的計算機視覺庫,提供了豐富的圖像處理和計算機視覺算法。cv2庫為Python開發(fā)者提供了對OpenCV功能的訪問,可以進行圖像加載、處理、分析以及計算機視覺任務(wù),如人臉識別、目標檢測等。
安裝注意事項:
如果直接通過pip install cv2安裝報錯的話,請使用下面的語句安裝:
pip install opencv-python
5、random庫
random是Python的隨機數(shù)生成庫。它提供了多種隨機數(shù)生成函數(shù),包括生成偽隨機數(shù)的函數(shù)和從序列中隨機選擇元素的函數(shù)。random庫可用于模擬、游戲開發(fā)、密碼學等領(lǐng)域,以及各種需要隨機性的應(yīng)用程序。
6、re庫
re是Python的正則表達式模塊,用于對字符串進行模式匹配和處理。正則表達式是一種強大的文本匹配工具,可以用來搜索、替換、提取特定模式的字符串。re庫提供了函數(shù)和方法來編譯正則表達式、執(zhí)行匹配操作,并返回匹配結(jié)果,使得處理文本數(shù)據(jù)更加靈活和高效。
三、實現(xiàn)步驟
下面我們使用代碼來實現(xiàn)滑塊的驗證。
1、打開登錄頁切換密碼登錄
第一步,打開登錄頁面,并點擊頁面上的“密碼登錄”:代碼:
import time ?# 事件庫,用于硬性等待
from selenium import webdriver ?# 導(dǎo)入selenium的webdriver模塊
from selenium.webdriver.common.by import By ?# 引入By類選擇器
# 創(chuàng)建Chrome WebDriver對象
driver = webdriver.Chrome()
try:
? ? # 打開豆瓣登錄頁
? ? driver.get("https://accounts.douban.com/passport/login")
? ? print(driver.title) ?# 打印頁面的標題
? ? # (1)獲取“密碼登錄”選項元素,并點擊它
? ? # 使用瀏覽器的F12開發(fā)者工具,使用copy xpath獲取該元素的XPATH路徑
? ? passClick = driver.find_element(By.XPATH, '//*[@id="account"]/div[2]/div[2]/div/div[1]/ul[1]/li[2]')
? ? passClick.click()
? ? # 整體等待5秒看結(jié)果
? ? time.sleep(5)
finally:
? ? # 關(guān)閉瀏覽器
? ? driver.quit()
效果:
值得注意的是,這里的“密碼登錄”的CSS選擇器路徑,是通過瀏覽器F12打開開發(fā)者選項,使用“copy xpath”功能復(fù)制的。
效果:
2、輸賬密點擊登錄
第二步,輸入賬號密碼,并點擊“登錄豆瓣”按鈕:
# 使用瀏覽器隱式等待3秒
driver.implicitly_wait(3)
# 獲取賬號密碼組件并賦值
userInput = driver.find_element(By.ID, "username")
userInput.send_keys("jackzhucoder@126.com")
passInput = driver.find_element(By.ID, "password")
passInput.send_keys("123456")
# 獲取登錄按鈕并點擊登錄
loginButton = driver.find_element(By.XPATH, '//*[@id="account"]/div[2]/div[2]/div/div[2]/div[1]/div[4]/a')
loginButton.click()
這里的登錄按鈕的xpath路徑,也是使用開發(fā)者選項的“copy xpath”功能復(fù)制。
效果:
3、切換焦點并下載驗證圖片
將焦點切換至滑塊驗證區(qū)域,并下載加載好的滑塊驗證背景圖片。
點擊登錄按鈕后,就會出現(xiàn)滑塊驗證區(qū)域,這是一個新增的frame區(qū)域,此時我們需要將切換的焦點從主頁面轉(zhuǎn)換到這個frame區(qū)域上:
代碼上我們使用WebDriver的switch_to.frame方法即可,參數(shù)就是frame區(qū)域的id名“tcaptcha_iframe_dy”。
然后我們需要獲取整個需要對其的大圖片,獲取其路徑并下載到本地,準備進行讀取驗證:
這里圖片元素獲取比較簡單,通過ID名“slideBg”獲取即可,但是圖片路徑需要分析其style屬性中的css參數(shù),通過正則表達式將圖片src地址解析出來,然后通過urllib訪問這個路徑將圖片下載下來。
解析圖片前,一定一定要等待圖片元素加載完成之后再獲取,否則會什么也解析不到。
代碼:
driver.implicitly_wait(5) ?# 使用瀏覽器隱式等待5秒
# 此時需要切換到彈出的滑塊區(qū)域,需要切換frame窗口
driver.switch_to.frame("tcaptcha_iframe_dy")
# 等待滑塊驗證圖片加載后,再做后面的操作
WebDriverWait(driver, 10).until(EC.visibility_of_element_located((By.ID, 'slideBg')))
# 獲取滑塊驗證圖片下載路徑,并下載到本地
bigImage = driver.find_element(By.ID, "slideBg")
s = bigImage.get_attribute("style") ?# 獲取圖片的style屬性
# 設(shè)置能匹配出圖片路徑的正則表達式
p = 'background-image: url\(\"(.*?)\"\);'
# 進行正則表達式匹配,找出匹配的字符串并截取出來
bigImageSrc = re.findall(p, s, re.S)[0] ?# re.S表示點號匹配任意字符,包括換行符
print("滑塊驗證圖片下載路徑:", bigImageSrc)
# 下載圖片至本地
urllib.request.urlretrieve(bigImageSrc, 'bigImage.png')
下載圖片的效果:
4、拖動滑塊至缺口處
我們接下來要做的,是將小拼圖圖片,移動到缺口處:
我們需要獲取小圖片到缺口處的實際距離,一般用到兩種方法。
第一種方法是模板匹配,通過openCV分析兩個圖片的相似度,獲取兩個相似度很高圖片的坐標,從而計算兩個圖片的距離。
第二種方法是輪廓檢測,通過openCV進行輪廓檢測,即在大圖片中找到缺口位置的坐標,然后計算小圖片到缺口位置的距離。
這里因為我們無法單獨獲取小拼圖的單獨圖片,所以不好使用模板匹配的方法,所以我們選擇使用第二種輪廓檢測的方法。
(1)得到缺口輪廓位置信息
首先我們計算一下缺口的坐標及面積大概有多大,使用PhotoShop打開下載的圖片,單獨將缺口按照正方形的尺寸摳出來,發(fā)現(xiàn)其長寬各是80像素:
所以這個封閉矩形的面積范圍大概是在80*80=6400像素左右。周長是80*4=320像素。但是現(xiàn)實中這里是有缺口的,不是一個完整的圖片,所以我們需要給它一定的誤差范圍,這里我們暫定目標區(qū)域面積為5025-7225,周長為300-380。
然后我們將計算距離的邏輯封裝為一個方法:
# 封裝的計算圖片距離的算法
def get_pos(imageSrc):
? ? # 讀取圖像文件并返回一個image數(shù)組表示的圖像對象
? ? image = cv2.imread(imageSrc)
? ? # GaussianBlur方法進行圖像模糊化/降噪操作。
? ? # 它基于高斯函數(shù)(也稱為正態(tài)分布)創(chuàng)建一個卷積核(或稱為濾波器),該卷積核應(yīng)用于圖像上的每個像素點。
? ? blurred = cv2.GaussianBlur(image, (5, 5), 0, 0)
? ? # Canny方法進行圖像邊緣檢測
? ? # image: 輸入的單通道灰度圖像。
? ? # threshold1: 第一個閾值,用于邊緣鏈接。一般設(shè)置為較小的值。
? ? # threshold2: 第二個閾值,用于邊緣鏈接和強邊緣的篩選。一般設(shè)置為較大的值
? ? canny = cv2.Canny(blurred, 0, 100) ?# 輪廓
? ? # findContours方法用于檢測圖像中的輪廓,并返回一個包含所有檢測到輪廓的列表。
? ? # contours(可選): 輸出的輪廓列表。每個輪廓都表示為一個點集。
? ? # hierarchy(可選): 輸出的輪廓層次結(jié)構(gòu)信息。它描述了輪廓之間的關(guān)系,例如父子關(guān)系等。
? ? contours, hierarchy = cv2.findContours(canny, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
? ? # 遍歷檢測到的所有輪廓的列表
? ? for contour in contours:
? ? ? ? # contourArea方法用于計算輪廓的面積
? ? ? ? area = cv2.contourArea(contour)
? ? ? ? # arcLength方法用于計算輪廓的周長或弧長
? ? ? ? length = cv2.arcLength(contour, True)
? ? ? ? # 如果檢測區(qū)域面積在5025-7225之間,周長在300-380之間,則是目標區(qū)域
? ? ? ? if 5025 < area < 7225 and 300 < length < 380:
? ? ? ? ? ? # 計算輪廓的邊界矩形,得到坐標和寬高
? ? ? ? ? ? # x, y: 邊界矩形左上角點的坐標。
? ? ? ? ? ? # w, h: 邊界矩形的寬度和高度。
? ? ? ? ? ? x, y, w, h = cv2.boundingRect(contour)
? ? ? ? ? ? print("計算出目標區(qū)域的坐標及寬高:", x, y, w, h)
? ? ? ? ? ? # 在目標區(qū)域上畫一個紅框看看效果
? ? ? ? ? ? cv2.rectangle(image, (x, y), (x+w, y+h), (0, 0, 255), 2)
? ? ? ? ? ? cv2.imwrite("111.jpg", image)
? ? ? ? ? ? return x
? ? return 0
然后在下載圖片后調(diào)用該方法:
# 下載圖片至本地
urllib.request.urlretrieve(bigImageSrc, 'bigImage.png')
# 計算缺口圖像的x軸位置
dis = get_pos('bigImage.png')
# 整體等待5秒看結(jié)果
time.sleep(5)
效果:
生成的目標區(qū)域畫紅框的計算圖片:
好了,到此為止我們獲取到了一個重要的數(shù)據(jù),就是缺口的位置信息。
(2)匹配小滑塊元素
得到小滑塊元素,讓其移動位置到上面計算的距離。
這里我們移動的位置,并不是直接拿剛剛我們得到的圖片上的x1減去小滑塊的x2坐標,因為我們打開F12開發(fā)者界面,可以看到整體圖片的寬度是小于原來下載下來的圖片的(網(wǎng)頁開發(fā)者為其固定了長寬),所以我們要重新計算一下缺口的x1位置相對于更小的這塊圖片的位置:
計算的方法就是拿原來的坐標乘以新畫布的寬度,再除以原畫布的寬度:
新缺口坐標=原缺口坐標*新畫布寬度/原畫布寬度
原理就是小學數(shù)字(見圖):
下面開始寫代碼。
首先獲取小滑塊的xpath地址,用于獲取該元素:
代碼:
# 計算缺口圖像的x軸位置
dis = get_pos('bigImage.png')
# 獲取小滑塊元素,并移動它到上面的位置
smallImage = driver.find_element(By.XPATH, '//*[@id="tcOperation"]/div[6]')
# 小滑塊到目標區(qū)域的移動距離(缺口坐標的水平位置距離小滑塊的水平坐標相減的差)
# 新缺口坐標=原缺口坐標*新畫布寬度/原畫布寬度
newDis = int(dis*340/672-smallImage.location['x'])
driver.implicitly_wait(5) ?# 使用瀏覽器隱式等待5秒
# 按下小滑塊按鈕不動
ActionChains(driver).click_and_hold(smallImage).perform()
# 移動小滑塊,模擬人的操作,一次次移動一點點
i = 0
moved = 0
while moved < newDis:
?? ?x = random.randint(3, 10) ?# 每次移動3到10像素
?? ?moved += x
?? ?ActionChains(driver).move_by_offset(xoffset=x, yoffset=0).perform()
?? ?print("第{}次移動后,位置為{}".format(i, smallImage.location['x']))
?? ?i += 1
# 移動完之后,松開鼠標
ActionChains(driver).release().perform()
# 整體等待5秒看結(jié)果
time.sleep(5)
由于大部分網(wǎng)站有檢測真人操作的邏輯,所以我們這里要模擬真人進行移動操作,不能一下移動到目標點,需要一點一點的移動。
效果:
selenium自動驗證滑塊效果
四、完整代碼
以下是上面按照步驟編寫完畢的完整代碼(截止2023年10月6日),后期網(wǎng)站有更新或者元素布局有所變化,需要各位修改優(yōu)化。
本代碼僅供學習參考,切勿用于其他用途。文章來源:http://www.zghlxwxcb.cn/news/detail-717747.html
# _*_ coding : utf-8 _*_
# @Time : 2023-10-06 9:44
# @Author : 光仔December
# @File : 豆瓣登錄自動滑動驗證
# @Project : Python基礎(chǔ)
import random
import re ?# 正則表達式匹配庫
import time ?# 事件庫,用于硬性等待
import urllib ?# 網(wǎng)絡(luò)訪問
import cv2 ?# opencv庫
from selenium import webdriver ?# 導(dǎo)入selenium的webdriver模塊
from selenium.webdriver.common.by import By ?# 引入By類選擇器
from selenium.webdriver.support.wait import WebDriverWait ?# 等待類
from selenium.webdriver.support import expected_conditions as EC ?# 等待條件類
from selenium.webdriver.common.action_chains import ActionChains ?# 動作類
# 封裝的計算圖片距離的算法
def get_pos(imageSrc):
? ? # 讀取圖像文件并返回一個image數(shù)組表示的圖像對象
? ? image = cv2.imread(imageSrc)
? ? # GaussianBlur方法進行圖像模糊化/降噪操作。
? ? # 它基于高斯函數(shù)(也稱為正態(tài)分布)創(chuàng)建一個卷積核(或稱為濾波器),該卷積核應(yīng)用于圖像上的每個像素點。
? ? blurred = cv2.GaussianBlur(image, (5, 5), 0, 0)
? ? # Canny方法進行圖像邊緣檢測
? ? # image: 輸入的單通道灰度圖像。
? ? # threshold1: 第一個閾值,用于邊緣鏈接。一般設(shè)置為較小的值。
? ? # threshold2: 第二個閾值,用于邊緣鏈接和強邊緣的篩選。一般設(shè)置為較大的值
? ? canny = cv2.Canny(blurred, 0, 100) ?# 輪廓
? ? # findContours方法用于檢測圖像中的輪廓,并返回一個包含所有檢測到輪廓的列表。
? ? # contours(可選): 輸出的輪廓列表。每個輪廓都表示為一個點集。
? ? # hierarchy(可選): 輸出的輪廓層次結(jié)構(gòu)信息。它描述了輪廓之間的關(guān)系,例如父子關(guān)系等。
? ? contours, hierarchy = cv2.findContours(canny, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
? ? # 遍歷檢測到的所有輪廓的列表
? ? for contour in contours:
? ? ? ? # contourArea方法用于計算輪廓的面積
? ? ? ? area = cv2.contourArea(contour)
? ? ? ? # arcLength方法用于計算輪廓的周長或弧長
? ? ? ? length = cv2.arcLength(contour, True)
? ? ? ? # 如果檢測區(qū)域面積在5025-7225之間,周長在300-380之間,則是目標區(qū)域
? ? ? ? if 5025 < area < 7225 and 300 < length < 380:
? ? ? ? ? ? # 計算輪廓的邊界矩形,得到坐標和寬高
? ? ? ? ? ? # x, y: 邊界矩形左上角點的坐標。
? ? ? ? ? ? # w, h: 邊界矩形的寬度和高度。
? ? ? ? ? ? x, y, w, h = cv2.boundingRect(contour)
? ? ? ? ? ? print("計算出目標區(qū)域的坐標及寬高:", x, y, w, h)
? ? ? ? ? ? # 在目標區(qū)域上畫一個紅框看看效果
? ? ? ? ? ? cv2.rectangle(image, (x, y), (x + w, y + h), (0, 0, 255), 2)
? ? ? ? ? ? cv2.imwrite("111.jpg", image)
? ? ? ? ? ? return x
? ? return 0
# 創(chuàng)建Chrome WebDriver對象
driver = webdriver.Chrome()
try:
? ? # 打開豆瓣登錄頁
? ? driver.get("https://accounts.douban.com/passport/login")
? ? print(driver.title) ?# 打印頁面的標題
? ? # (1)獲取“密碼登錄”選項元素,并點擊它
? ? # 使用瀏覽器的F12開發(fā)者工具,使用copy xpath獲取該元素的XPATH路徑
? ? passClick = driver.find_element(By.XPATH, '//*[@id="account"]/div[2]/div[2]/div/div[1]/ul[1]/li[2]')
? ? passClick.click()
? ? driver.implicitly_wait(3) ?# 使用瀏覽器隱式等待3秒
? ? # 獲取賬號密碼組件并賦值
? ? userInput = driver.find_element(By.ID, "username")
? ? userInput.send_keys("jackzhucoder@126.com")
? ? passInput = driver.find_element(By.ID, "password")
? ? passInput.send_keys("123456")
? ? # 獲取登錄按鈕并點擊登錄
? ? loginButton = driver.find_element(By.XPATH, '//*[@id="account"]/div[2]/div[2]/div/div[2]/div[1]/div[4]/a')
? ? loginButton.click()
? ? driver.implicitly_wait(5) ?# 使用瀏覽器隱式等待5秒
? ? # 此時需要切換到彈出的滑塊區(qū)域,需要切換frame窗口
? ? driver.switch_to.frame("tcaptcha_iframe_dy")
? ? # 等待滑塊驗證圖片加載后,再做后面的操作
? ? WebDriverWait(driver, 10).until(EC.visibility_of_element_located((By.ID, 'slideBg')))
? ? # 獲取滑塊驗證圖片下載路徑,并下載到本地
? ? bigImage = driver.find_element(By.ID, "slideBg")
? ? s = bigImage.get_attribute("style") ?# 獲取圖片的style屬性
? ? # 設(shè)置能匹配出圖片路徑的正則表達式
? ? p = 'background-image: url\(\"(.*?)\"\);'
? ? # 進行正則表達式匹配,找出匹配的字符串并截取出來
? ? bigImageSrc = re.findall(p, s, re.S)[0] ?# re.S表示點號匹配任意字符,包括換行符
? ? print("滑塊驗證圖片下載路徑:", bigImageSrc)
? ? # 下載圖片至本地
? ? urllib.request.urlretrieve(bigImageSrc, 'bigImage.png')
? ? # 計算缺口圖像的x軸位置
? ? dis = get_pos('bigImage.png')
? ? # 獲取小滑塊元素,并移動它到上面的位置
? ? smallImage = driver.find_element(By.XPATH, '//*[@id="tcOperation"]/div[6]')
? ? # 小滑塊到目標區(qū)域的移動距離(缺口坐標的水平坐標距離小滑塊的水平坐標相減的差)
?? ?# 新缺口坐標=原缺口坐標*新畫布寬度/原畫布寬度
? ? newDis = int(dis*340/672-smallImage.location['x'])
? ? driver.implicitly_wait(5) ?# 使用瀏覽器隱式等待5秒
? ? # 按下小滑塊按鈕不動
? ? ActionChains(driver).click_and_hold(smallImage).perform()
? ? # 移動小滑塊,模擬人的操作,一次次移動一點點
? ? i = 0
? ? moved = 0
? ? while moved < newDis:
? ? ? ? x = random.randint(3, 10) ?# 每次移動3到10像素
? ? ? ? moved += x
? ? ? ? ActionChains(driver).move_by_offset(xoffset=x, yoffset=0).perform()
? ? ? ? print("第{}次移動后,位置為{}".format(i, smallImage.location['x']))
? ? ? ? i += 1
? ? # 移動完之后,松開鼠標
? ? ActionChains(driver).release().perform()
? ? # 整體等待5秒看結(jié)果
? ? time.sleep(5)
finally:
? ? # 關(guān)閉瀏覽器
? ? driver.quit()
參考:小飛刀2018《Selenium驗證碼滑動登錄》
轉(zhuǎn)載請注明出處:https://guangzai.blog.csdn.net/article/details/133827764文章來源地址http://www.zghlxwxcb.cn/news/detail-717747.html
到了這里,關(guān)于【Python從入門到進階】39、使用Selenium自動驗證滑塊登錄的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!