Try   HackMD

Python Selenium with VSCODE 教學筆記

綱要

不知道為什麼這篇莫名其妙在Google搜尋「Selenium 教學」的排名特別前面
來信問開課的人突然暴增,但目前沒有收費開課的打算,所以之後會找個時間把進階教學寫一寫,有更多對E2E自動化測試有興趣的人一起學習是好事。

關於Chrome的Webdriver

如果你已經使用了115版以後的版本,要改從這裡下載相應的Driver
https://googlechromelabs.github.io/chrome-for-testing/#stable

基本環境安裝

Selenium自動化測試需要借用能操作瀏覽器的Driver之外,也需要輔以一些額外的套件進行。

以下依照順序詳解:

Windows

一、安裝Python最新版

安裝最新版本的Python(目前3.9.6):https://www.python.org/downloads/

安裝路徑預設在windows上是:

C:\Users\你的使用者名稱\AppData\Local\Programs\Python\Python39

記得在安裝畫面將Add Python 3.9 to PATH也勾選起來,便於之後安裝一些Package。

安裝好後如下所示,以「系統管理者身分」執行cmd

接著在終端機上輸入python,看到這訊息代表Python安裝成功了。

由於部分使用者在執行Python指令時,WINDOWS會彈出線上商店的關係。

現在需要到WINDOWS的系統環境變數修改些路徑:

按下「編輯系統環境變數」後會看到這個畫面,再按「環境變數」

進入環境變數視窗後選擇「path」>> 「編輯」,檢查看看Python的安裝路徑。

確認Python是不是擺在「windowApps」之前。

如果不是,就用右邊的上移、下移按鈕處理後按下確定。

假如你安裝Python時忘了把Add to path打勾

那就把這個路徑新增到系統變數 >> Path裡面去:

C:\Users\你的電腦帳號\AppData\Local\Programs\Python\Python目前版本\Scripts

權限問題排除

若敲指令時發生「python 不是内部或外部命令」的錯誤訊息出現時。
我們需要調整一下Windows的PowerShell權限設定。

在開始選單下的「Windows PowerShell」下,以系統管理員身分執行一次

並且輸入指令:Set-ExecutionPolicy RemoteSigned

輸入A選擇「全部皆是」,然後把VSCODE和終端機重開即可。

二、安裝Selenium套件

然後繼續輸入指令quit()跳出剛才有>>>的Python指令區

現在輸入我們要安裝Selenium的指令 pip install selenium

出現Successfully installed selenium 的訊息即可。


三、安裝 WebDriver

自動測試需要使用到瀏覽器行為的控制事件,所以我們要安裝相應的WebDriver以及版本。

如果你不清楚現在使用的Chrome版本,網址輸入chrome://settings/help 可以查看:

下載 Chrome WebDriver

https://chromedriver.chromium.org/downloads

如果有遇到Chrome更新,就要重新安裝對應版本的WebDriver

WebDriver存放的路徑,建議是放在Python安裝好的根目錄下,也就是:
C:\Users\你的使用者名稱\AppData\Local\Programs\Python\Python39

這樣即可在任何路徑下的腳本中隨時調用driver的功能。

第二個方式比較不推薦,不過當有著需要測試不同版本瀏覽器時可以參考看看:

regression_test
├── case_1
│   ├── chromedriver.exe
│   └── test_login.py
├── case_2
│   ├── chromedriver.exe
│   └── test_keno_bet.py

由於通常測試腳本都會進入Git版控管理,Driver本身的體積就有10MB左右

這樣做反而會讓專案打包Push上去遠端後佔用太多容量。


四、安裝BeautifulReport自動測試報告套件

下載並安裝BeautifulReport

假如你已經會使用Git,直接Clone這個位置:
https://github.com/TesterlifeRaymond/BeautifulReport.git

~~或者前往Github網址: (作者不再更新,然後原始版本的cdn異常緩慢)
https://github.com/TesterlifeRaymond/BeautifulReport

建議試著用我改好cdn位置的繁體化修改版本:
https://drive.google.com/file/d/1zQlAt1p-0CQoXnIjJFLdFp7SCuuVkZG2/view?usp=sharing

按下Code後選擇Download ZIP

解壓縮後將目錄名稱改為BeautifulReport

點入BeautifulReport會看到這些檔案:

回上一層,將整個BeautifulReport目錄複製到以下路徑即可:
C:\Users\你的使用者名稱\AppData\Local\Programs\Python\Python39\Lib\site-packages\

安裝webdriver-manager

接著回到終端機,我們需要webdriver manager的支援。
輸入指令:
pip install webdriver-manager


五、安裝VSCODE與IDE擴充套件

網址:https://code.visualstudio.com/

安裝成功後打開VSCODE,按一下左下的Extensions開啟擴充套件視窗,搜尋以下幾個套件:

1. Pylance

微軟提供的語法智能輔助工具,包含語法檢查與Debugging。

2. Path Intellisense

路徑選擇的輔助工具,當需要輸入來源程式碼、圖片、CSS等檔案時

依照輸入 .././ 的不同,自動會幫我們開啟相關目錄下拉視窗來選擇來源檔案。


Mac OSX

安裝Home Brew(有裝過的話可以跳過)

/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"

使用Home Brew安裝Python 3

brew install python3

安裝pip 3套件管理工具

python3 get-pip.py

確認有正確安裝pip 3

pip3 --version

安裝Selenium 4.0

pip3 install selenium

安裝webdriver manager套件

pip3 install webdriver-manager

下載webdriver

https://chromedriver.chromium.org/downloads

下載好相應版本後放在mac根目錄下: /usr/local/bin

如果你的chrome版本超過114,請下載這裡的
https://googlechromelabs.github.io/chrome-for-testing/


將BeautifulReport套件下載後解壓縮到以下路徑

下載位置:https://drive.google.com/file/d/1zQlAt1p-0CQoXnIjJFLdFp7SCuuVkZG2/view?usp=sharing
解壓縮到:

/opt/homebrew/lib/python3.11/site-package

VSCODE設定

和Windows沒有相異,所以VSCODE的設定參照一下Windows的部分即可


腳本對於元素定位的XPATH是怎麼找出來的

Python Selenium對於取得當前需要被操作的元素,常見方法有:

1. XPATH

HTML經過編譯成XML後找出的對應位置,分絕對位置與相對位置。
相對位置://div[@class='ytp-tooltip-text-wrapper']
絕對位置: /html[1]/body[1]/ytd-app[1]/div[1]/ytd-page-manager[1]/ytd-watch-flexy[1]/div[5]/div[1]/div[1]/div[1]/div[1]/div[1]/div[1]/ytd-player[1]/div[1]/div[1]/div[10]/div[1]

2. CSS Selector

可以透過CSS選取器取得元素定位。

3. ID

HTML上某元素指定的id="ooo"

4. ClassName

HTML上某元素含有的class="aaa bbb ccc"

先來安裝尋找XPATH的Chrome小工具: ChroPath

ChroPath

第二個工具是ChroPath,同樣加入擴充套件並將它釘選起來

https://chrome.google.com/webstore/detail/chropath/ljngjbnaijcbncmcnjfhigebomdlkcjo?hl=zh-TW

重新啟動瀏覽器後,在網頁上開啟開發人員工具(f12)

Elements頁籤下,中間會有Styles、Computed等的選單,按下「>>」即可找到ChroPath

接著網頁上無論是透過開發人員工具或者滑鼠右鍵 >> 檢查,都可以找到該元素在ChroPath上的Rel XPATH(Relative相對位置)以及Abs XPATH(Absolute絕對位置)。

這能補足RUTO找不到完整XPATH時的缺陷


開始撰寫第一個測試腳本

測試目標:打開Youtube搜尋hololive的虛擬主播節目

1. 建立新檔案

在D槽建立一個目錄,命名為auto_test

打開VSCODE,選取左上檔案圖示後點選Open Folder

在左側的檔案列表最上面,按下新增圖示,並將檔名命名為firstCase.py

2. 引入常用WebDriver API

from selenium import webdriver ## BY: 也就是依照條件尋找元素中XPATH、CLASS NAME、ID、CSS選擇器等都會用到的Library from selenium.webdriver.common.by import By ## keys: 鍵盤相關的Library from selenium.webdriver.common.keys import Keys ## Select: 下拉選單相關支援,但前端框架UI工具不適用(ex: Quasar、ElementUI、Bootstrap) from selenium.webdriver.support.ui import Select ## WebDriverWait: 等待頁面加載完成的顯性等待機制Library from selenium.webdriver.support.ui import WebDriverWait ## ActionChains: 滑鼠事件相關 from selenium.webdriver.common.action_chains import ActionChains ## expected_conditions: 條件相關 from selenium.webdriver.support import expected_conditions as EC ## BeautifulReport: 產生自動測試報告套件 from BeautifulReport import BeautifulReport ## Chrome WebDriver 需要DRIVER Manager的支援 from webdriver_manager.chrome import ChromeDriverManager ## 延遲時間相關 import time ## 單元測試模組,線性測試用不到 import unittest

ActionChain API 內容

點擊滑鼠右鍵: context_click()
雙擊滑鼠左鍵: double_click()
按著滑鼠左鍵不放: click_and_hold()
放開滑鼠左鍵: release()
拖曳到某個元素後放開: drag_and_drop(source, target)
拖曳到某個座標後放開: drag_and_drop_by_offset(source, xoffset, yoffset)
按下鍵盤上某個按鍵: key_down(value)
放開鍵盤上某個按鍵: key_up(value)
滑鼠指標從當前位置移動到某個座標: move_by_offset(xoffset, yoffset)
滑鼠指標移動到某個元素: move_to_element(to_element)
移動到某元素附近座標位置: move_to_element_with_offset(to_element, xoffset, yoffset)
執行當前這個ActionChain的動作: perform()
在元素上輸入值(ex:input): send_keys(value)
在指定的元素上輸入值: send_keys_to_element(element, value)

##剛才IMPORT的部分(省略)### ### ## 設定Chrome的瀏覽器彈出時遵照的規則 ## 這串設定是防止瀏覽器上頭顯示「Chrome正受自動控制」 options = webdriver.ChromeOptions() options.add_experimental_option("excludeSwitches", ["enable-automation"]) options.add_experimental_option('useAutomationExtension', False) ## 關閉自動記住密碼的提示彈窗 options.add_experimental_option("prefs", { "profile.password_manager_enabled": False, "credentials_enable_service": False})

接下來是測試腳本的內容,我們要將腳本定義完成這些動作需要幾個Case。

    1. 前往Youtube網站後,搜尋Gura的影片,關鍵字「Gawr Gura 熟肉」
    1. 在搜尋結果找到特定的影片並點進去
    1. 回上頁列表,重新整理網頁後,切換另一則影片,五秒後回到首頁
## 剛才import進來的東西與基本設定,省略 #### ## 我們如果要將CASE拆成幾個不同的方法,需要用一個Unitest Class包覆起來 ## 然後加上修飾符@classmethod class Test(unittest.TestCase): @classmethod ## setUpClass這邊的設定是,可以讓所有Case進行過程中只開啟一次瀏覽器 ## 執行時會依照這個順序循環一次 setUpClass > test > teardown ## self則是作為我們的區域參數來定義作用域 def setUpClass(self): ## 定義WebDriver以及ActionsChain的變數便於後頭應用 self.driver = webdriver.Chrome(chrome_options=options) self.action = ActionChains(self.driver) ## 開啟Chrome新視窗,前往Youtube網址並最大化視窗 self.URL = "https://youtube.com" self.driver.get(self.URL) self.driver.maximize_window() @classmethod def tearDownClass(self): ## 所有case跑完後就退出瀏覽器 self.driver.quit() ## Test Case 的命名方式務必以「test_01_* ~ test_99_*」為主,讓爬蟲依照順序走 ## """裡面的註解就是報表產生後的CASE描述文字。 ## time.sleep(number)數字代表一秒 def test_01_search(self): """ 前往Youtube網站後,搜尋Gura的影片 """ time.sleep(2) ## 等待頁面中的HTML,ID = 'search'這個元素出現後才執行動作 try: element = WebDriverWait(self.driver, 10).until( EC.presence_of_element_located((By.XPATH, "//input[@id='search']")) ) finally: time.sleep(2) ## 找到搜尋框的XPATH並且輸入'Gawr Gura 熟肉' 熟肉就是經過別人得到版權方同意,翻譯上傳過後的剪輯 ## 寫法上也通driver.find_element(By.XPATH, '//xxx') input_search = self.driver.find_element_by_xpath("//input[@id='search']") input_search.send_keys("Gawr Gura 熟肉") ## 找到搜尋按鈕後按下 button_search = self.driver.find_element_by_id("search-icon-legacy") button_search.click() def test_02_open_target(self): """ 在搜尋結果找到特定的影片並點進去 """ time.sleep(5) ## 滾動網頁往下拉 self.driver.execute_script("window.scrollBy(0,1200)") time.sleep(2) ## 隨便找一個影片的連結,利用XPATH找路徑 youtube_target = self.driver.find_element_by_xpath("//a[@href='/watch?v=9SfsF_6fY9c']") youtube_target.click() time.sleep(5) def test_03_back_to_list(self): """ 回上頁列表,重新整理網頁後,切換另一則影片,五秒後回到首頁 """ self.driver.back() time.sleep(2) self.driver.refresh() time.sleep(3) ## 注意,youtube可能因為你所在位置而針對搜尋結果作排序 ## 如果你發現突然跳出case導致失敗,很有可能是因為搜尋列表找不到影片 ## 將影片的 /watch?v=xxxxx替換成該搜尋結果中的任一連結即可 youtube_target = self.driver.find_element_by_xpath("//a[@href='/watch?v=MhVh01k_Wg0']") youtube_target.click() time.sleep(5) logo = self.driver.find_element_by_id("logo-icon") logo.click() time.sleep(5)

程式碼的尾端我們在這將產生測試報告的設定做好:

## 剛剛寫腳本的區域,省略 ### # basedir就是存放所有TEST Case的目錄,讓它爬 pattern = '*.py',所以要做哪個類別的測試就指定哪個前贅 # 路徑盡量放D槽喔,除非你的電腦只有C basedir = "D:/auto_test/" if __name__ == '__main__': # 取得資料夾目錄底下,符合後面任何副檔名為.py,並進行所有test的測試項目 test_suite = unittest.defaultTestLoader.discover( basedir, pattern='*.py') # 測試結果加入到 BeautifulReport 套件內 result = BeautifulReport(test_suite) # 結果產生Report 檔案名稱為 filename, 敘述為 description, log_path 預設放在跟目錄底下就行 result.report(filename='report', description='我的第一個測試', log_path='D:/auto_test/') # 啟動自動化指令,在終端機輸入: & C:/Users/你的使用者帳號/AppData/Local/Programs/Python/Python39/python.exe d:/auto_test/firstCase.py

完整CODE範例

跑自動測試的終端機啟動指令:

& C:/Users/你的使用者名稱/AppData/Local/Programs/Python/Python39/python.exe d:/auto_test/firstCase.py

執行自動化測試的這段時間你可以選擇從頭看到尾,也可以丟著讓他跑完等報告就好。

from selenium import webdriver from selenium.webdriver.common.by import By from selenium.webdriver.common.keys import Keys from selenium.webdriver.support.ui import Select from selenium.webdriver.support.ui import WebDriverWait from selenium.webdriver.common.action_chains import ActionChains from selenium.webdriver.support import expected_conditions as EC from BeautifulReport import BeautifulReport from webdriver_manager.chrome import ChromeDriverManager import time import unittest options = webdriver.ChromeOptions() options.add_experimental_option("excludeSwitches", ["enable-automation"]) options.add_experimental_option('useAutomationExtension', False) options.add_experimental_option("prefs", { "profile.password_manager_enabled": False, "credentials_enable_service": False }) class Test(unittest.TestCase): @classmethod def setUpClass(self): self.driver = webdriver.Chrome(chrome_options=options) self.action = ActionChains(self.driver) self.URL = "https://youtube.com" self.driver.get(self.URL) self.driver.maximize_window() @classmethod def tearDownClass(self): self.driver.quit() def test_01_search(self): """ 前往Youtube網站後,搜尋Gura的影片 """ time.sleep(2) try: element = WebDriverWait(self.driver, 10).until( EC.presence_of_element_located((By.XPATH, "//input[@id='search']")) ) finally: time.sleep(2) input_search = self.driver.find_element_by_xpath("//input[@id='search']") input_search.send_keys("Gawr Gura 熟肉") button_search = self.driver.find_element_by_id("search-icon-legacy") button_search.click() def test_02_open_target(self): """ 在搜尋結果找到特定的影片並點進去 """ time.sleep(5) self.driver.execute_script("window.scrollBy(0,1200)") time.sleep(2) youtube_target = self.driver.find_element_by_xpath("//a[@href='/watch?v=9SfsF_6fY9c']") youtube_target.click() time.sleep(5) def test_03_back_to_list(self): """ 回上頁列表,重新整理網頁後,切換另一則影片,五秒後回到首頁 """ self.driver.back() time.sleep(2) self.driver.refresh() time.sleep(3) youtube_target = self.driver.find_element_by_xpath("//a[@href='/watch?v=MhVh01k_Wg0']") youtube_target.click() time.sleep(5) logo = self.driver.find_element_by_id("logo-icon") logo.click() time.sleep(5) basedir = "D:/auto_test/" if __name__ == '__main__': test_suite = unittest.defaultTestLoader.discover(basedir, pattern='*.py') result = BeautifulReport(test_suite) result.report(filename='report',description='我的第一個測試', log_path='D:/auto_test/')

如果你有檢查資料正確與否的需求
def 方法下面可以加上 assert 判別結果是否符合測試例子

def test_01_new_test(self): """ 斷言例子 """ test_val = "亂叫的小鯊魚" ## ...一些事件後 target_text = self.driver.find_element_by_xpath("任何你找到的位置").text ## assert 就是在驗證結果的布林值,沒事不建議直接讓他 = true/false assert target_text = test_val time.sleep(5)

順利的話報告會產生在D:/auto_test下,名稱是report.html

可以打開來看看,到這步驟就結束囉!

tags: Python Selenium