使用selenium進行模擬登錄豆瓣網,利用opencv模塊獲取滑塊驗證碼的缺口,最終實現模擬登錄
涉及
1. selenim啓動360極速瀏覽器
2. selenium獲取標籤、輸入等的基本操作
3. 獲取登錄相關標籤時,遇iframe的解決辦法
3. 獲取滑塊驗證碼圖片,並下載到本地
4. 使用opencv模塊中的"模板匹配"方法獲取缺口的位置
5. 採用物理加速度位移相關公式按照先快後慢的人工滑動規律模擬滑塊運動軌跡
6. selenium滑塊操作
流程
1. 訪問主頁
2. 切換到密碼登錄頁
3. 輸入賬號、密碼,點擊登錄
4. 錯誤登錄幾次後會出現滑塊驗證碼
5. 破解滑塊驗證碼,使驗證通過
詳解
- selenim啓動360極速瀏覽器
1. 下載360極速瀏覽器對應的Chromedriver,下載請點擊,內核版本查詢見下圖
2. 將下載的Chromedriver.exe放到360chrome.exe所在目錄下以及pythonw.exe所在目錄
3. 添加系統環境變量path:F:\360Chrome\Chrome\Application\360chrome.exe
4. 初始化driver
browser_url = r'F:\360Chrome\Chrome\Application\360chrome.exe'
chrome_options = Options()
chrome_options.binary_location = browser_url
# 聲明瀏覽器對象
driver = webdriver.Chrome(chrome_options=chrome_options)
# 登錄豆瓣
# 訪問頁面
driver.get('https://www.douban.com')
- selenium常用操作
1. 詳細操作參考:詳細說明
2. 輸入賬號、密碼
# 通過類名查找 若遇到複合類(即中間有空格)class='account-tab-account on',選取其中一個類即可,#若其再html中不唯一,可採用[index]定位
driver.find_element_by_class_name("account-tab-account").click()
driver.find_element_by_id('username').send_keys('12345678')
driver.find_element_by_id('password').send_keys('qwertyu')
time.sleep(2)
driver.find_element_by_class_name('btn-account').click()
- iframe獲取
1. iframe,又叫浮動幀標記,是內嵌的網頁元素,可以將一個html文件嵌入到另一個html文件中顯示。
# switch_to.frame() 切換到iframe上
# switch_to.default_content() 切換回原主頁面
# 定位到iframe #通過contains函數,提取匹配特定文本的元素
iframe=driver.find_element_by_xpath("//iframe[contains(@src,'//accounts.douban.com/passport/login_popup?login_source=anony')]")
# 切換到iframe
driver.switch_to.frame(iframe)
# 定位到滑塊驗證碼的iframe
slider_iframe = driver.find_element_by_xpath('//div[@id="TCaptcha"]/iframe[1]')
# 切換到iframe
driver.switch_to.frame(slider_iframe)
- 獲取滑塊驗證碼圖片,並下載到本地
1. 獲取驗證碼圖片
# 獲取背景圖和滑塊圖的url
background_image_url=driver.find_element_by_id('slideBkg').get_attribute('src')
slider_image_url=driver.find_element_by_id('slideBlock').get_attribute('src')
# 下載圖片到本地
def get_image(img_url,imgname):
# 以流的形式下載文件
image=requests.get(img_url,stream=True)
# str.join()方法用於將序列中的元素以指定的字符(str)連接生成一個新的字符串
imgName = ''.join(["./", imgname])
with open(imgName, 'wb') as f:
for chunk in image.iter_content(chunk_size=1024): # 循環寫入 chunk_size:每次下載的數據大小
if chunk:
f.write(chunk)
f.flush()
f.close()
- 使用opencv模塊中的"模板匹配"方法獲取缺口的位置
# 使用opencv模塊 計算缺口的偏移值
def get_image_offset(background_image_url,slider_image_url):
back_image='back_image.png' # 背景圖像命名
slider_image='slider_image.png' # 滑塊圖像命名
get_image(background_image_url,back_image)
get_image(slider_image_url,slider_image)
# 獲取圖片並灰度化
block=cv2.imread(slider_image,0)
template=cv2.imread(back_image,0)
w,h=block.shape[::-1]
print(w,h)
# 二值化後圖片名稱
block_name='block.jpg'
template_name='template.jpg'
# 保存二值化後的圖片
cv2.imwrite(block_name,block)
cv2.imwrite(template_name,template)
block=cv2.imread(block_name)
block=cv2.cvtColor(block,cv2.COLOR_RGB2GRAY)
block=abs(255-block)
cv2.imwrite(block_name,block)
block=cv2.imread(block_name)
template=cv2.imread(template_name)
# 獲取偏移量
# 模板匹配,查找block在template中的位置,返回result是一個矩陣,是每個點的匹配結果
result=cv2.matchTemplate(block,template,cv2.TM_CCOEFF_NORMED)
x,y=np.unravel_index(result.argmax(),result.shape)
print(x,y)
# 由於獲取到的驗證碼圖片像素與實際的像素有差(實際:280*158 原圖:680*390),故對獲取到的座標進行處理
offset=y*(280/680)
# 畫矩形圈出匹配的區域
# 參數解釋:1.原圖 2.矩陣的左上點座標 3.矩陣的右下點座標 4.畫線對應的rgb顏色 5.線的寬度
cv2.rectangle(template, (y, x), (y + w, x + h), (7, 249, 151), 2)
show(template)
return offset
# 顯示圖片
def show(name):
cv2.imshow('Show', name)
cv2.waitKey(0)
cv2.destroyAllWindows()
- 模擬運動軌跡
# 採用物理加速度位移相關公式按照先快後慢的人工滑動規律進行軌跡計算,
# 同時還採用了模擬人滑動超過了缺口位置再滑回至缺口的情況以使軌跡更契合人工滑動軌跡
def get_track(distance):
track = []
current = 0
mid = distance * 3 / 4
t=random.randint(2,3)/10
v = 0
while current < distance:
if current < mid:
a = 2
else:
a = -3
v0 = v
v = v0 + a * t
move = v0 * t + 1 / 2 * a * t * t
current += move
track.append(round(move,2))
return track
- selenium滑塊操作
# 定位到滑塊按鈕
button=driver.find_element_by_id('tcaptcha_drag_thumb')
# 拖動操作用到ActionChains類,實例化
action=ActionChains(driver)
# perform()用來執行ActionChains中存儲的行爲
action.click_and_hold(button).perform()
# 清除之前的action
action.reset_actions()
# 獲取軌跡
track=get_track(distance+random.randint(3,5))
print(track)
sum=0
for i in track:
sum+=i
print(sum)
for i in track:
action.move_by_offset(xoffset=i,yoffset=0).perform()
action.reset_actions()
time.sleep(1)
action.release().perform()
time.sleep(3)
driver.quit()
運行結果:
識別率還ok,代碼寫的比較粗糙,後續處理別的網站再進行細節優化