填坑記錄
------------------------2021-05-17:-----------------------------------
坑1:放到服務器(vmware虛擬機)后,報:
pyautogui.FailSafeException: PyAutoGUI fail-safe triggered from mouse moving to a corner of the screen. To disable this fail-safe, set pyautogui.FAILSAFE to False. DISABLING FAIL-SAFE IS NOT RECOMMENDED.
原因:
因為通過mstsc啟動遠程桌面連接時,被連接的Windows會啟動一個會話(Session)。此時你對遠程桌面窗口里面的所有操作(鼠標,鍵盤)將會‘翻譯’成TCP包傳輸過去,被連接的Windows接收到這些包之后,‘還原’命令並且在當前的活動會話上面執行。而當你斷開連接時(點X關閉),會話變成斷開狀態,Windows會自動關閉會話(事實上會話還是在的,只是狀態變成斷開的),也就導致了所有基於GUI的操作‘失效’了。
解決方案:
新建一個批處理文件,添加以下下代碼,斷開遠程的時候不要直接斷開,運行上面的bat斷開。就會保持交互狀態
for /f "skip=1 tokens=3" %%s in ('query user %USERNAME%') do (
%windir%\System32\tscon.exe %%s /dest:console
)
參考:https://www.cnblogs.com/sophia201552/p/13344320.html
坑2:還是在服務器上(虛擬機win server2008),解決了上面的問題后,報:找不到元素
原因:
分析日志發現遠程連接上去看到的分辨率(1536*904)和斷開連接的分辨率(800*600)不一樣,然后使用全屏截圖來分析,發現頁面產生了滾動條。
解決方案:
嘗試方案:開始時希望通過修改屏幕分辨率(QRes.exe)使不產生滾動條(無法執行,報錯:沒有****模式)
嘗試方案:調整坐標,增加計算滾動條(計算太復雜了,調不好,主要是驗證碼是彈窗到頁面中間的,浮動到最上層)
最終方案:在開始計算位置和拖曳前,先滾動到最左邊和最上邊(這里能這樣做的原因是因為滑動驗證碼是彈窗,滾動時,該彈窗仍然顯示在屏幕最中間)
執行代碼:
self.browser.execute_script('window.scrollTo(0, 0);')
------------------------ end 填坑記錄 -----------------------------------
遇到過淘寶的滑塊驗證(只有一個從頭到底的滑動),還有類似京東的登錄滑塊(有缺口的)
1、淘寶的滑塊比較簡單,直接用selenium的ActionChain(但后來發現淘寶做了模擬瀏覽器的檢測機制,解決要點在怎么擾亂他的檢查,這個可以看另一篇文章解決:https://www.cnblogs.com/Denny_Yang/p/14764326.html)
類似這種

2、類似京東的這種缺口驗證碼,有兩種,一種是前端有暴露原圖,另一種是沒有暴露原圖。暴露原圖的要簡單一些,沒有暴露原圖的要引入cv2庫來解決
第一種:(實現代碼參考:https://www.cnblogs.com/ohahastudy/p/11493971.html)(因為我需要的不是這種所以沒有測,但應該比較簡單)
(圖一)完整初始圖

(圖二)缺失的塊圖

(圖三)滑塊

(圖四)原圖(沒有暴露下面這張原圖的,要稍微麻煩點)

注意:稍微好點兒的站點都做了滑動時的速度檢測機制,會被判定為機器人行為(如京東)。淘寶做的是直接檢測是否是模擬瀏覽器(你完成拖動后,會報:
哎呀,出錯了,點擊刷新再來一次(error:9AA9Jd)
這里只貼了沒有原圖的自動驗證代碼:
1 #!/usr/bin/python 2 # -*- coding:utf-8 -*- 3 4 import requests 5 import cv2 6 from PIL import Image 7 from selenium import webdriver 8 import pyautogui 9 from numpy import random 10 import time 11 12 13 class SliderVerificationCode: 14 15 def __init__(self): 16 url = 'https://console.ecapi.cn/user/login' 17 self.driver = self.get_url(url, '11111', '222222') 18 19 def get_url(self, url, user, password): 20 browser = webdriver.Chrome(executable_path=r'E:\python\GeckoDriver\chromedriver.exe') 21 browser.get(url) 22 browser.maximize_window() 23 time.sleep(3) 24 user_input = browser.find_element_by_xpath('//*[@id="username"]') 25 pwd_input = browser.find_element_by_xpath('//*[@id="password"]') 26 btn = browser.find_element_by_xpath('//*[@id="formLogin"]/div[4]/div/div/span/button') 27 user_input.send_keys(user) 28 pwd_input.send_keys(password) 29 btn.click() 30 time.sleep(0.5) 31 return browser 32 33 def get_image(self): 34 time.sleep(3) 35 print('frame location:', self.driver.find_element_by_id('tcaptcha_iframe').location) 36 self.driver.switch_to.frame('tcaptcha_iframe') 37 self.target = self.driver.find_element_by_xpath('//*[@id="slideBg"]') 38 self.template = self.driver.find_element_by_xpath('//*[@id="slideBlock"]') 39 self.download_img(self.target.get_attribute('src'), 'target.png') 40 self.download_img(self.template.get_attribute('src'), 'temlate.png') 41 42 # 下載下來的原圖網頁的css有調整尺寸,這樣就需要按照網頁的尺寸來計算偏移 43 self.resize_image('target.png', 'target.png', 341, 195, 'png') 44 self.resize_image('temlate.png', 'temlate.png', 68, 68, 'png') 45 46 def resize_image(self, filein, fileout, width, height, type): 47 img = Image.open(filein) 48 out = img.resize((width, height), Image.ANTIALIAS) 49 # resize image with high-quality 50 out.save(fileout, type) 51 52 def download_img(self, img_url, save_name): 53 host_referer = { 54 'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.106 Safari/537.36' 55 } 56 print('download:' + img_url) 57 html = requests.get(img_url, headers=host_referer) 58 # 圖片不是文本文件,以二進制格式寫入,所以是html.content 59 f = open(save_name, 'wb') 60 f.write(html.content) 61 f.close() 62 63 def find_pic(self, target='target.png', template='temlate.png'): 64 target_rgb = cv2.imread(target) 65 target_gray = cv2.cvtColor(target_rgb, cv2.COLOR_RGB2GRAY) 66 template_rgb = cv2.imread(template, 0) 67 res = cv2.matchTemplate(target_gray, template_rgb, cv2.TM_CCOEFF_NORMED) 68 value = cv2.minMaxLoc(res) 69 # print(value) 70 return value[2][0] 71 72 def size(self): 73 x = self.find_pic() 74 img = cv2.imread('target.png') 75 w1 = img.shape[1] 76 w2 = self.target.size['width'] 77 self.offset = int(x * w2 / w1 + 25) # 這個25沒搞清楚為什么是25... 78 print(self.offset) 79 80 def drag(self): 81 time.sleep(3) 82 The_slider = self.driver.find_element_by_xpath('//*[@id="tcaptcha_drag_button"]') 83 # 780:是驗證碼彈窗距離瀏覽器最左邊的x軸距離(因為在整個驗證碼彈窗是個iframe,所以這個元素的x定位是以iframe的來計算的) 84 # 284:是y軸的 85 x = The_slider.location.get('x') + 780 # 滑塊的初始x位置 86 y = The_slider.location.get('y') + 284 87 print(The_slider.location, ',kw_x = ', x, ',kw_y = ', y) 88 xx = self.offset + 780 - 11 # offset=缺口到iframe邊框的距離 89 90 pyautogui.moveTo(x, y + 127, duration=0.1) 91 92 pyautogui.mouseDown() 93 94 y += random.randint(9, 19) 95 pyautogui.moveTo(x + int(self.offset * random.randint(15, 23) / 20), y, duration=0.28) 96 97 y += random.randint(-9, 0) 98 pyautogui.moveTo(x + int(self.offset * random.randint(17, 21) / 20), y, duration=(random.randint(20, 31)) / 100) 99 100 y += random.randint(0, 8) 101 pyautogui.moveTo(xx, y, duration=0.3) 102 103 # self.driver.save_screenshot('fullscreen.png') 104 print('finally x:{},y:{}'.format(xx, y)) 105 106 pyautogui.mouseUp() 107 108 109 if __name__ == '__main__': 110 p = SliderVerificationCode() 111 p.get_image() 112 p.find_pic() 113 p.size() 114 p.drag() 115 print('end')
PPS:用到的額外的插件包括:cv2(倉庫名是opencv-python)、numpy
pip install時,如果非常慢,可以通過鏡像來安裝:pip install -i https://pypi.tuna.tsinghua.edu.cn/simple numpy
安裝完后,代碼里面有警告,提示找不到引用,這里搞了半天沒解決,但代碼能正確執行,暫時就沒解決了,有解決掉的,煩請告知!

本文源碼大部分摘自:https://blog.csdn.net/qq_42899854/article/details/110671815(python實現滑動京東滑塊驗證碼)
