---
title: 'Python Selenium 教學筆記'
disqus: hackmd
---
Python Selenium with VSCODE 教學筆記
===
綱要
[TOC]
:::info
不知道為什麼這篇莫名其妙在Google搜尋「Selenium 教學」的排名特別前面...
來信問開課的人突然暴增,但目前沒有收費開課的打算,所以之後會找個時間把進階教學寫一寫,有更多對E2E自動化測試有興趣的人一起學習是好事。
:::
關於Chrome的Webdriver
===
:::info
如果你已經使用了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`
![](https://i.imgur.com/tPDBvuG.png)
記得在安裝畫面將`Add Python 3.9 to PATH`也勾選起來,便於之後安裝一些Package。
安裝好後如下所示,以「系統管理者身分」執行cmd
![](https://i.imgur.com/cAaOv1E.png)
接著在終端機上輸入`python`,看到這訊息代表Python安裝成功了。
![](https://i.imgur.com/7da4WBS.png)
由於部分使用者在執行Python指令時,WINDOWS會彈出線上商店的關係。
現在需要到WINDOWS的系統環境變數修改些路徑:
![](https://i.imgur.com/1S5Y6MD.png)
按下「編輯系統環境變數」後會看到這個畫面,再按「環境變數」
![](https://i.imgur.com/L97FDmk.png)
進入環境變數視窗後選擇「path」>> 「編輯」,檢查看看Python的安裝路徑。
確認Python是不是擺在「windowApps」之前。
如果不是,就用右邊的上移、下移按鈕處理後按下確定。
![](https://i.imgur.com/g7lGX5V.png)
假如你安裝Python時忘了把Add to path打勾
那就把這個路徑新增到系統變數 >> Path裡面去:
`C:\Users\你的電腦帳號\AppData\Local\Programs\Python\Python目前版本\Scripts`
![](https://i.imgur.com/8CYDhEO.png)
**權限問題排除**
:::info
若敲指令時發生「python 不是内部或外部命令」的錯誤訊息出現時。
我們需要調整一下Windows的PowerShell權限設定。
:::
在開始選單下的「Windows PowerShell」下,以系統管理員身分執行一次
![](https://i.imgur.com/uhOFSv9.png)
並且輸入指令:`Set-ExecutionPolicy RemoteSigned`
![](https://i.imgur.com/RrF9a6p.png)
輸入A選擇「全部皆是」,然後把VSCODE和終端機重開即可。
![](https://i.imgur.com/Pw9Lfhx.png)
### 二、安裝Selenium套件
然後繼續輸入指令`quit()`跳出剛才有`>>>`的Python指令區
現在輸入我們要安裝Selenium的指令 `pip install selenium`
出現`Successfully installed selenium` 的訊息即可。
![](https://i.imgur.com/ccuHtYz.png)
---
### 三、安裝 WebDriver
自動測試需要使用到瀏覽器行為的控制事件,所以我們要安裝相應的WebDriver以及版本。
如果你不清楚現在使用的Chrome版本,網址輸入`chrome://settings/help` 可以查看:
![](https://i.imgur.com/1qXplqR.png)
**下載 Chrome WebDriver**
https://chromedriver.chromium.org/downloads
:::info
如果有遇到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自動測試報告套件
![](https://i.imgur.com/q9ExpBM.png)
**下載並安裝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**
![](https://i.imgur.com/AyTdFXE.png)
解壓縮後將目錄名稱改為BeautifulReport
![](https://i.imgur.com/UIBlzN4.png)
點入BeautifulReport會看到這些檔案:
![](https://i.imgur.com/0UOUWt7.png)
回上一層,將整個BeautifulReport目錄複製到以下路徑即可:
`C:\Users\你的使用者名稱\AppData\Local\Programs\Python\Python39\Lib\site-packages\`
**安裝webdriver-manager**
接著回到終端機,我們需要webdriver manager的支援。
輸入指令:
`pip install webdriver-manager`
---
### 五、安裝VSCODE與IDE擴充套件
![](https://i.imgur.com/h4obXNA.png)
網址:https://code.visualstudio.com/
安裝成功後打開VSCODE,按一下左下的**Extensions**開啟擴充套件視窗,搜尋以下幾個套件:
**1. Pylance**
![](https://i.imgur.com/zQFsLEl.png)
微軟提供的語法智能輔助工具,包含語法檢查與Debugging。
**2. Path Intellisense**
![](https://i.imgur.com/VwZdqjj.png)
路徑選擇的輔助工具,當需要輸入來源程式碼、圖片、CSS等檔案時
依照輸入 `../` 或 `./` 的不同,自動會幫我們開啟相關目錄下拉視窗來選擇來源檔案。
---
## Mac OSX
### 安裝Home Brew(有裝過的話可以跳過)
```bash
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
```
### 使用Home Brew安裝Python 3
```bash
brew install python3
```
### 安裝pip 3套件管理工具
```bash
python3 get-pip.py
```
確認有正確安裝pip 3
```bash
pip3 --version
```
### 安裝Selenium 4.0
```bash
pip3 install selenium
```
### 安裝webdriver manager套件
```bash
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
解壓縮到:
```bash
/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**
![](https://i.imgur.com/w6PujRt.png)
第二個工具是**ChroPath**,同樣加入擴充套件並將它釘選起來
![](https://i.imgur.com/JHa9Hzx.png)
https://chrome.google.com/webstore/detail/chropath/ljngjbnaijcbncmcnjfhigebomdlkcjo?hl=zh-TW
重新啟動瀏覽器後,在網頁上開啟開發人員工具(f12)
![](https://i.imgur.com/PeB3Xhl.png)
在**Elements**頁籤下,中間會有Styles、Computed等的選單,按下「>>」即可找到**ChroPath**
![](https://i.imgur.com/wW6Dp2n.jpg)
接著網頁上無論是透過開發人員工具或者滑鼠右鍵 >> 檢查,都可以找到該元素在**ChroPath**上的Rel XPATH(Relative相對位置)以及Abs XPATH(Absolute絕對位置)。
![](https://i.imgur.com/6ceO6D4.png)
這能補足**RUTO**找不到完整XPATH時的缺陷
---
# 開始撰寫第一個測試腳本
==**測試目標:打開Youtube搜尋hololive的虛擬主播節目**==
**1. 建立新檔案**
在D槽建立一個目錄,命名為`auto_test`
打開VSCODE,選取左上檔案圖示後點選Open Folder
![](https://i.imgur.com/6VjC82M.png)
在左側的檔案列表最上面,按下新增圖示,並將檔名命名為`firstCase.py`
![](https://i.imgur.com/QM1gj7g.png)
**2. 引入常用WebDriver API**
```python=
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 內容**
:::info
點擊滑鼠右鍵: 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)
:::
```python=
##剛才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 熟肉」
- 2. 在搜尋結果找到特定的影片並點進去
- 3. 回上頁列表,重新整理網頁後,切換另一則影片,五秒後回到首頁
```python=
## 剛才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)
```
程式碼的尾端我們在這將產生測試報告的設定做好:
```python=
## 剛剛寫腳本的區域,省略
###
# 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`
執行自動化測試的這段時間你可以選擇從頭看到尾,也可以丟著讓他跑完等報告就好。
```python=
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/')
```
:::info
如果你有檢查資料正確與否的需求
def 方法下面可以加上 assert 判別結果是否符合測試例子
:::
```python=
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
可以打開來看看,到這步驟就結束囉!
![](https://i.imgur.com/6dLqnbH.png)
###### tags: `Python` `Selenium`