使用python實現(xiàn)一個瀏覽器自動化的腳本
背景
最近工作中有這樣一個需求:客戶反饋在瀏覽器操作過程中,重復(fù)流程操作太頻繁,能不能讓瀏覽器自動操作完成?
在我的認知中,瀏覽器就是一個用來瀏覽頁面的工具,因此第一反應(yīng)就是“不可能!絕對不可能!”。領(lǐng)導(dǎo)說,你了解過RPA嗎?會后專門查閱了相關(guān)資料,在我的理解中,RPA就是一個定制化機器人(腳本流程),通過控制腳本操作顯示器,來模擬用戶操作的過程。
開始
一開始的時候,我在github上面找了一些開源的項目,例如:PyRPA、RPA-Python、TagUI、openrpa等,但是因為定制化比較強,后期不知道會變成怎么樣,因此做的要靈活一些。但是在這些開源項目中,提供了一部分的api,但是在有些地方并不是很容易操作,感覺后面可能會不可控。
但是在我觀察中發(fā)現(xiàn),大多數(shù)的實現(xiàn)都是通過python
實現(xiàn)的,作為一個前端,第一反應(yīng)就是,為什么不用node和js結(jié)合呢,最后反應(yīng)過來,使用python可以操作整個PC,但是如果你使用node或js,只能說操作瀏覽器更方便一些了(其實和python差不多),只是python在使用第三方庫時候,會存在一定程度的延時。
因此,我決定放棄現(xiàn)有的RPA的項目,自己實現(xiàn)一個自動化的python腳本。
語言選擇
關(guān)于我為什么選擇的python作為語言,其實在前面已經(jīng)說過了,作為一個前端開發(fā),其實最熟悉的莫過于javascript,另加一些nodejs,那么為什么我沒有用nodejs呢?node在前端開發(fā)過程中,常常扮演著一個環(huán)境的角色,雖然也可以作為一個后端語言來寫一些接口或服務(wù)(依賴于第三方庫),但是很少用到DOM的操作,操作瀏覽器的DOM,我們通常來說,都是使用js直接操作,或使用jquery等第三方工具。如果要再直接去攔截系統(tǒng)的一些操作,js就不太行了。
因此,采取了python,這一門熱度一直很高的語言。主要思路就是,圖片的對比,獲取點位,模擬用戶鼠標,鍵盤等操作。
瀏覽器的啟動
其實這個啟動瀏覽器,一開始我只是單純的打開瀏覽器,但是后面發(fā)現(xiàn),每天第一次啟動的時候,都會特別慢,查閱資料也沒有找到原因,好像是緩存被清空了吧,網(wǎng)上找了大量的相關(guān)資料,最終找到了一個方案:加載時候啟動指定驅(qū)動程序(瀏覽器版本
與驅(qū)動程序
需要對應(yīng)),指定版本瀏覽器下載,新版驅(qū)動下載,114版本前驅(qū)動下載,有一部分頁面需要科學(xué)上網(wǎng)才能訪問與下載,建議大家科學(xué)上網(wǎng)昂。
一個啟動瀏覽器的demo,這里的driver我在后續(xù)就不就行重復(fù)的定義了,直接使用了,例如:
from selenium import webdriver from selenium.webdriver.chrome.service import Service driver = webdriver.Chrome(service=Service(r"C:\\tb2Lot\\driver\\chromedriver.exe")) driver.maximize_window() driver.execute_script("document.charset='utf-8';") driver.get("http://www.baidu.com")
這時候我們就已經(jīng)可以打開瀏覽器,并操作瀏覽器調(diào)取到百度的頁面了,我們想在百度的頁面輸入并搜索指定內(nèi)容怎么辦呢?這時候我們就需要獲取頁面的元素節(jié)點,然后進行輸入了,下面我們來看一下如何在瀏覽器搜索吧!
在百度進行搜索的方案
首先我們先列舉一下目前能夠想到的兩個方案:
- 從頁面抓取頁面
元素路徑
,然后直接點擊元素; - 整個頁面截圖,再截取需要點擊的小圖片,獲取需要點擊的
圖片的坐標
,點擊坐標;
這兩種方案對于簡單的操作都是可行的,復(fù)雜一些的,會出現(xiàn)一些問題,我們先看一下兩種方案分別怎么進行操作,然后再來分析一下會遇見怎樣的問題吧!
頁面抓取元素,直接點擊:
import pyautogui import pyperclip import time from selenium.webdriver.common.by import By def cvEnter(msg): pyperclip.copy(msg) time.sleep(1) pyautogui.hotkey('ctrl','v') time.sleep(1) pyautogui.hotkey('enter') #回車搜索 #driver的定義在本文最上面,這里沒有重復(fù)寫 #... cvEnter("稀土掘金") driver.find_element(By.XPATH,r'//*[@id="su"]').click() #通過瀏覽器的xpath觸發(fā)點擊事件 time.sleep(2) driver.find_element(By.XPATH,r'//*[@id="kw"]').clear() #清除輸入框 driver.find_element(By.XPATH,r'//*[@id="kw"]').send_keys('稀土掘金官網(wǎng)') #輸入框輸入數(shù)據(jù) pyautogui.hotkey('enter') time.sleep(5)
在上面,其實我們已經(jīng)使用了兩種輸入與搜索的方式:
輸入
- 方式一:通過
粘貼板
,直接進行“c+v”; - 方式二:借助python瀏覽器的driver的
send_keys
方法,直接鍵入;
搜索(這里是回車和點擊實現(xiàn)的都是搜索)
- 方式一:使用pyautogui的
鍵盤熱鍵觸發(fā)
; - 方式二:借助python瀏覽器的driver獲取瀏覽器
元素
,觸發(fā)該元素的click
事件;
通過圖片的對比,獲取點位進行點擊
import pyautogui import cv2 def getPosiXY(img): pyautogui.screenshot('./pics/screen.png') #顯示完成之后,截圖 screen = cv2.imread('./pics/screen.png') #加載全屏截圖 current = cv2.imread(f'./tb2lot_pic/{img}') #加載比對的圖片 result = cv2.matchTemplate(screen, current, cv2.TM_CCOEFF_NORMED) #在screen中尋找current的點位 pos_start = cv2.minMaxLoc(result)[3] x = int(pos_start[0]) + int(current.shape[1]/2) y = int(pos_start[1]) + int(current.shape[0]/2) return x,y pointX, pointY = getPosiXY("query_btn.png") pyautogui.click(pointX, pointY)
在上面的demo中,我們借助cv2
庫,實現(xiàn)了一個簡單的大圖中尋找小圖的功能,這里在獲取之前自動截圖
并保存
到指定目錄,小圖
的名稱作為參數(shù),傳遞到封裝的方法中,抓取點位信息,再點擊獲取到的坐標
位置。因為我們抓取的坐標點,因此如果點擊的輸入框,輸入框粘貼數(shù)據(jù),就需要直接通過粘貼板進行粘貼了。
為什么我們前面說抓取元素會有問題呢?
首先我們最理想的元素抓取就是,都在一個html中,沒有動態(tài)的元素,沒有切換界面,沒有切換彈窗等,但是在實際的應(yīng)用過程中,往往都是比較復(fù)雜的,例如:
vue打包的html
(元素的id不是固定的,有時候元素節(jié)點渲染的問題,嵌套可能有點區(qū)別);html嵌套了iframe
(直接切換了代碼引用的窗口,后面都統(tǒng)一叫做句柄);選擇框
的元素,展開和關(guān)閉不一致;- ...
以上的問題,都會導(dǎo)致直接抓取元素xpath
直接調(diào)取時候報錯
,難道我們就真的不能用xpath進行操作了嗎?答案當然是否定的,但是也不是完全,例如在iframe
中,我們可以切換句柄
,來達到代碼引用模塊的更換,例如:
#driver的定義在本文最上面,這里沒有重復(fù)寫 #... iframeSrc = driver.find_element(By.XPATH,r'/html/body/div/iframe') driver.switch_to.frame(iframeSrc) # 切換句柄到iframe #driver.switch_to.default_content() #切換到默認的句柄 driver.find_element(By.XPATH,r'/html/body/form/div/input').click()
這樣看來,我們iframe也是可以抓取到元素的,不過要等待頁面渲染完成
之后再去抓取,否則還是會報錯的。其余的兩個,因為元素是動態(tài)的,如果只是id
的問題的話,我們可以使用full xpath
進行抓取,但是如果元素嵌套都有可能變化的話,就只能采取截圖比對的方式了。
此外,我們也再添加一段代碼,比如開啟瀏覽器兩個標簽頁的時候與標簽頁之間的切換怎么處理:
driver.get("http://www.baidu.com") #打開標簽1 driver.execute_script("window.open('http://www.baidu.com');") #打開標簽2 driver.switch_to.window(driver.window_handles[0]) # 手動切換到標簽1
最后
其實到這里,python簡單的控制瀏覽器就已經(jīng)結(jié)束了,其實圖片的對比不局限于瀏覽器,它可以截取PC的屏幕上的所有,因此也可以模擬APP的操作,但是我們在調(diào)取的過程中,常常會報錯,但是如果打包成了exe文件,我們并不知道報的什么錯,因此我們也可以在最外層加上try-except,如果檢測到報錯,我們可以將報錯內(nèi)容記錄在txt中,模擬日志
的效果,例如:
from datetime import datetime, timedelta try: # some codes except Exception as e: now = datetime.now() date_time = now.strftime("%Y-%m-%d %H:%M:%S") data_to_append = f"{date_time}\n{e}\n\n" with open('C:\\logs\\error.txt', 'a') as file: file.write(data_to_append) print("Error!", e) driver.quit() raise ValueError("Error!")
最后打開預(yù)覽報錯信息,例如:
代碼
import pyautogui import pyperclip import time from selenium.webdriver.common.by import By from selenium import webdriver from selenium.webdriver.chrome.service import Service from datetime import datetime, timedelta def cvEnter(msg): pyperclip.copy(msg) time.sleep(1) pyautogui.hotkey('ctrl','v') time.sleep(1) pyautogui.hotkey('enter') try: driver = webdriver.Chrome(service=Service(r"C:\\pyExe\\driver\\chromedriver.exe")) #驅(qū)動寫在最上面 driver.maximize_window() driver.execute_script("document.charset='utf-8';") driver.get("http://www.baidu.com") driver.implicitly_wait(10) cvEnter("稀土掘金") driver.find_element(By.XPATH,r'//*[@id="su"]').click() #通過瀏覽器的xpath觸發(fā)點擊事件、 time.sleep(2) driver.find_element(By.XPATH,r'//*[@id="kw"]').clear() driver.find_element(By.XPATH,r'//*[@id="kw"]').send_keys('稀土掘金官網(wǎng)') pyautogui.hotkey('enter') time.sleep(5) except Exception as e: now = datetime.now() date_time = now.strftime("%Y-%m-%d %H:%M:%S") data_to_append = f"{date_time}\n{e}\n\n" with open('C:\\pyExe\\logs\\error.txt', 'a') as file: file.write(data_to_append) print("Error!", e) driver.quit() raise ValueError("Error!")
代碼打包
pyinstaller --onefile --noconsole --icon ./favorite.ico ./index.py # --noconsole 隱藏黑窗口 # --icon ./favorite.ico 打包后的應(yīng)用圖標(路徑選對,僅支持ico) # ./index.py 需要打包的py文件路徑
有時候打包完圖標沒有變化,是默認的圖標,可以查看屬性,屬性中應(yīng)該是已經(jīng)有了的,這是因為應(yīng)用緩存的原因,刷新一下應(yīng)用程序即可。
重中之重?。。?/strong>
打包完成之后,將打包后的dist/index.exe文件,移到之前index.py同級目錄下,因為如果涉及到圖片的比對,會導(dǎo)致圖片的位置訪問失敗。
以上就是使用python實現(xiàn)一個瀏覽器自動化的腳本的詳細內(nèi)容,更多關(guān)于python瀏覽器自動化的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
一篇文章帶你搞定Ubuntu中打開Pycharm總是卡頓崩潰
這篇文章主要介紹了一篇文章帶你搞定Ubuntu中打開Pycharm總是卡頓崩潰,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-11-11Python緩存方案優(yōu)化程序性能提高數(shù)據(jù)訪問速度
Python緩存方案是一種優(yōu)化程序性能,提高數(shù)據(jù)訪問速度的方案。通過緩存數(shù)據(jù),可以減少重復(fù)的計算和IO操作,從而提高程序的運行效率。Python中常用的緩存方案包括內(nèi)存緩存、磁盤緩存和分布式緩存等,根據(jù)實際需求選擇不同的方案可以幫助我們更好地優(yōu)化程序性能2023-05-05總結(jié)Python圖形用戶界面和游戲開發(fā)知識點
在本篇文章里小編給大家整理了關(guān)于Python圖形用戶界面和游戲開發(fā)知識點以及實例代碼,需要的朋友們學(xué)習(xí)下。2019-05-05Python自動檢測requests所獲得html文檔的編碼
這篇文章主要為大家詳細介紹了如何通過Python自動檢測requests實現(xiàn)獲得html文檔的編碼,文中的示例代碼講解詳細,感興趣的可以了解下2024-11-11