思路:
1、獲取帶滑塊的圖片
2、獲取不帶滑塊、完整的圖片
3、比較兩張圖片中不一樣的地方,找到滑塊的坐標
4、通過滑塊坐標來拖動瀏覽器
代碼:
import random import time from PIL import Image from io import BytesIO import requests as rq from bs4 import BeautifulSoup as bs from selenium import webdriver from selenium.webdriver import ActionChains from selenium.webdriver import ChromeOptions def crop_image(image_file_name): # 保存圖片 # 截圖驗證碼圖片 # 定位某個元素在瀏覽器中的位置 time.sleep(2) img = browser.find_element_by_xpath("//*[@class='geetest_canvas_slice geetest_absolute']") location = img.location print("圖片的位置", location) size = img.size top, buttom, left, right = location["y"], location["y"]+size["height"], location["x"], location['x'] + size["width"] print("驗證碼位置", left,top, right, buttom) screenshot = browser.get_screenshot_as_png() screenshot = Image.open(BytesIO(screenshot)) captcha = screenshot.crop((int(left),int(top), int(right), int(buttom))) captcha.save(image_file_name) return captcha def compare_pixel(image1, image2, i, j): # 判斷兩個圖片像素是否相同 pixel1 = image1.load()[i, j] pixel2 = image2.load()[i, j] threshold = 60 if abs(pixel1[0] - pixel2[0]) < threshold and abs(pixel1[1] - pixel2[1]) < threshold and abs(pixel1[2] - pixel2[2]) < threshold: return True return False def find_coordinate(left, img1, img2): # 根據判斷結果,返回x坐標 has_find = False for i in range(left, img1.size[0]): # x坐標 if has_find: # 找到不一樣的位置,退出外層循環 break for j in range(img1.size[1]): # y坐標(從0開始) if not compare_pixel(img1, img2, i, j): # 比較兩張圖片在同一位置的值 left = i has_find = True # 如果兩張圖片元素不一樣,那么就退出內層循環 break return left options = ChromeOptions() #實例化一個ChromeOptions對象,設置參數避免被檢測 options.add_experimental_option('excludeSwitches', ['enable-automation']) #以鍵值對的形式加入參數 options.add_argument("--no-sandbox") options.add_argument("--start-maximized") # 最大化窗口,一定要最大化,不然坐標會不准 options.add_argument('--disable-gpu') browser=webdriver.Chrome(options=options) time.sleep(0.6) browser.get('https://www.bilibili.com/') # 訪問網站 time.sleep(0.5) button = browser.find_element_by_xpath('//div[@class="mini-login van-popover__reference"]') # 登陸 button.click() browser.switch_to.window(browser.window_handles[1]) # 對於新窗口,切換窗口句柄,不然句柄還保持在上一窗口,后面捕捉會出錯 user = browser.find_element_by_xpath('//input[@id="login-username"]') user.send_keys('19444338') # 用戶名 time.sleep(0.5) passwd = browser.find_element_by_xpath('//input[@id="login-passwd"]') passwd.send_keys('3346777') # 密碼 time.sleep(0.5) login = browser.find_element_by_xpath('//a[@class="btn btn-login"]') # 點擊登錄,出現驗證碼圖片 login.click() time.sleep(0.5) # 滑塊驗證 def slid_verify(): # 缺口圖片 img1 = crop_image('缺口圖片.png') time.sleep(0.5) # 完整圖片 # JS增刪改查操作元素的屬性 # #新增屬性 # driver.execute_script(“arguments[0].%s=arguments[1]” %attributeName,elementObj, value) # #修改屬性 # driver.execute_script(“arguments[0].setAttribute(arguments[1],arguments[2])”, elementObj, attributeName, value) # #獲取屬性 # elementObj.get_attribute(attributeName) # #刪除屬性 # driver.execute_script(“arguments[0].removeAttribute(arguments[1])”,elementObj, attributeName) # https://blog.csdn.net/DansonC/article/details/99398096 img_obj = browser.find_element_by_xpath('//*[@class="geetest_canvas_fullbg geetest_fade geetest_absolute"]') # 找到圖片,建立對象 # img_style = img_obj.get_attribute('style') # 記錄style的值 browser.execute_script("arguments[0].removeAttribute(arguments[1])",img_obj, 'style') # 刪除圖片屬性,顯示完整圖片 img2 = crop_image('完整圖片.png') # browser.execute_script("arguments[0].setAttribute(arguments[1],arguments[2])", img_obj, 'style', img_style) # 將style值添加回去,顯示缺口圖片 slider = browser.find_element_by_xpath("//div[@class='geetest_slider_button']") # 找到拖動按鈕 ActionChains(browser).move_to_element(slider).perform() # 建立拖動對象 # 獲取滑塊圖片位置 slid_coor = find_coordinate(2, img1, img2) # 獲取缺口圖片位置 target_coor = find_coordinate(57, img1, img2) print(slid_coor, target_coor) target_coor -= 6 # 調整偏移量 #拖動圖片 track = [] # 用於儲存一次拖動滑塊的距離(不能一次拖到位,不然會被判定為機器) i = 0 # 分為3斷,分別設置不同速度,越接近缺口,越慢 stagev1 = round((target_coor-slid_coor)/4) # 第1段(前3/5):分為4次(平均距離移動),stafev1為當前階段的速度 while i<round(target_coor* 3/5): i += stagev1 track.append(stagev1) stagev2 = round((target_coor-i)/7) # 第2段(3/5到21/25):分為7次(平均距離移動) while i<round(target_coor*21/25): i += stagev2 track.append(stagev2) stagev3 = 1 while i<round(target_coor): # 第3段(21/25到最后):按1為單位移動 i += stagev3 track.append(stagev3) ActionChains(browser).click_and_hold(slider).perform() # 點擊,並按住鼠標不放 for x in track: ActionChains(browser).move_by_offset(xoffset=x, yoffset=0).perform() # 拖動,x為一次移動的距離 time.sleep(0.5) ActionChains(browser).release().perform() # 放開鼠標 time.sleep(1) success_flag = Selector(text=browser.page_source).xpath('/html/body/div[2]/div[2]/div[6]/div/div[1]/div[1]/div/div[3]/div/div[2]/text()').extract()[0] return success_flag success_flag = slid_verify() while '超過' not in success_flag: # 成功后,會有:'sec 秒的速度超過 score% 的用戶' if '怪物吃了拼圖,請重試' == success_flag: # 這是被判定為機器操作,需要"點擊重試" reclick = browser.find_element_by_xpath("//div[@class='geetest_panel_error_content']") reclick.click() re_verify = browser.find_element_by_xpath("//div[@class='geetest_slider_button']") re_verify.click() success_flag = slid_verify() time.sleep(0.5)
