Web自動化測試--selenium

2023-09-13 12:02:08

一、selenium介紹

Selenium 是支援web瀏覽器自動化的一系列工具和庫的綜合專案,能夠進行自動化網頁瀏覽器操作,廣泛應用於測試和自動化行業。它可以模擬使用者在瀏覽器中執行的操作,如點選按鈕、填寫表單、導航到不同頁面等。Selenium 提供了一組強大的 API 和工具,使開發人員能夠以程式設計方式控制瀏覽器,從而實現自動化測試、網頁抓取和跨瀏覽器測試等任務。

官網:https://www.selenium.dev/zh-cn/documentation/

特點:

多語言支援:Selenium 提供了多種程式語言的 API,例如 Java、Python、C#、Ruby 等,使開發人員可以使用自己熟悉的語言編寫測試指令碼。
跨瀏覽器相容性:Selenium 支援各種流行的瀏覽器,包括Chrome、Firefox、Safari 和 Edge等,可以在不同瀏覽器上執行測試並驗證應用程式的一致性。
強大的定位機制:Selenium 提供了豐富的元素定位方法,如通過 ID、CSS、XPath 等定位方式,使得開發人員可以準確定位頁面上的元素並與之互動。
自動化與整合:Selenium 可以與常見的整合工具和測試框架(如 TestNG、JUnit、Cucumber 等)無縫整合,使得測試和自動化過程更加靈活高效。
支援分散式測試:Selenium Grid 允許在多臺計算機上並行執行測試,以加速測試執行和提高效率。
豐富的社群支援:Selenium 擁有龐大的開發者社群和活躍的維護者團隊,提供了豐富的檔案、教學和範例,方便開發人員學習和解決問題。

二、環境搭建

1、安裝 Selenium 庫

pip install selenium

2、獲取瀏覽器的驅動程式

1.1 檢視谷歌瀏覽器版本(以谷歌瀏覽器作為範例)
Chrome -> 右上角三個點-> 設定 -> 關於Google Chrome

1.2 下載對應版本的chromedriver
谷歌瀏覽器chromedriver:https://registry.npmmirror.com/binary.html?path=chromedriver/

3 設定 ChromeDriver 路徑

下載解壓後得到 chromedriver.exe,將其放入 Python 安裝路徑下的 Scripts 目錄

4 編寫 Selenium 指令碼驗證安裝

新建python檔案,命名open-web.py,使用 ChromeDriver 建立一個 Chrome 瀏覽器範例,開啟 "https://www.example.com" 網頁並最後關閉瀏覽器

from selenium import webdriver

# 建立 ChromeDriver 範例
driver = webdriver.Chrome()
# 開啟網頁,填寫你需要的網站
driver.get("https://www.example.com")
# 執行其他操作
# ...
# 關閉瀏覽器0...........
driver.quit()

三、基本組成

1. 使用驅動範例開啟對談

from selenium import webdriver
driver = webdriver.Chrome()

2. 在瀏覽器上執行操作

導航到網頁

driver.get("https://www.selenium.dev/selenium/web/web-form.html")

3. 請求瀏覽器資訊

請求一系列關於瀏覽器的資訊, 包括視窗控制程式碼、瀏覽器尺寸/位置、cookie、警報等

title = driver.title

4. 建立等待策略

等待一段時間使元素處於可互動狀態

driver.implicitly_wait(0.5)
time.sleep(0.5)

5. 傳送命令查詢元素

text_box = driver.find_element(by=By.NAME, value="my-text")
submit_button = driver.find_element(by=By.CSS_SELECTOR, value="button")

6. 操作元素

text_box.send_keys("Selenium")
submit_button.click()

7. 獲取元素資訊

value = message.text

8. 結束對談

driver.quit()

四、元素

1.查詢

根據提供的定位值定位元素.

#評估DOM元素,查詢匹配的第一個元素
driver.find_element(By.CLASS_NAME, "tomatoes")

#評估DOM子集,縮小範圍,通過父元素定位子元素
fruits = driver.find_element(By.ID, "fruits")
fruit = fruits.find_element(By.CLASS_NAME,"tomatoes")

#使用 CSS 或 XPath 在單個命令中找到此元素
fruit = driver.find_element(By.CSS_SELECTOR,"#fruits .tomatoes")

#獲取所有匹配元素
plants = driver.find_elements(By.TAG_NAME, "li")

#迴圈存取集合並確定所需的集合
elements = driver.find_elements(By.TAG_NAME, 'p')
for e in elements:
    print(e.text)
 

2. 定位器

在DOM中標識一個或多個特定元素的方法
新版本:

名稱 含義 定位元素
類名 定位class屬性與搜尋值匹配的元素(不允許使用複合類名) By.ID
CSS 選擇器 定位 CSS 選擇器匹配的元素 By.XPATH
編號 定位 id 屬性與搜尋值匹配的元素 By.LINK_TEXT
名字 定位 name 屬性與搜尋值匹配的元素 By.PARTIAL_LINK_TEXT
連結文字 定位link text可視文字與搜尋值完全匹配的錨元素 By.NAME
部分連結文字 定位link text可視文字部分與搜尋值部分匹配的錨點元素。 如果匹配多個元素,則只選擇第一個元素。 By.TAG_NAME
標籤名稱 定位標籤名稱與搜尋值匹配的元素 By.CLASS_NAME
xpath 定位與 XPath 表示式匹配的元素 By.CSS_SELECTOR

例:
單個元素:driver.find_element(By.CSS_SELECTOR, "#fname")
多個元素:driver.find_elements(By.CSS_SELECTOR, "#fname")

舊版本:

定位元素 含義
find_element_by_id 通過元素 id 進行定位
find_element_by_name 通過元素名稱進行定位
find_element_by_xpath 通過 xpath 表示式進行定位
find_element_by_link_text 通過完整超連結文字進行定位
find_element_by_partial_link_text 通過部分超連結文字進行定位
find_element_by_tag_name 通過標記名稱進行定位
find_element_by_class_name 通過類名進行定位
find_element_by_css_selector 通過 css 選擇器進行定位

例:
單個元素:driver.find_element_by_id('username')
多個元素:driver.find_elements_by_id('username')

3. 資訊

3.1 是否顯示

是否正確顯示在網頁上. 返回一個 Boolean 值, 如果連線的元素顯示在當前的瀏覽器上下文中,則為True,否則返回false
is_email_visible = driver.find_element(By.NAME, "email_input").is_displayed()

3.2 是否啟用

檢查所連線的元素在網頁上是啟用還是禁用狀態。 返回一個布林值,如果在當前瀏覽上下文中是啟用狀態,則返回 true,否則返回 false。
value = driver.find_element(By.NAME, 'button_input').is_enabled()

3.3 是否被選定

此方法確認相關的元素是否已選定,常用於核取方塊、單選框、輸入框和選擇元素中。
該方法返回一個布林值,如果在當前瀏覽上下文中 選擇了 參照的元素,則返回 True,否則返回 False。
value = driver.find_element(By.NAME, "checkbox_input").is_selected()

3.4 獲取元素標籤名

此方法用於獲取在當前瀏覽上下文中具有焦點的被參照元素的TagName。
attr = driver.find_element(By.NAME, "email_input").tag_name

3.5 位置和大小

用於獲取參照元素的尺寸和座標。
提取的資料主體包含以下詳細資訊:

元素左上角的X軸位置
元素左上角的y軸位置
元素的高度
元素的寬度

res = driver.find_element(By.NAME, "range_input").rect

3.6 獲取元素CSS值

獲取當前瀏覽上下文中元素的特定計算樣式屬性的值。
cssValue = driver.find_element(By.ID, "namedColor").value_of_css_property('background-color')

3.7 文字內容

獲取特定元素渲染後的文字內容。
text = driver.find_element(By.ID, "justanotherlink").text

3.8 獲取特性或屬性

獲取與 DOM 屬性關聯的執行時的值。 它返回與該元素的 DOM 特性或屬性關聯的資料。

email_txt = driver.find_element(By.NAME, "email_input")
value_info = email_txt.get_attribute("value")

#獲取連結
例:article.find_elements_by_xpath("/a")[j].get_attribute('href') 

五、互動

1. 元素互動

1.1 點選

元素點選命令執行在元素中央。如果元素中央由於某些原因被遮擋 , Selenium將返回一個元素點選中斷錯誤。
driver.find_element(By.NAME, "input").click()

1.2 傳送鍵位

元素傳送鍵位命令將錄入提供的鍵位到編輯的元素。通常, 這意味著元素是具有文字型別的表單的輸入元素或具有內容可編輯屬性的元素. 如果不可編輯, 則返回無效元素狀態錯誤。
driver.find_element(By.NAME, "email_input").send_keys("abc")

1.3 清除

元素清除命令重置元素的內容. 這要求元素可編輯, 且可重置。 通常, 這意味著元素是具有文 型別的表單的輸入元素或具有內容可編輯屬性的元素. 如果不滿足這些條件, 將返回無效元素狀態錯誤.
driver.find_element(By.NAME, "email_input").clear()

2. 瀏覽器互動(獲取瀏覽器資訊)

2.1 獲取標題

driver.title

2.2 獲取當前url

driver.current_url

3. 瀏覽器導航

3.1 開啟網站

driver.get("https://selenium.dev")

3.2 後退

driver.back()

3.3 前進

driver.forward()

3.4 重新整理

driver.refresh()

4. 彈窗

4.1 Alerts 警告框

它顯示一條自定義訊息, 以及一個用於關閉該警告的按鈕, 在大多數瀏覽器中標記為"確定"(OK). 在大多數瀏覽器中, 也可以通過按"關閉"(close)按鈕將其關閉, 但這始終與「確定」按鈕具有相同的作用

# 匯入所需的模組和類
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
# 範例化瀏覽器驅動
driver = webdriver.Chrome()
# 點選連結以啟用彈窗
driver.find_element(By.LINK_TEXT, "See an example alert").click()
# 等待彈窗顯示並將其儲存在變數中
wait = WebDriverWait(driver, 10)
alert = wait.until(EC.alert_is_present())
# 將彈窗文字儲存在變數中
text = alert.text
# 點選確定按鈕
alert.accept()
#點選取消按鈕
alert.dismiss()

4.2 Confirm 確認框

確認框類似於警告框, 不同之處在於使用者還可以選擇取消訊息

# 點選連結以啟用確認框
driver.find_element(By.LINK_TEXT, "See a sample confirm").click()
# 等待確認框的出現,expected_conditions重新命名為EC
wait = WebDriverWait(driver, 10)
wait.until(EC.alert_is_present())
# 將確認框儲存在變數中以便複用
alert = driver.switch_to.alert
# 將確認框文字儲存在變數中
text = alert.text
# 點選取消按鈕
alert.dismiss()

4.3 Prompt 提示框

提示框與確認框相似, 不同之處在於它們還包括文字輸入. 與處理表單元素類似, 您可以使用WebDriver的sendKeys來填寫響應. 這將完全替換預留位置文字. 按下取消按鈕將不會提交任何文字

# 等待提示框的出現
wait = WebDriverWait(driver, 10)
wait.until(EC.alert_is_present())
# 將提示框儲存在變數中以便複用
alert = Alert(driver)
# 輸入訊息
alert.send_keys("Selenium")
# 點選確定按鈕
alert.accept()

5. 視窗和分頁

5.1 獲取視窗控制程式碼

WebDriver 沒有區分視窗和分頁。如果你的站點開啟了一個新分頁或視窗,Selenium 將允許您使用視窗控制程式碼來處理它。 每個視窗都有一個唯一的識別符號,該識別符號在單個對談中保持永續性。你可以使用以下方法獲得當前視窗的視窗控制程式碼
driver.current_window_handle

5.2 切換視窗或分頁

單擊在 <a href=「https://seleniumhq.github.io"target="_blank」>新視窗 中開啟連結, 則螢幕會聚焦在新視窗或新分頁上,但 WebDriver 不知道作業系統認為哪個視窗是活動的。 要使用新視窗,您需要切換到它。 如果只有兩個索引標籤或視窗被開啟,並且你知道從哪個視窗開始, 則你可以遍歷 WebDriver, 通過排除法可以看到兩個視窗或索引標籤,然後切換到你需要的視窗或索引標籤。

# 儲存原始視窗的 ID
original_window = driver.current_window_handle
# 檢查一下,我們還沒有開啟其他的視窗
assert len(driver.window_handles) == 1
# 單擊在新視窗中開啟的連結
driver.find_element(By.LINK_TEXT, "new window").click()
# 等待新視窗或分頁
wait.until(EC.number_of_windows_to_be(2))
# 迴圈執行,直到找到一個新的視窗控制程式碼
for window_handle in driver.window_handles:
    if window_handle != original_window:
        driver.switch_to.window(window_handle)
        break
# 等待新分頁完成載入內容
  wait.until(EC.title_is("xxxx"))

5.3 建立新視窗或新分頁並且切換

建立一個新視窗 (或) 分頁,螢幕焦點將聚焦在新視窗或標籤在上。您不需要切換到新視窗 (或) 分頁。如果除了新視窗之外, 您開啟了兩個以上的視窗 (或) 分頁,您可以通過遍歷 WebDriver 看到兩個視窗或索引標籤,並切換到非原始視窗。

# 開啟新分頁並切換到新分頁
driver.switch_to.new_window('tab')
# 開啟一個新視窗並切換到新視窗
driver.switch_to.new_window('window')

5.4 關閉視窗或分頁

#關閉分頁或視窗
driver.close()
#切回到之前的分頁或視窗
driver.switch_to.window(original_window)

5.5 在對談結束時退出瀏覽器

完成了瀏覽器對談,應該呼叫 quit 退出,而不是 close 關閉
driver.quit()
退出將會:

  • 關閉所有與 WebDriver 對談相關的視窗和索引標籤
  • 結束瀏覽器程序
  • 結束後臺驅動程序
  • 通知 Selenium Grid 瀏覽器不再使用,以便可以由另一個對談使用它(如果您正在使用 Selenium Grid)

5.6 獲取視窗大小

# 分別獲取每個尺寸
width = driver.get_window_size().get("width")
height = driver.get_window_size().get("height")
# 或者儲存尺寸並在以後查詢它們
size = driver.get_window_size()
width1 = size.get("width")
height1 = size.get("height")

5.7 設定視窗大小

driver.set_window_size(1024, 768)

5.8 視窗位置

# 分別獲取每個尺寸
x = driver.get_window_position().get('x')
y = driver.get_window_position().get('y')

# 或者儲存尺寸並在以後查詢它們
position = driver.get_window_position()
x1 = position.get('x')
y1 = position.get('y')

5.9 設定視窗位置

# 將視窗移動到主顯示器的左上角
driver.set_window_position(0, 0)

5.10 最大化視窗

driver.maximize_window()

5.11 最小化視窗

driver.minimize_window()

5.12 全螢幕視窗

填充整個螢幕,類似於在大多數瀏覽器中按下 F11
driver.fullscreen_window()

5.12 螢幕截圖

用於捕獲當前瀏覽上下文的螢幕截圖. WebDriver端點螢幕截圖 返回以Base64格式編碼的螢幕截圖
driver.save_screenshot('./image.png')

5.13 元素螢幕截圖

ele = driver.find_element(By.CSS_SELECTOR, 'h1')
ele.screenshot('./image.png')

5.14 執行指令碼

在當前frame或者視窗的上下文中,執行JavaScript程式碼片段

# 儲存標題元素
header = driver.find_element(By.CSS_SELECTOR, "h1")
# 執行 JavaScript 程式碼以捕獲標題元素的 innerText
inner_text = driver.execute_script('return arguments[0].innerText', header)
# 執行JavaScript程式碼,將頁面捲動到底部
js = "window.scrollTo(0, document.body.scrollHeight);"
driver.execute_script(js)

5.15 列印頁面

from selenium.webdriver.common.print_page_options import PrintOptions
# 範例化列印選項物件
print_options = PrintOptions()
print_options.page_ranges = ['1-2']
# 開啟列印頁的網址
driver.get("printPage.html")
# 執行列印操作,並獲取列印後的頁面內容的 Base64 編碼
base64code = driver.print_page(print_options)

6 Cookies

Cookie是從網站傳送並儲存在您的計算機中的一小段資料. Cookies主要用於識別使用者並載入儲存的資訊。

這個方法常常用於將cookie新增到當前存取的上下文中. 新增Cookie僅接受一組已定義的可序列化JSON物件. 這裡是一個連結, 用於描述可接受的JSON鍵值的列表
首先, 您需要位於有效Cookie的域上. 如果您在開始與網站進行互動之前嘗試預設cookie, 並且您的首頁很大或需要一段時間才能載入完畢, 則可以選擇在網站上找到一個較小的頁面 (通常404頁很小, 例如 http://example.com/some404page)
將 Cookie 新增到當前瀏覽器上下文中
driver.add_cookie({"name": "key", "value": "value"})

此方法返回與cookie名稱匹配的序列化cookie資料中所有關聯的cookie.

# 將 Cookie 新增到當前瀏覽器上下文中
driver.add_cookie({"name": "key", "value": "value"})
# 使用命名的 cookie 'key' 獲取 cookie 詳細資訊
print(driver.get_cookie("key"))

6.3 獲取全部 Cookies

driver.get_cookies()

driver.delete_cookie("key")

6.5 刪除所有 Cookies

driver.delete_all_cookies()

6.6 Same-Site Cookie屬性

此屬性允許使用者引導瀏覽器控制cookie, 是否與第三方站點發起的請求一起傳送. 引入其是為了防止CSRF(跨站請求偽造)攻擊.
Same-Site cookie屬性接受以下兩種引數作為指令

  • Strict:當sameSite屬性設定為 Strict, cookie不會與來自第三方網站的請求一起傳送.
  • Lax:將cookie sameSite屬性設定為 Lax, cookie將與第三方網站發起的GET請求一起傳送.
driver.add_cookie({"name": "key", "value": "value", 'sameSite': 'Strict'})
driver.add_cookie({"name": "key1", "value": "value", 'sameSite': 'Lax'})

7. IFrames和Frame

遇到巢狀的 iframe(內聯框架),需要定位和切換到 iframe

7.1 使用 WebElement切換

iframe_element = driver.find_element_by_xpath("//iframe[@id='iframe_id']")
driver.switch_to.frame(iframe_element)

7.2 使用 name 或 id切換

# 通過 id 切換框架
driver.switch_to.frame('buttonframe')

7.3 使用索引切換

# 基於索引切換到第 2 個 iframe
iframe = driver.find_elements(By.TAG_NAME,'iframe')[1]
# 切換到選擇的 iframe
driver.switch_to.frame(iframe)

7.4 切回主檔案

完成 iframe 內的操作後,可以使用該方法將焦點切回到主檔案。這將恢復驅動器的預設上下文,使後續的操作在主檔案中進行
driver.switch_to.default_content()

六、等待

我們在做WEB自動化時,一般要等待頁面元素載入完成後,才能執行操作,否則會報錯找不到元素的錯誤
三種等待方式:

  • 隱式等待
  • 顯示等待
  • 強制等待

1. 隱式等待

Selenium有一種內建的方式來自動等待稱為隱式等待的元素。 可以使用瀏覽器選項中的超時功能或使用驅動程式方法(如下所示)設定隱式等待值。
這是一個全域性設定,適用於整個對談的每個元素位置呼叫。 預設值為 ,這意味著如果未找到該元素,它將 立即返回錯誤。如果設定了隱式等待,驅動程式將等待 返回錯誤之前所提供值的持續時間。請注意,只要元素定位,驅動程式將返回元素參照,程式碼將繼續執行, 因此,較大的隱式等待值不一定會增加對談的持續時間。缺點:有時需要的元素早已載入完成,個別元素載入慢,仍要等待頁面全部載入完成才能執行下一步。
警告:不要混合隱式和顯式等待。 這樣做可能會導致不可預測的等待時間。 例如,將隱式等待設定為 10 秒 並顯式等待 15 秒 可能會導致 20 秒後發生超時
driver.implicitly_wait(2)

2. 顯式等待

顯式等待是一種條件觸發式的等待方式,指定某一條件直到這個條件成立時才會繼續執行,可以設定超時時間,如果超過這個時間元素依然沒被載入,就會丟擲異常。
element = WebDriverWait(driver, 10).until(EC.presence_of_element_located((By.XPATH, "//div//input"))
或者例下:

revealed = driver.find_element(By.ID, "revealed")
wait = WebDriverWait(driver, timeout=2)
driver.find_element(By.ID, "reveal").click()
wait.until(lambda d : revealed.is_displayed())
revealed.send_keys("Displayed")

3. 強制等待

利用time模組的sleep方法來實現,使程式等待一段時間
time.sleep(time)

4. 其他

Selenium提供了一些內建的用於顯式等待的方法,位於expected_conditions類中,方法名稱如表所示:

內建方法 功能
title_is 判斷當前頁面的title 是否等於預期內容
title_contains 判斷當前頁面的 title 是否包含預期字串
presence_of_element_located 判斷某個元素是否被加到了 dom 樹裡,並不代表該元素一定可見
visibility_of_element_located 判斷某個元素是否可見
visibility_of 判斷某個元素是否可見
presence_of_all_elements_located 判斷是否至少有 1個元素存在於 dom 樹中
text_to_be_present_in_element 判斷某個元素中的 text 是否包含了預期的字串
text_to_be_present_in_element_value 判斷某個元素中的 value 屬性是否包含了預期的字串
frame tobe availableand switch toit 判斷該 frame 是否可以切換進去,如果可以的話,返回 True並且切換進去,否則返回 False
invisibility_of_element_located 判斷某個元素中是否不存在於 dom 樹或不可見
element_tobeclickable 判斷某個元素中是否可見並且是 enable 的
stalenessof 等待某個元素從 dom樹中移除
element_tobeselected 判斷某個元素是否被選中了,一般用於下拉選單
element_located to be_selected 判斷某個元素是否被選中了,一般用於下拉選單
element_selection_statetobe 判斷某個元素的選中狀態是否符合預期
element_located_selection_state_to_be 判斷某個元素的選中狀態是否符合預期
alert_is_present 判斷頁面上是否存在 alert 框

七、Web自動化測試範例

這是本人空閒時間寫的一個招標資訊獲取自動化測試,裡面基本涵蓋了上述selenium內容,附加了註釋,日期、excel表格讀取和寫入,貼近日常工作。

import time
import pandas as pd
import glob
import openpyxl
import traceback
from openpyxl.styles import Border, Side, Alignment
from datetime import datetime,timedelta
from pathlib import Path
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC


# 指定桌面路徑
keyword_path = Path.home() / '招標/關鍵詞'
save_path = Path.home() / '招標/結果'
# 獲取當日日期``````````
today = time.strftime("%Y-%m-%d", time.localtime())
# 獲取昨天的日期時間
yesterday = datetime.now() - timedelta(days=1)
yesterday_start = yesterday.replace(hour=0, minute=0, second=0, microsecond=0)
# 獲取今天的日期時間
thetoday = datetime.now()
today_start = thetoday.replace(hour=0, minute=0, second=0, microsecond=0)
# 格式化日期時間
yesterday_formatted = yesterday_start.strftime("%Y-%m-%d %H:%M:%S")
today_formatted = today_start.strftime("%Y-%m-%d %H:%M:%S")
# 建立空的case列表
case = []
# 建立空的結果列表
result_list = []

def read_excel():
    global case
    # 查詢以"關鍵詞"開頭的Excel檔案
    file_pattern = str(keyword_path / '關鍵詞*.xlsx')
    file_list = glob.glob(file_pattern)
    # 讀取第一個匹配到的Excel檔案
    if file_list:
        file_path = file_list[0]
        df = pd.read_excel(file_path)
        case = df['關鍵字'].values.tolist()
    else:
        print("未找到匹配的Excel檔案")

#網站1資料獲取
def search_results():
    global result_list
    global case
    # 開啟第一個網站
    driver.get("http://118.64.254.72/freecms/site/juncai//cggg/index.html")

    # 等待頁面載入完全
    time.sleep(2)

    #進入採購大廳
    purchase_notice1 = WebDriverWait(driver, 10).until(
        EC.presence_of_element_located((By.XPATH, "//ul[@class='nav-tab']//li/span[contains(text(),'採購大廳')]"))
    )
    purchase_notice1.click()
    # 等待搜尋結果載入完全
    time.sleep(1)
    driver.find_element_by_xpath("//div[@class='layui-input-inline']//input[@id='stateDate']").send_keys(yesterday_formatted)
    driver.find_element_by_xpath("//div[@class='layui-input-inline']//input[@id='endDate']").send_keys(today_formatted)
    driver.find_element_by_xpath(
        "//div[@class='layui-col-md3']//div[@class='layui-form-select']//i[@class ='layui-edge']").click()
    time.sleep(1)
    driver.find_element_by_xpath(
        "//div[@class='layui-input-inline layui-form']//dl/dd[contains(text(),'全部')]").click()
    driver.find_element_by_xpath(
        "//div[@class='layui-col-md3']//div[@class='layui-form-select']//i[@class ='layui-edge']").click()

    for i, keyword in enumerate(case):
        # 在第一個網站中搜尋關鍵詞
        keyword_str = str(keyword)
        search_input1 = WebDriverWait(driver, 10).until(EC.presence_of_element_located((By.CSS_SELECTOR, "input[name='identity']")))
        search_input1.clear()
        search_input1.send_keys(keyword)

        search_button = WebDriverWait(driver, 10).until(
            EC.presence_of_element_located((By.XPATH, "//button[contains(@class,'layui-btn-normal')]"))
        )
        search_button.click()
        # 等待搜尋結果載入完全
        time.sleep(1)

        # 迴圈處理每一頁的搜尋結果
        while True:
            # 獲取當前頁的搜尋結果
            articles = driver.find_elements(By.XPATH, "//div[@class='searchBoxBottom']//ul/li/a/..")
            if articles:
                for j, article in enumerate(articles):
                    # 獲取搜尋結果的資訊
                    Announcement_title =article.find_elements_by_xpath("//div[@class='searchBoxBottom']//ul/li/a/span/p[@class='ellipsis']")[j].text
                    Announcement_type = article.find_elements_by_xpath("//div[@class='searchBoxBottom']//ul/li/a/span[contains(@style,'margin-left: 42px')]")[j].text
                    Announcement_time = article.find_elements_by_xpath("//div[@class='searchBoxBottom']//ul/li/a/span[contains(@style,'margin-right: 15px')]")[j].text
                    Announcement_link = article.find_elements_by_xpath("//div[@class='searchBoxBottom']//ul/li/a")[j].get_attribute('href')
                    result_list.append([keyword_str, Announcement_type, Announcement_title, Announcement_time, Announcement_link])
            time.sleep(1)
            # 判斷是否存在下一頁按鈕
            next_page_buttons = driver.find_elements(By.XPATH, "//div[@class='pagination' and not(contains(@style,'display: none'))]//li[contains(text(),'>') and not(@class='disabled')]")
            if len(next_page_buttons) > 0:
                # 點選下一頁按鈕
                next_page_button = next_page_buttons[0]
                next_page_button.click()
                # 等待搜尋結果載入完全
                time.sleep(1)
            else:
                break
        time.sleep(1)
    return result_list

#建立excel儲存資料
def creat_excel(result_list):
    # 建立Excel工作簿
    wb = openpyxl.Workbook()
    sheet = wb.active
    last_row = 0
    # 設定表頭
    sheet['A1'] = '關鍵詞'
    sheet['B1'] = '公告型別'
    sheet['C1'] = '標題'
    sheet['D1'] = '時間'
    sheet['E1'] = 'URL'

    # 遍歷result_list中的資料,並逐個寫入Excel單元格
    for i, result in enumerate(result_list):
        keyword_str, Announcement_type, Announcement_title, Announcement_time, Announcement_link = result
        # 從第二行開始寫入,因為第一行是表頭
        last_row = i + 2
        sheet.cell(row=last_row, column=1, value=keyword_str)
        sheet.cell(row=last_row, column=2, value=Announcement_type)
        sheet.cell(row=last_row, column=3, value=Announcement_title)
        sheet.cell(row=last_row, column=4, value=Announcement_time)
        sheet.cell(row=last_row, column=5, value=Announcement_link)

    # 建立邊框樣式
    border = Border(
        left=Side(border_style="thin", color="000000"),
        right=Side(border_style="thin", color="000000"),
        top=Side(border_style="thin", color="000000"),
        bottom=Side(border_style="thin", color="000000")
    )

    # 設定邊框樣式、對齊方式和行高
    for row in sheet.iter_rows(min_row=1, max_row=last_row, min_col=1, max_col=5):
        for cell in row:
            cell.border = border
            cell.alignment = Alignment(wrap_text=True, vertical="center")
            sheet.row_dimensions[cell.row].height = 40
            # 設定列寬
            sheet.column_dimensions['A'].width = 19
            sheet.column_dimensions['B'].width = 10
            sheet.column_dimensions['C'].width = 21
            sheet.column_dimensions['D'].width = 12
            sheet.column_dimensions['E'].width = 40

    # 儲存Excel檔案
    file_name = f'結果_{today}.xlsx'
    file_path = save_path / file_name
    wb.save(file_path)
    wb.close()
    print("資料已寫入Excel檔案:", file_path)

if __name__ == '__main__':
    try:
        read_excel()
        # 建立Chrome瀏覽器範例
        driver = webdriver.Chrome()
        driver.maximize_window()
        #呼叫函數
        search_results()
        # 關閉網站
        driver.quit()
        creat_excel(result_list=result_list)
    except Exception as e:
        print(traceback.format_exc())

八、總結

本文主要介紹了selenium的部署使用、組成元素、互動操作等基本內容,後續還有一些進階內容,例如Actions介面,驗證碼識別、指令碼執行等等,我也會結合python編寫實用的程式供大家參考。至此,selenium的基礎學習完結,但學無止境,繼續加油