iT邦幫忙

2023 iThome 鐵人賽

DAY 27
0
Software Development

跟著 OXXO 一起學 Python系列 第 56

( Day 27.1 ) Python Selenium 函式庫

  • 分享至 

  • xImage
  •  

elenium 函式庫 ( 模組 ) 是使用 Python 進行網路爬蟲時,必備的函式庫之一,透過 selenium 可以模擬出使用者在瀏覽器的所有操作行為 ( 點擊按鈕、輸入帳號密碼、捲動捲軸...等 ),因此除了爬蟲的應用,也常作為「自動化測試」使用的工具,在網站開發完成後,透過自動化的腳本測試所有功能是否正常,這篇教學將會介紹 selenium 函式庫的常見用法,更多用法可前往閱讀 selenium 官方文件。

原文參考:Selenium 函式庫

執行 selenium 會啟動 chromedriver,所以所以請使用本機環境 ( 參考:使用 Python 虛擬環境 ) 或使用 Anaconda Jupyter 進行實作 ( 參考:使用 Anaconda ) 。

安裝 selenium 模組

在本機環境輸入下列指令,就能安裝 selenium 函式庫 ( 依據每個人的作業環境不同,可使用 pip 或 pip3 或 pipenv,Anaconda Jupyter 的安裝指令為 !pip )。

pip install selenium

什麼是 Selenium WebDriver

WebDriver 是用來執行並操作瀏覽器的 API 介面,每一個瀏覽器都會有各自對應的驅動程式 ( driver ),Selenium 會透過 WebDriver 來直接對瀏覽器進行操作,將所支援的瀏覽器進行自動化作業,就如同真的使用者在操作

下載 WebDriver

不同的瀏覽器會對應不同的 driver,以下提供幾種常見的 driver ( 本篇範例使用的是 Chrome ):

下載 Chrome driver 時請,必須下載對應的 Chrome 的版本,點擊右上角選單「說明 > 關於 Google Chrome」,可以查看版本。

Python 教學 - Selenium 函式庫

下載後將 driver 與執行的 Python 檔案放在同一個目錄下,就比較不需要煩惱執行時路徑的問題。

Python 教學 - Selenium 函式庫

import selenium

要使用 requests 必須先 import selenium 模組,啟用 webdriver 的功能。

from selenium import webdriver

使用 WebDriver 開啟第一個網頁

selenium 與 driver 都安裝與準備好之後,下方的程式碼執行後,會打開一個新的 Chrome 視窗,裡面出現指定的 Google 網頁,此時這個新的 Chrome 視窗會標明「受到自動測試軟體控制」,表示程式正在控制相關的操作。

webdriver.Chrome(路徑) 使用相對路徑 chromedriver 和執行的程式位在同一層。

from selenium import webdriver
driver = webdriver.Chrome('./chromedriver')    # 指向 chromedriver 的位置
driver.get('https://www.google.com')           # 打開瀏覽器,開啟網頁

Python 教學 - Selenium 函式庫

取得網頁元素

要模擬真人操作網頁的第一步,就是要知道觸碰了哪些網頁元素,首先載入 selenium 的 By 模組,接著就能使用 find_element() 搭配參數設定,取得指定的網頁元素,下方列出 find_element() 常用參數設定 ( 如果將方法的 element 改為 elements,會以串列方式回傳找到的元素 ):

新版本 selenium 取得元素的方法有所變更,本文也一併更新,詳細的方法參考:selenium.webdriver.remote.webelement

參數 說明
By.ID, id 透過 id,尋找第一個相符的網頁元素。
By.CLASS_NAME, class 透過 class,尋找第一個相符的網頁元素。
By.CSS_SELECTOR, css selector 透過 css 選擇器,尋找第一個相符的網頁元素。
By.NAME, name 透過 name 屬性,尋找第一個相符的網頁元素。
By.TAG_NAME, tag 透過 HTML tag,尋找第一個相符的網頁元素。
By.LINK_TEXT, text 透過超連結的文字,尋找第一個相符的網頁元素
By.PARTIAL_LINK_TEXT, text 透過超連結的部分文字,尋找第一個相符的網頁元素。
By.XPATH, xpath 透過 xpath 的方式,尋找第一個相符的網頁元素。

下方的程式會用 selenium 開啟範例網址 ( 網址連結 ),開啟後會用上述的方法,選取特定的網頁元素,接著套用點擊的方法,依序點擊各個按鈕,最後會連續打開兩次 Google 網站。

範例網址已經有做過點擊的處理,點擊按鈕或下拉選單切換時,上方空格會顯示對應的文字。

from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.select import Select   # 使用 Select 對應下拉選單
import time

driver = webdriver.Chrome('./chromedriver')
driver.get('https://example.oxxostudio.tw/python/selenium/demo.html')  # 開啟範例網址
a = driver.find_element(By.ID, 'a')                # 取得 id 為 a 的網頁元素 ( 按鈕 A )
b = driver.find_element(By.CLASS_NAME, 'btn')      # 取得 class 為 btn 的網頁元素 ( 按鈕 B )
c = driver.find_element(By.CSS_SELECTOR, '.test')  # 取得 class 為 test 的網頁元素 ( 按鈕 C )
d = driver.find_element(By.NAME, 'dog')            # 取得屬性 name 為 dog 的網頁元素 ( 按鈕 D )
h1 = driver.find_element(By.TAG_NAME, 'h1')        # 取得 tag h1 的網頁元素
link1 = driver.find_element(By.LINK_TEXT, '我是超連結,點擊會開啟 Google 網站')  # 取得指定超連結文字的網頁元素
link2 = driver.find_element(By.PARTIAL_LINK_TEXT, 'Google') # 取得超連結文字包含 Google 的網頁元素
select = Select(driver.find_element(By.XPATH, '/html/body/select'))   # 取得 html > body > select 這個網頁元素

a.click()        # 點擊 a
print(a.text)    # 印出 a 元素的內容
time.sleep(0.5)
b.click()        # 點擊 b
print(b.text)    # 印出 b 元素的內容
time.sleep(0.5)
c.click()        # 點擊 c
print(c.text)    # 印出 c 元素的內容
time.sleep(0.5)
d.click()        # 點擊 d
print(d.text)    # 印出 d 元素的內容
time.sleep(0.5)
select.select_by_index(2)  # 下拉選單選擇第三項 ( 第一項為 0 )
time.sleep(0.5)
h1.click()       # 點擊 h1
time.sleep(0.5)
link1.click()    # 點擊 link1
time.sleep(0.5)
link2.click()    # 點擊 link2
print(link2.get_attribute('href'))   # 印出 link2 元素的 href 屬性

Python 教學 - Selenium 函式庫

Python 教學 - Selenium 函式庫

操作網頁元素

使用 Selenium 函式庫操作網頁元素下列幾種方法:

方法 ActionChains 參數 說明
click() element 按下滑鼠左鍵。
click_and_hold() element 滑鼠左鍵按著不放。
double_click() element 連續按兩下滑鼠左鍵。
context_click() element 按下滑鼠右鍵 ( 需搭配指定元素定位 )。
drag_and_drop() source, target 點擊 source 元素後,移動到 target 元素放開。
drag_and_drop_by_offset() source, x, y 點擊 source 元素後,移動到指定的座標位置放開。
move_by_offset() x, y 移動滑鼠座標到指定位置。
move_to_element() element 移動滑鼠到某個元素上。
move_to_element_with_offset() element, x, y 移動滑鼠到某個元素的相對座標位置。
release() element 放開滑鼠。
send_keys() values 送出某個鍵盤按鍵值。
send_keys_to_element() element, values 向某個元素發送鍵盤按鍵值。
key_down() value 按著鍵盤某個鍵。
key_up() value 放開鍵盤某個鍵。
reset_actions() 清除儲存的動作 ( 實測沒有作用,查訊後是 Bug )。
pause() seconds 暫停動作。
perform() 執行儲存的動作。

要使用這些方法的方式有兩種,第一種就是「針對指定元素呼叫方法」,例如上方例子的 click() 方法,只要針對指定的元素,呼叫指定的方法,就會執行對應的動作,第二種是使用「ActionChains」,將所有需要執行的方法串成「鏈」,全部完成後執行 perform() 執行所有的過程

下方的程式使用「針對指定元素呼叫方法」。

from selenium import webdriver
from selenium.webdriver.common.by import By
from time import sleep

driver = webdriver.Chrome('./chromedriver')
driver.get('https://example.oxxostudio.tw/python/selenium/demo.html')
a = driver.find_element(By.ID, 'a')
add = driver.find_element(By.ID, 'add')
a.click()     # 點擊按鈕 A,出現 a 文字
sleep(1)
add.click()   # 點擊 add 按鈕,出現 數字 1
add.click()   # 點擊 add 按鈕,出現 數字 2
sleep(1)
add.click()   # 點擊 add 按鈕,出現 數字 3
sleep(1)
add.click()   # 點擊 add 按鈕,出現 數字 4

下方的程式使用「ActionChains」的方式,結果與上述的執行結果相同。

from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.common.action_chains import ActionChains

driver = webdriver.Chrome('./chromedriver')
driver.get('https://example.oxxostudio.tw/python/selenium/demo.html')
a = driver.find_element(By.ID, 'a')
add = driver.find_element(By.ID, 'add')
actions = ActionChains(driver)   # 使用 ActionChains 的方式
actions.click(a).pause(1)        # 點擊按鈕 A,出現 a 文字後,暫停一秒
actions.double_click(add).pause(1).click(add).pause(1).click(add)
# 連點 add 按鈕,等待一秒後再次點擊,等待一秒後再次點擊
actions.perform()  # 執行儲存的動作

Python 教學 - Selenium 函式庫

雖然「針對指定元素呼叫方法」看起來滿直覺,但相對來說能使用的方法有限 ( 只能使用 click、send_keys...等兩三種 ),使用「ActionChains」才能完整發揮所有的方法,下方的程式碼執行後,會自動在輸入框內輸入指定的文字。

from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.common.action_chains import ActionChains

driver = webdriver.Chrome('./chromedriver')
driver.get('https://example.oxxostudio.tw/python/selenium/demo.html')
a = driver.find_element(By.ID, 'a')
show = driver.find_element(By.ID, 'show')
actions = ActionChains(driver)
actions.click(show).send_keys(['1','2','3','4','5'])    # 輸入 1~5 的鍵盤值 ( 必須是字串 )
actions.pause(1)    # 等待一秒
actions.click(a)    # 點擊按鈕 A
actions.pause(1)    # 等待一秒
actions.send_keys_to_element(show, ['A','B','C','D','E'])   # # 輸入 A~E 的鍵盤值
actions.perform()   # 送出動作

Python 教學 - Selenium 函式庫

取得網頁元素的內容

Selenium 不僅能模擬真人去控制網頁元素,也可以取得網頁元素的相關內容,甚至進一步執行網頁截圖並儲存的功能,常用的內容如下:

內容 說明
text 元素的內容文字。
get_attribute 元素的某個 HTML 屬性值。
id 元素的 id。
tag_name 元素的 tag 名稱。
size 元素的長寬尺寸。
screenshot 將某個元素截圖並儲存為 png。
is_displayed() 元素是否顯示在網頁上。
is_enabled() 元素是否可用。
is_selected() 元素是否被選取。
parent 元素的父元素。

下方的程式碼執行後,會取得元素的 id、內容文字、tag 名稱、尺寸和屬性值,最後會將整張網頁截圖為 test.png。

from selenium import webdriver
from selenium.webdriver.common.by import By

driver = webdriver.Chrome('./chromedriver')
driver.get('https://example.oxxostudio.tw/python/selenium/demo.html')
body = driver.find_element(By.TAG_NAME, 'body')
a = driver.find_element(By.ID, 'a')
b = driver.find_element(By.CLASS_NAME, 'btn')
c = driver.find_element(By.CSS_SELECTOR, '.test')
d = driver.find_element(By.NAME, 'dog')
link1 = driver.find_element(By.LINK_TEXT, '我是超連結,點擊會開啟 Google 網站')
link2 = driver.find_element(By.PARTIAL_LINK_TEXT, 'Google')

print(a.id)
print(b.text)
print(c.tag_name)
print(d.size)
print(link1.get_attribute('href'))
print(link2.get_attribute('target'))
body.screenshot('./test.png')

Python 教學 - Selenium 函式庫

搭配 JavaScript,發揮最大效益

Selenium 除了內建的方法,也可以搭網頁的 JavaScript,發揮網頁控制的最大效益,下方的程式碼執行後,會先上下滾動網頁捲軸,接著彈出提示視窗,兩秒後再關閉提示視窗。

from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.common.alert import Alert
from time import sleep

driver = webdriver.Chrome('./chromedriver')
driver.get('https://www.selenium.dev/selenium/docs/api/py/webdriver_remote/selenium.webdriver.remote.webelement.html')

sleep(1)
driver.execute_script('window.scrollTo(0, 500)')   # 捲動到 500px 位置
sleep(1)
driver.execute_script('window.scrollTo(0, 2500)')  # 捲動到 2500px 位置
sleep(1)
driver.execute_script('window.scrollTo(0, 0)')     # 捲動到 0px 位置

h1 = driver.find_element(By.TAG_NAME, 'h1')
h3 = driver.find_element(By.TAG_NAME, 'h3')
script = '''
  let h1 = arguments[0];
  let h3 = arguments[1];
  alert(h1, h3)
'''
driver.execute_script(script, h1, h3)   # 執行 JavaScript,印出元素
sleep(2)
Alert(driver).accept()    # 點擊提示視窗的確認按鈕,關閉提示視窗

參考資料

Selenium 函式庫不僅能應用於自動化測試,對於爬蟲的應用而言也是必備的函式庫,下方列出 Selenium 的官方文件,如果要了解更詳細的資訊可以前往閱讀:

更多教學

大家好,我是 OXXO,是個即將邁入中年的斜槓青年,我有個超過一千篇教學的 STEAM 教育學習網,有興趣可以參考下方連結呦~ ^_^


上一篇
( Day 26.2 ) Python Beautiful Soup 函式庫
下一篇
( Day 27.2 ) Python 爬取 PTT 八卦版文章標題
系列文
跟著 OXXO 一起學 Python101
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

1 則留言

我要留言

立即登入留言