python爬蟲之利用selenium+opencv識別滑動驗(yàn)證并模擬登陸知乎功能
滑動驗(yàn)證距離
分別獲取驗(yàn)證碼背景圖和滑塊圖兩張照片,然后利用opencv庫,通過高斯模糊和Canny算法進(jìn)行處理,然后通過matchTemplate方法進(jìn)行兩張圖的匹配,獲得滑動距離。需要注意的是,知乎驗(yàn)證碼在進(jìn)行操作的時候,需要在原有基礎(chǔ)上再向右偏移10px距離
def get_distance(self, bg_img_path='./bg.png', slider_img_path='./slider.png'):
"""獲取滑塊移動距離"""
# 背景圖片處理
bg_img = cv.imread(bg_img_path, 0) # 讀入灰度圖片
bg_img = cv.GaussianBlur(bg_img, (3, 3), 0) # 高斯模糊去噪
bg_img = cv.Canny(bg_img, 50, 150) # Canny算法進(jìn)行邊緣檢測
# 滑塊做同樣處理
slider_img = cv.imread(slider_img_path, 0)
slider_img = cv.GaussianBlur(slider_img, (3, 3), 0)
slider_img = cv.Canny(slider_img, 50, 150)
# 尋找最佳匹配
res = cv.matchTemplate(bg_img, slider_img, cv.TM_CCOEFF_NORMED)
# 最小值,最大值,并得到最小值, 最大值的索引
min_val, max_val, min_loc, max_loc = cv.minMaxLoc(res)
# 例如:(-0.05772797390818596, 0.30968162417411804, (0, 0), (196, 1))
top_left = max_loc[0] # 橫坐標(biāo)
return top_left
滑塊運(yùn)動軌跡
模擬人的行為,到缺口位置時,繼續(xù)向后滑動一段距離,然后再回退到準(zhǔn)確位置
def get_tracks(self, distance):
'''滑動軌跡 '''
tracks = []
v = 0
t = 0.2 # 單位時間
current = 0 # 滑塊當(dāng)前位移
distance += 10 # 多移動10px,然后回退
while current < distance:
if current < distance * 5 / 8:
a = random.randint(1, 3)
else:
a = -random.randint(2, 4)
v0 = v # 初速度
track = v0 * t + 0.5 * a * (t ** 2) # 單位時間(0.2s)的滑動距離
tracks.append(round(track)) # 加入軌跡
current += round(track)
v = v0 + a * t
#回退到大致位置
for i in range(5):
tracks.append(-random.randint(1, 3))
return tracks
鼠標(biāo)滑動操作
通過selenium中的鼠標(biāo)動作鏈,按照滑動軌跡進(jìn)行滑動
def mouse_move(self,slide,tracks):
'''鼠標(biāo)滑動'''
#鼠標(biāo)點(diǎn)擊滑塊并按照不放
ActionChains(self.driver).click_and_hold(slide).perform()
#按照軌跡進(jìn)行滑動,
for track in tracks:
ActionChains(self.driver).move_by_offset(track, 0).perform()
ActionChains(self.driver).release(slide).perform()
規(guī)避知乎selenium檢測
使用selenium自動化測試爬取知乎的時候出現(xiàn)了:錯誤代碼10001:請求異常請升級客戶端后重新嘗試,這個錯誤的產(chǎn)生是由于知乎可以檢測selenium自動化測試的腳本
使用chrome的遠(yuǎn)程調(diào)試模式結(jié)合selenium來遙控操作chrome進(jìn)行抓取,這樣就會規(guī)避selenium被網(wǎng)站檢測到
添加環(huán)境變量
將chrome.exe的目錄添加到系統(tǒng)環(huán)境變量,比如C:\Program Files\Google\Chrome\Application,這樣就可以直接在命令行輸入chrome.exe啟動瀏覽器
打開cmd窗口,執(zhí)行命令
chrome.exe --remote-debugging-port=9222 --user-data-dir="E:\eliwang\selenium_data"
注意端口不要被占用,user-data-dir用來指明配置文件的路徑,自定義
此時會開啟瀏覽器,并打開一個新的標(biāo)簽頁
selenium接管的主要代碼
options.add_experimental_option("debuggerAddress", "127.0.0.1:9222")
關(guān)閉瀏覽器窗口
1、使用瀏覽器對象的close()方法,quit()方法不行。
2、手動打開,手動關(guān)閉
完整登陸代碼
# coding:utf-8
import cv2 as cv
import time
import random
from selenium import webdriver
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.support.ui import WebDriverWait as WAIT
from selenium.webdriver import ActionChains
from selenium.webdriver.common.by import By
from urllib.request import urlretrieve
class Zhihu_login:
'''知乎模擬登陸'''
def __init__(self):
options = webdriver.ChromeOptions()
#操控chrome瀏覽器
options.add_experimental_option("debuggerAddress", "127.0.0.1:9222")
self.driver = webdriver.Chrome(options=options)
self.wait = WAIT(self.driver, 5)
self.url = 'https://www.zhihu.com/'
self.bg_img_path = './bg.png'
self.slider_img_path = './slider.png'
def run(self):
'''執(zhí)行入口'''
self.driver.get(self.url)
try:
if WAIT(self.driver,3).until(EC.presence_of_element_located((By.ID,'Popover15-toggle'))):
print('登陸成功')
self.save_cookie()
self.driver.close()
except:
# 切換到密碼登陸
self.wait.until(EC.element_to_be_clickable((By.XPATH, '//div[contains(@class,"SignFlow-tabs")]/div[2]'))).click()
name_input = self.driver.find_element_by_name('username')
name_input.clear()
name_input.send_keys('賬號')
pass_input = self.driver.find_element_by_name('password')
pass_input.clear()
pass_input.send_keys('密碼')
self.wait.until(EC.element_to_be_clickable((By.XPATH, '//button[@type="submit"]'))).click() # 點(diǎn)擊登陸按鈕
time.sleep(1)
#進(jìn)行滑動驗(yàn)證,最多嘗試5次重新驗(yàn)證
if self.slide_verify():
print('登陸成功')
self.save_cookie()
self.driver.close()
else:
print('第1次登陸失敗')
for i in range(4):
print('正在嘗試第%d次登陸'%(i+2))
if self.slide_verify():
print('第%d次登陸成功'%(i+2))
self.save_cookie()
self.driver.close()
return
print('第%d次登陸失敗' % (i + 2))
print('登陸失敗5次,停止登陸')
self.driver.close()
def slide_verify(self):
'''滑動驗(yàn)證'''
slider_button = self.wait.until(EC.element_to_be_clickable((By.XPATH, '//div[@class="yidun_slider"]')))
self.bg_img_url = self.wait.until(EC.presence_of_element_located((By.XPATH, '//img[@class="yidun_bg-img"]'))).get_attribute('src') # 獲取驗(yàn)證碼背景圖url
self.slider_img_url = self.wait.until(EC.presence_of_element_located((By.XPATH, '//img[@class="yidun_jigsaw"]'))).get_attribute('src') # 獲取驗(yàn)證碼滑塊圖url
urlretrieve(self.bg_img_url, self.bg_img_path)
urlretrieve(self.slider_img_url, self.slider_img_path)
distance = self.get_distance(self.bg_img_path, self.slider_img_path)
distance += 10 # 實(shí)際移動距離需要向右偏移10px
tracks = self.get_tracks(distance)
self.mouse_move(slider_button,tracks)
try:
element = self.wait.until(EC.presence_of_element_located((By.ID,'Popover15-toggle')))
except:
return False
else:
return True
def save_cookie(self):
cookie = {}
for item in self.driver.get_cookies():
cookie[item['name']] = item['value']
print(cookie)
print('成功獲取登陸知乎后的cookie信息')
def mouse_move(self,slide,tracks):
'''鼠標(biāo)滑動'''
#鼠標(biāo)點(diǎn)擊滑塊并按照不放
ActionChains(self.driver).click_and_hold(slide).perform()
#按照軌跡進(jìn)行滑動,
for track in tracks:
ActionChains(self.driver).move_by_offset(track, 0).perform()
ActionChains(self.driver).release(slide).perform()
def get_distance(self, bg_img_path='./bg.png', slider_img_path='./slider.png'):
"""獲取滑塊移動距離"""
# 背景圖片處理
bg_img = cv.imread(bg_img_path, 0) # 讀入灰度圖片
bg_img = cv.GaussianBlur(bg_img, (3, 3), 0) # 高斯模糊去噪
bg_img = cv.Canny(bg_img, 50, 150) # Canny算法進(jìn)行邊緣檢測
# 滑塊做同樣處理
slider_img = cv.imread(slider_img_path, 0)
slider_img = cv.GaussianBlur(slider_img, (3, 3), 0)
slider_img = cv.Canny(slider_img, 50, 150)
# 尋找最佳匹配
res = cv.matchTemplate(bg_img, slider_img, cv.TM_CCOEFF_NORMED)
# 最小值,最大值,并得到最小值, 最大值的索引
min_val, max_val, min_loc, max_loc = cv.minMaxLoc(res)
# 例如:(-0.05772797390818596, 0.30968162417411804, (0, 0), (196, 1))
top_left = max_loc[0] # 橫坐標(biāo)
return top_left
def get_tracks(self, distance):
'''滑動軌跡 '''
tracks = []
v = 0
t = 0.2 # 單位時間
current = 0 # 滑塊當(dāng)前位移
distance += 10 # 多移動10px,然后回退
while current < distance:
if current < distance * 5 / 8:
a = random.randint(1, 3)
else:
a = -random.randint(2, 4)
v0 = v # 初速度
track = v0 * t + 0.5 * a * (t ** 2) # 單位時間(0.2s)的滑動距離
tracks.append(round(track)) # 加入軌跡
current += round(track)
v = v0 + a * t
#回退到大致位置
for i in range(5):
tracks.append(-random.randint(1, 3))
return tracks
if __name__ == '__main__':
Zhihu_login().run()
到此這篇關(guān)于python爬蟲之利用selenium+opencv識別滑動驗(yàn)證并模擬登陸知乎的文章就介紹到這了,更多相關(guān)selenium+opencv滑動驗(yàn)證內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
詳談套接字中SO_REUSEPORT和SO_REUSEADDR的區(qū)別
下面小編就為大家分享一篇詳談套接字中SO_REUSEPORT和SO_REUSEADDR的區(qū)別,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2018-04-04
Python爬蟲之使用MongoDB存儲數(shù)據(jù)的實(shí)現(xiàn)
本文主要介紹了Python爬蟲之使用MongoDB存儲數(shù)據(jù)的實(shí)現(xiàn),文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2023-06-06
Python使用Bokeh進(jìn)行交互式數(shù)據(jù)可視化
Bokeh是一個Python庫,用于在Web瀏覽器中創(chuàng)建交互式數(shù)據(jù)可視化,這篇文章主要為大家學(xué)習(xí)介紹了如何使用Bokeh實(shí)現(xiàn)回執(zhí)交互式數(shù)據(jù)可視化圖表,感興趣的可以學(xué)習(xí)一下2023-07-07
Paddle模型性能分析工具Profiler定位瓶頸點(diǎn)優(yōu)化程序詳解
這篇文章主要為大家介紹了Paddle模型性能分析工具Profiler定位瓶頸點(diǎn)優(yōu)化程序詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-03-03
Python常見數(shù)據(jù)結(jié)構(gòu)之棧與隊(duì)列用法示例
這篇文章主要介紹了Python常見數(shù)據(jù)結(jié)構(gòu)之棧與隊(duì)列用法,結(jié)合實(shí)例形式簡單介紹了數(shù)據(jù)結(jié)構(gòu)中棧與隊(duì)列的概念、功能及簡單使用技巧,需要的朋友可以參考下2019-01-01
如何基于Python實(shí)現(xiàn)一個慶祝國慶節(jié)的小程序
這篇文章主要介紹了如何基于Python實(shí)現(xiàn)一個慶祝國慶節(jié)的小程序,增加了互動選擇祝福語、查詢信息、播放背景音樂及趣味小測驗(yàn)等功能,使用tkinter增強(qiáng)GUI,提升用戶互動體驗(yàn),需要的朋友可以參考下2024-09-09
python基于tkinter點(diǎn)擊按鈕實(shí)現(xiàn)圖片的切換
這篇文章主要介紹了python基于tkinter點(diǎn)擊按鈕實(shí)現(xiàn)圖片的切換,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2021-04-04
Django制作簡易注冊登錄系統(tǒng)的實(shí)現(xiàn)示例
本文介紹了如何使用Django搭建一個簡易的注冊登錄系統(tǒng),文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2024-11-11

