Mã Python mẫu để truy vấn, thêm và xóa Cookie 4 - cwin222

24 tháng 4 năm 2023 - Công Nghệ Thông Tin

Bài trước "Sử dụng Cơ Bản Selenium WebDriver" đã giới thiệu về cách sử dụng các chức năng cơ bản của Selenium WebDriver. Bài viết này sẽ tiếp tục trình bày về cách sử dụng các tính năng nâng cao của Selenium WebDriver, bao gồm chiến lược tải trang, chiến lược chờ đợi, định vị và thao tác phần tử, cũng như các thao tác trên trình duyệt.

Tất cả các ví dụ trong bài viết đều được mô tả bằng ngôn ngữ lập trình Python. Ngoài ra, dưới đây là thông tin phiên bản trình duyệt và Selenium được sử dụng:

  • Trình duyệt: Chrome
  • Phiên bản Selenium: 4.9.0

1. Chiến Lược Tải Trang

Selenium WebDriver cung cấp ba chiến lược tải trang có thể chọn trong tùy chọn trình duyệt, đó là: normal, eagernone.

Trước khi tìm hiểu ý nghĩa của chúng, hãy xem qua các giai đoạn chính trong quá trình tải và hiển thị một trang web.

Theo sự kiện, vòng đời của một trang web chủ yếu bao gồm các giai đoạn sau: DOMContentLoaded, load, beforeunloadunload.

  • DOMContentLoaded: Tài liệu HTML đã được tải hoàn tất và cây DOM đã được xây dựng xong, nhưng các tài nguyên bên ngoài như tập lệnh, hình ảnh, bảng kiểu CSS, iFrame có thể chưa được tải xong.
  • load: Không chỉ tài liệu HTML đã được tải hoàn tất mà các tài nguyên bên ngoài như tập lệnh, hình ảnh, bảng kiểu CSS, iFrame cũng đã được tải xong.
  • beforeunload: Sự kiện xảy ra trước khi người dùng rời khỏi trang.
  • unload: Người dùng đã rời khỏi trang.

Theo thuộc tính document.readyState, chỉ có ba trạng thái: loading, interactivecomplete.

  • loading: Tài liệu HTML vẫn đang được tải.
  • interactive: Tài liệu HTML đã được tải và phân tích cú pháp xong, nhưng các tài nguyên bên ngoài như tập lệnh, hình ảnh, bảng kiểu CSS, iFrame có thể chưa được tải xong.
  • complete: Tài liệu HTML và các tài nguyên bên ngoài như tập lệnh, hình ảnh, bảng kiểu CSS, iFrame đã được tải hoàn tất.

Hình dưới đây kết hợp hai cách trên để minh họa vòng đời của một trang web: !Vòng đời trang web

Như có thể thấy, sự kiện DOMContentLoaded tương ứng với interactive trong document.readyState; sự kiện load tương ứng với complete trong document.readyState.

Dưới đây là bảng so sánh giữa các chiến lược tải trang của Selenium với các sự kiện và document.readyState tương ứng:

Chiến lược tải trang của Selenium Sự kiện tương ứng document.readyState tương ứng
normal (mặc định) load complete
eager DOMContentLoaded interactive
none Không có Any (bất kỳ trạng thái nào)

Khi truy cập một URL, chiến lược mặc định của Selenium WebDriver là chờ toàn bộ trang được tải hoàn toàn (trừ khi nội dung động được thêm vào sau sự kiện load bằng JavaScript). Khi viết kịch bản kiểm tra tự động, nếu logic kiểm tra không phụ thuộc vào việc tải các tài nguyên bên ngoài, chiến lược tải trang có thể được thay đổi từ giá trị mặc định normal sang eager hoặc none để tăng tốc độ quá trình kiểm tra.

Một ví dụ về mã nguồn Python thay đổi chiến lược tải trang của Selenium WebDriver (page_load_strategy.py):

1from selenium import webdriver
2from selenium.webdriver.chrome.options import Options
3options = Options()
4options.page_load_strategy = 'eager' # 'none', 'normal'
5driver = webdriver.Chrome(options=options)
6driver.get('https://example.com')
7driver.quit()

2. Chiến Lược Chờ Đợi

WebDriver là một thư viện cho phép ra lệnh cho trình duyệt thực hiện các hành động nhất định. Do đặc tính bất đồng bộ của các trang web và WebDriver không theo dõi thời gian thực trạng thái của DOM, đôi khi việc định vị phần tử có thể dẫn đến lỗi "no such element".

Xem ví dụ sau (no_such_element.py):

 1from selenium import webdriver
 2from selenium.webdriver import Keys
 3from selenium.webdriver.common.by import By
 4driver = webdriver.Chrome()
 5driver.get('https://www.baidu.com')
 6text_input = driver.find_element(By.ID, 'kw')
 7text_input.send_keys('Selenium' + Keys.RETURN)
 8# Sẽ ném ra lỗi NoSuchElementException
 9first_result_title = driver.find_element(By.XPATH, '//div[@id="content_left"]/div[1]/h3').text
10print(first_result_title)
11driver.quit()

Đoạn mã này mở trang chủ Baidu, nhập từ khóa "Selenium" rồi nhấn Enter để tìm kiếm, sau đó in ra tiêu đề của kết quả đầu tiên. Khi chạy đoạn mã này, sẽ xuất hiện lỗi NoSuchElementException, lý do là vì trang kết quả tìm kiếm chưa được tải hoàn toàn nên không tìm thấy phần tử tương ứng.

Làm thế nào để giải quyết vấn đề này? Có thể sử dụng chức năng chờ đợi rõ ràng hoặc chờ đợi ngầm của Selenium WebDriver.

2.1 Chờ Đợi Rõ Ràng

Chờ đợi rõ ràng là tạm dừng chương trình cho đến khi điều kiện truyền vào được thỏa mãn. Chức năng này rất phù hợp để đồng bộ hóa trạng thái giữa WebDriver và DOM.

Đoạn mã ném lỗi "no such element" (no_such_element.py) có thể được cải tiến bằng cách sử dụng chờ đợi rõ ràng (explicit_wait.py):

 1from selenium import webdriver
 2from selenium.webdriver import Keys
 3from selenium.webdriver.common.by import By
 4from selenium.webdriver.support.wait import WebDriverWait
 5from selenium.webdriver.support import expected_conditions as EC
 6driver = webdriver.Chrome()
 7driver.get('https://www.baidu.com')
 8text_input = driver.find_element(By.ID, 'kw')
 9text_input.send_keys('Selenium' + Keys.RETURN)
10# Chờ kết quả tìm kiếm hiển thị
11WebDriverWait(driver, 10).until(EC.presence_of_element_located((By.ID, 'content_left')))
12# Sẽ không ném ra ngoại lệ
13first_result_title = driver.find_element(By.XPATH, '//div[@id="content_left"]/div[1]/h3').text
14print(first_result_title)
15driver.quit()

Ở đây, chúng ta tạo một đối tượng WebDriverWait (chỉ định thời gian hết hạn), và đặt điều kiện thoát cho nó bằng phương thức expected_conditions.presence_of_element_located(). Ngoài phương thức này, gói expected_conditions còn cung cấp các phương thức hữu ích khác như expected_conditions.url_contains()expected_conditions.title_is().

2.2 Chờ Đợi Ngầm

Chờ đợi ngầm là hướng dẫn WebDriver tìm kiếm phần tử trong một khoảng thời gian nhất định nếu phần tử không tồn tại ngay lập tức. Nó thường được thiết lập khi khởi tạo WebDriver và áp dụng cho toàn bộ phiên làm việc.

Đoạn mã ném lỗi "no such element" (no_such_element.py) có thể được cải tiến bằng cách sử dụng chờ đợi ngầm (implicit_wait.py):

 1from selenium import webdriver
 2from selenium.webdriver import Keys
 3from selenium.webdriver.common.by import By
 4driver = webdriver.Chrome()
 5# Thiết lập thời gian chờ đợi ngầm
 6driver.implicitly_wait(10)
 7driver.get('https://www.baidu.com')
 8text_input = driver.find_element(By.ID, 'kw')
 9text_input.send_keys('Selenium' + Keys.RETURN)
10# Sẽ không ném ra ngoại lệ
11first_result_title = driver.find_element(By.XPATH, '//div[@id="content_left"]/div[1]/h3').text
12print(first_result_title)
13driver.quit()

Trong các tình huống kiểm thử thực tế, thường chỉ khuyến nghị sử dụng chờ đợi rõ ràng.

3. Định Vị Và Thao Tác Phần Tử

Việc định vị và thao tác với các phần tử trong DOM là công việc chính khi viết các kịch bản kiểm tra tự động bằng Selenium.

3.1 Định Vị Phần Tử

Selenium WebDriver cung cấp tám phương pháp cơ bản để định vị phần tử.

Phương pháp định vị Mô tả
id Tìm phần tử có thuộc tính id trùng khớp với giá trị tìm kiếm
name Tìm phần tử có thuộc tính name trùng khớp với giá trị tìm kiếm
class name Tìm phần tử có tên class chứa giá trị tìm kiếm
css selector Tìm phần tử khớp với bộ chọn CSS
link text Tìm phần tử thẻ a có văn bản hiển thị trùng khớp với giá trị tìm kiếm
partial link text Tìm phần tử thẻ a có văn bản hiển thị chứa giá trị tìm kiếm. Nếu có nhiều phần tử, chỉ chọn phần tử đầu tiên.
tag name Tìm phần tử có tên thẻ trùng khớp với giá trị tìm kiếm
xpath Tìm phần tử khớp với biểu thức XPath

Dưới đây là mã HTML của ô input trong trang tìm kiếm Baidu:

1<input id="kw" name="wd" class="s_ipt" maxlength="255" autocomplete="off" />

Có thể sử dụng các cách sau để định vị phần tử input này:

1driver.find_element(By.ID, 'kw')
2driver.find_element(By.CLASS_NAME, [78win+đăng+nhập](/post/leetcode-insert-into-a-binary-search-tree.html)  's_ipt')
3driver.find_element(By.NAME, 'wd')
4driver.find_element(By.XPATH, '//input[@name="wd"]')

Ngoài ra, từ phiên bản 4, Selenium đã giới thiệu các định vị tương đối, cho phép sử dụng vị trí không gian tương đối để định vị một phần tử, rất hữu ích khi các phương pháp định vị truyền thống không đủ mô tả.

Dưới đây là một ví dụ về trang mẫu biểu mẫu web từ trang chính thức của Selenium: !Biểu mẫu mẫu Selenium

Trên trang này, bên dưới ô nhập liệu Text input có một ô nhập liệu Password.

Mã HTML của hai ô nhập liệu này là:

1<input type="text" name="my-text" id="my-text-id" />
2...
3<input type="password" name="my-password" autocomplete="off" />

Nếu khó định vị ô Password bằng phương pháp truyền thống, có thể sử dụng định vị tương đối:

1password_locator = locate_with(By.TAG_NAME, 'input').below({By.ID: 'my-text-id'})
2driver.find_element(password_locator)

3.2 Thao Tác Phần Tử

Selenium cung cấp bốn lệnh cơ bản để thao tác phần tử. Đó là:

Dưới đây là một ví dụ minh họa cách sử dụng các lệnh này.

Mã HTML của ô nhập liệu từ khóa và nút tìm kiếm "百度一下" trong trang Baidu:

1<input id="kw" name="wd" class="s_ipt" maxlength="255" autocomplete="off" />
2...
3<input type="submit" id="su" value="百度一下" class="bg s_btn" />

Có thể sử dụng các lệnh sau để xóa từ khóa, nhập từ khóa mới và nhấp vào nút tìm kiếm:

1input_text = driver.find_element(By.ID, 'kw')
2input_text.clear()
3input_text.send_keys('Selenium')
4driver.find_element(By.ID, 'su').click()

Về lệnh Select, có thể sử dụng trang mẫu biểu mẫu web từ trang chính thức của Selenium để làm ví dụ.

Mã HTML của phần chọn đơn Dropdown (select) trên trang này:

1<select class="form-select" name="my-select">
2 <option selected="">Open this select menu</option>
3 <option value="1">One</option>
4 <option value="2">Two</option>
5 <option value="3">Three</option>
6</select>

Mã Python sử dụng đối tượng Select để chọn một mục trong danh sách thả xuống:

1dropdown = Select(driver.find_element(By.NAME, 'my-select'))
2dropdown.select_by_value('2')

4. Thao Tác Trên Trình Duyệt

4.1 Thao Tác Điều Hướng

Mã Python thực hiện các thao tác điều hướng trên trình duyệt:

1# Mở địa chỉ URL
2driver.get('https://example.com')
3# Nhấn nút quay lại
4driver.back()
5# Nhấn nút tiến lên
6driver.forward()
7# Nhấn nút làm mới
8driver.refresh()

4.2 Thao Tác Với Cửa Sổ Thông Báo Nguyên Bản

Có thể sử dụng Selenium WebDriver để tương tác với ba loại cửa sổ thông báo nguyên bản (Alert, Confirm và Prompt).

Dưới đây là mã HTML để minh họa ba loại cửa sổ này (alerts-test.html):

 1<!DOCTYPE html>
 2<html>
 3 <head>
 4  <title>Alerts, Prompts and Confirmations test</title>
 5  <script>
 6   function exampleAlert() {
 7    alert("This is an example alert");
 8   }
 9   function exampleConfirm() {
10    let confirmed = confirm("Do you want to confirm?");
11    document.getElementById("confirmed").innerText = confirmed;
12   }
13   function examplePrompt() {
14    let favoriteSport = prompt(
15     "What is your favorite sport?",
16     "Basketball"
17    );
18    document.getElementById("favorite-sport").innerText = favoriteSport;
19   }
20  </script>
21 </head>
22 <body>
23  <table border="1">
24   <tr>
25    <td><a onclick="exampleAlert()">Click to see an example alert</a></td>
26    <td></td>
27   </tr>
28   <tr>
29    <td>
30     <a onclick="exampleConfirm()">Click to see an example confirm</a>
31    </td>
32    <td><p id="confirmed"></p></td>
33   </tr>
34   <tr>
35    <td><a onclick="examplePrompt()">Click to see an example prompt</a></td>
36    <td><p id="favorite-sport"></p></td>
37   </tr>
38  </table>
39 </body>
40</html>

Tiếp theo, mã Python kiểm thử ba loại cửa sổ trên trang HTML này (alerts_test.py):

 1from unittest import TestCase
 2from selenium import webdriver
 3from selenium.webdriver.common.by import By
 4from selenium.webdriver.support.wait import WebDriverWait
 5from selenium.webdriver.support import expected_conditions as EC
 6class TestAlerts(TestCase):
 7  def setUp(self) -> None:
 8    self.driver = webdriver.Chrome()
 9    self.addCleanup(self.driver.quit)
10  def test_alert(self) -> None:
11    # Mở trang Alerts mẫu
12    self.driver.get('file:///Users/larry/Desktop/alerts-test.html')
13    # Nhấn liên kết "Click to see an example alert"
14    self.driver.find_element(By.LINK_TEXT, 'Click to see an example alert').click()
15    # Chờ cửa sổ bật lên, lấy thông báo Alert, nhấn OK
16    alert = WebDriverWait(self.driver, 10).until(EC.alert_is_present())
17    alert_message = alert.text
18    alert.accept()
19    # Kiểm tra
20    self.assertEqual(alert_message, 'This is an example alert')
21  def test_confirm(self) -> None:
22    # Mở trang Alerts mẫu
23    self.driver.get('file:///Users/larry/Desktop/alerts-test.html')
24    # Nhấn liên kết "Click to see an example confirm"
25    self.driver.find_element(By.LINK_TEXT, 'Click to see an example confirm').click()
26    # Chờ cửa sổ bật lên, nhấn OK
27    alert = WebDriverWait(self.driver, 10).until(EC.alert_is_present())
28    alert.accept()
29    # Lấy văn bản của "#confirmed"
30    confirmed = self.driver.find_element(By.ID, 'confirmed').text
31    # Kiểm tra
32    self.assertEqual(confirmed, 'true')
33  def test_prompt(self) -> None:
34    # Mở trang Alerts mẫu
35    self.driver.get('file:///Users/larry/Desktop/alerts-test.html')
36    # Nhấn liên kết "Click to see an example prompt"
37    self.driver.find_element(By.LINK_TEXT, 'Click to see an example prompt').click()
38    # Chờ cửa sổ bật lên, nhập thông tin, nhấn OK
39    alert = WebDriverWait(self.driver, 10).until(EC.alert_is_present())
40    alert.send_keys('Football')
41    alert.accept()
42    # Lấy văn bản của "#favorite-sport"
43    favorite_sport = self.driver.find_element(By.ID, 'favorite-sport').text
44    # Kiểm tra
45    self.assertEqual(favorite_sport, 'Football')

Có thể sử dụng Selenium WebDriver để thao tác với Cookie.

Mã Python mẫu để truy vấn, thêm và xóa Cookie:

 1from selenium import webdriver
 2driver = webdriver.Chrome()
 3# Mở URL
 4driver.get('https://example.com')
 5# Thêm Cookie vào trình duyệt hiện tại
 6driver.add_cookie({'name': 'foo', 'value': 'bar'})
 7# Lấy tất cả các Cookie
 8print(driver.get_cookies())
 9# Lấy thông tin Cookie có tên foo
10print(driver.get_cookie('foo'))
11# Xóa thông tin Cookie có tên foo
12driver.delete_cookie('foo')
13# Xóa tất cả các Cookie
14driver.delete_all_cookies()
15driver.quit()

4.4 Thao Tác Cửa Sổ Và Tab

Có thể sử dụng Selenium WebDriver để mở, đóng và chuyển đổi giữa các cửa sổ hoặc tab.

Mã Python mẫu để thao tác cửa sổ hoặc tab:

 1# Lấy tất cả các [cwin222](/post/what-is-devops.html)  handle cửa sổ hoặc tab
 2driver.window_handles
 3# Lấy handle cửa sổ hoặc tab hiện tại
 4driver.current_window_handle
 5# Chuyển đổi cửa sổ hoặc tab
 6driver.switch_to.window(handle)
 7# Mở cửa sổ mới
 8driver.switch_to.new_window('window')
 9# Mở tab mới
10driver.switch_to.new_window('tab')
11# Đóng cửa sổ hoặc tab hiện tại
12driver.close()

Tóm lại, bài viết này đã sử dụng các ví dụ mã nguồn Python để giới thiệu cách sử dụng các tính năng nâng cao của Selenium WebDriver, bao gồm chiến lược tải trang, chiến lược chờ đợi, định vị và thao tác phần tử, cũng như các thao tác trên trình duyệt.

[Tài liệu tham khảo] [1] WebDriver | Selenium - www.selenium.dev [2] Page: DOMContentLoaded, load, beforeunload, unload | The Modern JavaScript Tutorial - javascript.info [3] Hiểu lại JavaScript Phục Kháng Tập Về Vòng Đời Trang Web | iT Bang Bang Mang - ithelp.ithome.com.tw [4] Document: readyState property | MDN - developer.mozilla.org