Trong quá trình tự động hóa web với Selenium, có nhiều trường hợp bạn cần tìm các phần tử dựa trên tên thẻthuộc tính (attributes) của chúng. Thay vì phải tìm kiếm riêng lẻ từng loại thẻ hoặc thuộc tính, chúng ta có thể xây dựng một hàm linh hoạt để tìm kiếm bất kỳ thẻ HTML nào với các thuộc tính cụ thể. Hàm này giúp chúng ta tối ưu quá trình tìm kiếm và quản lý các phần tử trong DOM một cách dễ dàng hơn.

Dưới đây là hướng dẫn chi tiết về hàm find_elements_by_tag_and_attributes, sử dụng Selenium:

def find_elements_by_tag_and_attributes(driver, tag_name="*", attributes={}):
    # Tạo query XPath với tên thẻ
    xpath_query = f"//{tag_name}"
    
    # Nếu có thuộc tính cần tìm, thêm điều kiện vào query
    if attributes:
        conditions = []
        for attr, value in attributes.items():
            # Tìm kiếm giá trị gần đúng cho từng thuộc tính
            conditions.append(f"contains(@{attr}, '{value}')")
        
        # Kết hợp các điều kiện thành một chuỗi XPath hoàn chỉnh
        xpath_query += f"[{' and '.join(conditions)}]"
    
    # Trả về danh sách các phần tử phù hợp với XPath query
    return driver.find_elements_by_xpath(xpath_query)

1. Mục đích của hàm

Hàm find_elements_by_tag_and_attributes được sử dụng để:

  • Tìm kiếm các thẻ HTML trong trang web dựa trên tên thẻ và các thuộc tính gần đúng.
  • Tăng tính linh hoạt khi có thể áp dụng cho bất kỳ thẻ nào (a, div, span, v.v.) và bất kỳ thuộc tính nào (class, id, href, v.v.).
  • Tiết kiệm thời gian cho người lập trình khi cần tìm kiếm nhiều phần tử phức tạp trong DOM.

2. Các tham số đầu vào

Hàm nhận ba tham số chính:

  • driver: Đây là đối tượng trình duyệt đang hoạt động trong Selenium, dùng để tương tác với DOM của trang web.
  • tag_name (mặc định là "*") : Tên thẻ HTML cần tìm. Mặc định là "*", có nghĩa là tìm tất cả các thẻ. Bạn có thể chỉ định bất kỳ thẻ nào như a, div, span, input, v.v.
  • attributes (mặc định là {}): Là một dictionary chứa các cặp khóa (thuộc tính) và giá trị (giá trị gần đúng của thuộc tính) mà bạn muốn tìm. Ví dụ: { "class": "header", "id": "main" }.

3. Cấu trúc hoạt động của hàm

Bước 1: Tạo query XPath với tên thẻ

  • xpath_query = f"//{tag_name}": Đây là bước tạo query XPath cơ bản để tìm thẻ HTML dựa trên tên thẻ được truyền vào. Ví dụ, nếu tag_name"div", query XPath sẽ là "//div" để tìm tất cả các thẻ div trong trang web.

Bước 2: Kiểm tra và thêm điều kiện về thuộc tính

Nếu attributes được truyền vào, hàm sẽ tạo một danh sách các điều kiện dựa trên các cặp thuộc tính và giá trị.

  • Duyệt qua các thuộc tính: Với vòng lặp for attr, value in attributes.items(), hàm sẽ duyệt qua từng cặp attr (thuộc tính) và value (giá trị gần đúng).
  • Sử dụng hàm contains của XPath: contains(@{attr}, '{value}') là cách tìm kiếm trong XPath để kiểm tra xem giá trị của thuộc tính có chứa chuỗi con được chỉ định hay không.
    • Ví dụ: contains(@class, 'header') sẽ tìm tất cả các thẻ có class chứa chuỗi "header".

Bước 3: Kết hợp các điều kiện

  • xpath_query += f"[{' and '.join(conditions)}]": Nếu có nhiều điều kiện tìm kiếm (nhiều thuộc tính), hàm sẽ nối các điều kiện này lại bằng từ khóa and để tìm các phần tử thỏa mãn tất cả các điều kiện.

Bước 4: Trả về danh sách các phần tử

  • return driver.find_elements_by_xpath(xpath_query): Sau khi hoàn thành câu query XPath, hàm sẽ sử dụng Selenium để tìm các phần tử thỏa mãn điều kiện và trả về danh sách các phần tử đó.

4. Ví dụ sử dụng

Giả sử bạn đang làm việc trên một trang web và muốn tìm tất cả các thẻ div có class chứa "example" và id chứa "header". Bạn có thể sử dụng hàm như sau:

driver = webdriver.Chrome()
driver.get("https://example.com")

# Tìm tất cả các thẻ div có class chứa 'example' và id chứa 'header'
attributes = {
    "class": "example",
    "id": "header"
}
elements = find_elements_by_tag_and_attributes(driver, "div", attributes)

# In ra các thuộc tính của thẻ đã tìm được
for element in elements:
    print(element.get_attribute("class"), element.get_attribute("id"))

Kết quả:

Hàm sẽ trả về các thẻ div thỏa mãn điều kiện rằng chúng có:

  • class chứa chuỗi "example".
  • id chứa chuỗi "header".

5. Lợi ích của hàm

  • Tính linh hoạt cao: Bạn có thể tìm bất kỳ thẻ nào với bất kỳ thuộc tính nào bằng cách truyền vào tên thẻ và danh sách thuộc tính.
  • Tiết kiệm thời gian: Giảm bớt việc viết nhiều đoạn mã lặp lại để tìm các phần tử dựa trên nhiều thuộc tính khác nhau.
  • Dễ dàng mở rộng: Nếu cần thêm các điều kiện phức tạp hơn (như so sánh giá trị chính xác, tìm theo nội dung văn bản), bạn chỉ cần sửa đổi hàm mà không cần viết lại từ đầu.

Kết luận

Hàm find_elements_by_tag_and_attributes giúp tự động hóa quá trình tìm kiếm các phần tử HTML trong trang web một cách linh hoạthiệu quả. Bạn có thể dễ dàng tìm kiếm bất kỳ thẻ nào dựa trên các thuộc tính khác nhau và áp dụng vào nhiều trường hợp khác nhau trong quá trình làm việc với Selenium.