Làm cách nào để tìm một phần tử có chứa văn bản cụ thể trong Selenium WebSearch (Python)?


259

Tôi đang thử kiểm tra giao diện javascript phức tạp với Selenium (sử dụng giao diện Python và trên nhiều trình duyệt). Tôi có một số nút có dạng:

<div>My Button</div>

Tôi muốn có thể tìm kiếm các nút dựa trên "Nút của tôi" (hoặc không phân biệt chữ hoa chữ thường, khớp một phần, chẳng hạn như "nút của tôi" hoặc "nút")

Tôi đang tìm thấy điều này cực kỳ khó khăn, đến mức tôi cảm thấy như mình đang thiếu thứ gì đó rõ ràng. Điều tốt nhất tôi có cho đến nay là:

driver.find_elements_by_xpath('//div[contains(text(), "' + text + '")]')

Điều này là trường hợp nhạy cảm, tuy nhiên. Một điều khác tôi đã thử là lặp qua tất cả các div trên trang và kiểm tra thuộc tính Element.text. Tuy nhiên, mỗi khi bạn nhận được một tình huống của mẫu:

<div class="outer"><div class="inner">My Button</div></div>

div.outer cũng có "Nút của tôi" làm văn bản. Để khắc phục RATNG, tôi đã cố gắng xem liệu div.outer có phải là cha mẹ của div.inner không, nhưng không thể tìm ra cách làm điều đó (Element.get_element_by_xpath ('..') trả về cha mẹ của một phần tử, nhưng nó kiểm tra không bằng div.outer). Ngoài ra, việc lặp qua tất cả các yếu tố trên trang dường như rất chậm, ít nhất là sử dụng trình duyệt web Chrome.

Ý tưởng?

Chỉnh sửa: Câu hỏi này xuất hiện một chút mơ hồ. Đã hỏi (và trả lời) một phiên bản cụ thể hơn ở đây: Làm cách nào để lấy văn bản của một phần tử trong Selenium WebDriver (thông qua api Python) mà không bao gồm văn bản phần tử con?


Các câu trả lời hiện tại không làm việc cho tôi. Điều này đã làm: sqa.stackexchange.com/a/2486
alejandro

Câu trả lời:


328

Hãy thử như sau:

driver.find_elements_by_xpath("//*[contains(text(), 'My Button')]")

3
Cảm ơn bạn đã trả lời, đó là 50% những gì tôi cần (đã giúp tôi bắt đầu). Biểu mẫu tôi đã đến là "(// * [chứa (text (), '" + text + "')] | // * [@ value = '" + text + "'])" nó sẽ tìm kiếm văn bản đã cho không chỉ bên trong các nút phần tử, mà cả bên trong các phần tử đầu vào có văn bản được đặt thông qua thuộc tính 'value' tức là <button value = "Nút của tôi" />. Mặc dù lưu ý, giá trị phải phù hợp nghiêm ngặt, không chỉ chứa văn bản.
Ivan Koshelev

9
Cũng đáng đề cập cho khách truy cập công cụ tìm kiếm khác: nếu bạn đang tìm kiếm một liên kết, có find_element(s)_by_link_textfind_element(s)_by_partial_link_textphương pháp
Dan Passaro

3
Nếu văn bản là động thì sao? Đó là, có thể chứa dấu ngoặc kép. Điều đó sẽ không phá vỡ giải pháp này?
IcedDante

3
Tìm kiếm một số tên nhất định dường như phá vỡ điều này. Lấy ví dụ sau đây cho một ví dụ: "// * [chứa (text (), '" + username + "')]" if username = "O'Reilly"; sau đó xpath sẽ trở nên không hợp lệ. Có cách nào để giái quyết vấn đề này không?
Sakamoto Kazuma

Nó dường như không hoạt động khi văn bản đích có nhiều dòng.
Shawn

29

bạn có thể thử một xpath như:

'//div[contains(text(), "{0}") and @class="inner"]'.format(text)

Cảm ơn ... để giúp phân biệt bên trong với bên ngoài, nhưng điều đó thực sự hoạt động tốt với xpath, tôi chỉ gặp vấn đề đó lặp đi lặp lại qua tất cả các div. Vấn đề của tôi với xpath là tôi không thể tìm ra cách làm cho nó không phân biệt chữ hoa chữ thường?
Josh

2
xpath 2.0 có chức năng chữ thường, vì vậy đây sẽ làm việc: '// div [chứa (chữ thường (text ()), "{0}")]' định dạng (văn bản).
Andrean

cảm ơn! mặc dù, sự hiểu biết của tôi là xpath 2.0 không được hỗ trợ trên các trình duyệt chính ...
Josh

selenium đánh giá các biểu thức xpath trực tiếp bằng các phương thức riêng của trình duyệt, do đó, nó phụ thuộc vào trình duyệt nào bạn đang sử dụng với selenium. nói chung chỉ có nghĩa là 6,7 và 8 không nên hỗ trợ xpath 2.0.
andrean

.formatkhông được công nhận trong nhật thực của tôi. nó cho và lỗi. bất cứ ý tưởng, tại sao?
anujin

16

Bạn cũng có thể sử dụng nó với Mẫu đối tượng trang, ví dụ:

Hãy thử mã này:

@FindBy(xpath = "//*[contains(text(), 'Best Choice')]")
WebElement buttonBestChoice;

13

// * sẽ tìm kiếm bất kỳ thẻ HTML nào. Trong trường hợp nếu một số văn bản phổ biến cho Nút và thẻ div và nếu // * là danh mục thì nó sẽ không hoạt động như mong đợi. Nếu bạn cần chọn bất kỳ cụ thể nào thì Bạn có thể lấy nó bằng cách khai báo thẻ Phần tử HTML. Giống:

driver.find_element_by_xpath("//div[contains(text(),'Add User')]")
driver.find_element_by_xpath("//button[contains(text(),'Add User')]")

5

Điều thú vị là hầu như tất cả các câu trả lời xoay quanh chức năng xpath của contains(), bỏ qua một thực tế đó là trường hợp nhạy cảm - trái với hỏi của OP.
Nếu bạn cần phân biệt chữ hoa chữ thường, có thể đạt được trong xpath 1.0 (phiên bản hỗ trợ trình duyệt hiện đại) , mặc dù nó không đẹp - bằng cách sử dụng translate()chức năng. Nó thay thế một ký tự nguồn thành dạng mong muốn của nó, bằng cách sử dụng bảng dịch.

Xây dựng một bảng gồm tất cả các ký tự chữ hoa sẽ chuyển đổi hiệu quả văn bản của nút thành dạng thấp hơn () - cho phép khớp không phân biệt chữ hoa chữ thường (đây chỉ là đặc quyền) :

[
  contains(
    translate(text(), 'ABCDEFGHIJKLMNOPQRSTUVWXYZ', 'abcdefghijklmnopqrstuvwxyz'),
    'my button'
  )
]
# will match a source text like "mY bUTTon"

Cuộc gọi python đầy đủ:

driver.find_elements_by_xpath("//*[contains(translate(text(), 'ABCDEFGHIJKLMNOPQRSTUVWXYZЙ', 'abcdefghijklmnopqrstuvwxyzй'), 'my button')]")

Đương nhiên cách tiếp cận này có nhược điểm của nó - như đã cho, nó sẽ chỉ hoạt động đối với văn bản Latin; nếu bạn muốn bao gồm các ký tự unicode - bạn sẽ phải thêm chúng vào bảng dịch. Tôi đã thực hiện điều đó trong mẫu ở trên - ký tự cuối cùng là biểu tượng Cyrillic "Й".


Và nếu chúng ta sống trong một thế giới nơi các trình duyệt hỗ trợ xpath 2.0 trở lên (, nhưng sẽ không xảy ra bất cứ lúc nào) , chúng ta có thể đã sử dụng các chức năng lower-case()(chưa, không nhận biết đầy đủ địa phương) và matches(đối với tìm kiếm regex, với trường hợp cờ -ensensitive ( 'i')).


3

Trong HTML mà bạn đã cung cấp:

<div>My Button</div>

Văn bản My ButtoninnerHTMLvà không có khoảng trắng xung quanh nó để bạn có thể dễ dàng sử dụng text()như sau:

my_element = driver.find_element_by_xpath("//div[text()='My Button']")

Lưu ý : text()chọn tất cả các nút con văn bản của nút bối cảnh


Văn bản với không gian hàng đầu / dấu

Bắt đầu văn bản có liên quan có chứa khoảng trắng ngay từ đầu:

<div>   My Button</div>

hoặc ở cuối:

<div>My Button   </div>

hoặc ở cả hai đầu:

<div> My Button </div>  

Trong những trường hợp này, bạn có 2 tùy chọn:

  • Bạn có thể sử dụng contains()hàm xác định xem chuỗi đối số thứ nhất có chứa chuỗi đối số thứ hai và trả về boolean đúng hay sai như sau:

    my_element = driver.find_element_by_xpath("//div[contains(., 'My Button')]")
  • Bạn có thể sử dụng normalize-space()chức năng loại bỏ khoảng trắng dẫn đầu và theo dõi khoảng trắng từ một chuỗi, thay thế các chuỗi ký tự khoảng trắng bằng một khoảng trắng và trả về chuỗi kết quả như sau:

    driver.find_element_by_xpath("//div[normalize-space()='My Button']]")

xpath cho văn bản biến

Trong văn bản là một biến bạn có thể sử dụng:

foo= "foo_bar"
my_element = driver.find_element_by_xpath("//div[.='" + foo + "']")

1
wait.until(ExpectedConditions.visibilityOfElementLocated(By.xpath("//*[contains(text(), 'YourTextHere')]")));
    assertNotNull(driver.findElement(By.xpath("//*[contains(text(), 'YourTextHere')]")));
    String yourButtonName=driver.findElement(By.xpath("//*[contains(text(), 'YourTextHere')]")).getAttribute("innerText");
    assertTrue(yourButtonName.equalsIgnoreCase("YourTextHere"));

1

Vấn đề tương tự: Tìm <button>Advanced...</button>

Có thể điều này sẽ cung cấp cho bạn một số ý tưởng (vui lòng chuyển khái niệm từ Java sang Python):

wait.until(ExpectedConditions.elementToBeClickable(//
    driver.findElements(By.tagName("button")).stream().filter(i -> i.getText().equals("Advanced...")).findFirst().get())).click();

0

Sử dụng driver.find_elements_by_xpathkhớp chức năng khớp regex cho trường hợp tìm kiếm không nhạy cảm của phần tử bằng văn bản của nó.

driver.find_elements_by_xpath("//*[matches(.,'My Button', 'i')]")

matches()là một chức năng xpath 2.0 và rất tiếc các trình duyệt chỉ hỗ trợ cho 1.0.
Todor Minakov

-19

Thử cái này. Nó rất dễ:

driver.getPageSource().contains("text to search");

Điều này thực sự làm việc cho tôi trong trình điều khiển web selenium.


9
Nó không hoạt động nếu văn bản được tạo bởi JavaScript.
palacsint

2
Đây là một cách rất để kiểm tra nó, bởi vì bạn đang chuyển toàn bộ nội dung của trang qua dây. Đối với các trang rất nhỏ, điều này có thể chấp nhận được nhưng đối với các trang rất lớn, bạn sẽ chuyển tất cả nội dung của tệp và kiểm tra phía máy chủ. Một cách tiếp cận tốt hơn sẽ là làm điều đó ở phía máy khách với xpath, javascript hoặc css.
thomas.han

Tôi có thể nghĩ rằng toàn bộ nguồn trang sẽ cần phải được chuyển qua dây để trình duyệt hiển thị không?
René

3
Josh đang hỏi làm thế nào để tìm phần tử bằng văn bản, không kiểm tra xem văn bản có trong nguồn của trang không.
Cedric

1
Đối với những trường hợp cần tất cả là tìm một văn bản tĩnh trên một trang, giải pháp này là đủ tốt. (Nó giúp trong trường hợp của tôi).
Karlth
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.