Bagaimana cara menemukan elemen yang berisi teks tertentu di Selenium Webdriver (Python)?

259

Saya mencoba menguji antarmuka javascript yang rumit dengan Selenium (menggunakan antarmuka Python, dan melintasi beberapa browser). Saya memiliki sejumlah tombol dalam bentuk:

<div>My Button</div>

Saya ingin dapat mencari tombol berdasarkan "Tombol Saya" (atau pencocokan parsial yang tidak case-sensitif seperti "tombol saya" atau "tombol")

Saya menemukan ini sangat sulit, sampai-sampai saya merasa kehilangan sesuatu yang jelas. Hal terbaik yang saya miliki sejauh ini adalah:

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

Ini peka huruf besar-kecil. Hal lain yang saya coba adalah mengulangi semua div di halaman, dan memeriksa properti element.text. Namun, setiap kali Anda mendapatkan situasi berupa:

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

div.outer juga memiliki "My Button" sebagai teks. Untuk memperbaiki ITU, saya sudah mencoba melihat apakah div.outer adalah induk dari div.inner, tetapi tidak dapat menemukan cara melakukannya (element.get_element_by_xpath ('..') mengembalikan orangtua elemen, tetapi tes tidak sama dengan div.outer). Selain itu, melakukan iterasi melalui semua elemen pada halaman tampaknya sangat lambat, setidaknya menggunakan webdriver Chrome.

Ide ide?

Sunting: Pertanyaan ini sedikit kabur. Ditanyakan (dan dijawab) versi yang lebih spesifik di sini: Cara mendapatkan teks elemen di Selenium WebDriver (melalui api Python) tanpa menyertakan teks elemen anak?

Astaga
sumber
Jawaban saat ini tidak berhasil untuk saya. Yang ini lakukan: sqa.stackexchange.com/a/2486
alejandro

Jawaban:

328

Coba yang berikut ini:

driver.find_elements_by_xpath("//*[contains(text(), 'My Button')]")
Ricky
sumber
3
Terima kasih atas jawabannya, itu adalah 50% dari apa yang saya butuhkan (membantu saya memulai). Bentuk yang saya datangi adalah ini "(// * [berisi (teks (), '" + teks + "')] | // * [@ value = '" + text + "'])" ia akan mencari diberikan teks tidak hanya di dalam node elemen, tetapi juga di dalam elemen input yang teksnya diatur melalui atribut 'nilai' yaitu <tombol nilai = "Tombol Saya" />. Meski perlu diketahui, nilainya harus ketat, tidak hanya berisi teks.
Ivan Koshelev
9
Juga layak disebutkan untuk pengunjung mesin pencari lain: jika Anda mencari tautan, ada find_element(s)_by_link_textdan find_element(s)_by_partial_link_textmetode
Dan Passaro
3
Bagaimana jika teksnya dinamis? Artinya, mungkin berisi kutipan. Bukankah itu memecahkan solusi ini?
IcedDante
3
Mencari nama-nama tertentu tampaknya mematahkan ini. Ambil contoh berikut: "// * [berisi (teks (), '" + nama pengguna + "')]" jika nama pengguna = "O'Reilly"; maka xpath akan menjadi tidak valid. Apakah ada jalan keluarnya?
Sakamoto Kazuma
Tampaknya tidak berfungsi ketika teks target memiliki beberapa baris.
Shawn
29

Anda dapat mencoba xpath seperti:

'//div[contains(text(), "{0}") and @class="inner"]'.format(text)
andrean
sumber
Terima kasih ... sehingga membantu membedakan bagian dalam dari bagian luar, tetapi itu benar-benar berfungsi dengan baik dengan xpath, saya hanya mengalami masalah iterasi melalui semua div. Masalah saya dengan xpath adalah saya tidak tahu bagaimana cara membuatnya case-insensitive?
josh
2
xpath 2.0 memiliki fungsi huruf kecil, jadi ini harus berfungsi: '// div [berisi (huruf kecil (teks ()), "{0}")]' .format (teks)
andrean
Terima kasih! meskipun, pemahaman saya adalah bahwa xpath 2.0 tidak didukung di semua browser utama ...
josh
selenium mengevaluasi ekspresi xpath secara langsung dengan metode browser sendiri, jadi itu tergantung pada browser yang Anda gunakan dengan selenium. umumnya hanya 6,7 ​​dan 8 seharusnya tidak mendukung xpath 2.0.
andrean
.formattidak dikenali dalam gerhana saya. itu memberi dan kesalahan. ada ide, kenapa?
anujin
16

Anda juga dapat menggunakannya dengan Pola Objek Halaman, misalnya:

Coba kode ini:

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

// * akan mencari tag HTML apa pun. Di mana jika beberapa teks umum untuk Button dan tag div dan jika // * adalah kategorinya, itu tidak akan berfungsi seperti yang diharapkan. Jika Anda perlu memilih spesifik maka Anda bisa mendapatkannya dengan mendeklarasikan tag Elemen HTML. Suka:

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

Menariknya, hampir semua jawaban berputar di sekitar fungsi xpath contains(), mengabaikan fakta bahwa ia peka terhadap huruf besar-kecil - berlawanan dengan yang diminta OP.
Jika Anda memerlukan ketidakpekaan huruf, yang dapat dicapai di xpath 1.0 (versi dukungan browser kontemporer) , meskipun tidak cantik - dengan menggunakan translate()fungsi. Ini menggantikan karakter sumber ke bentuk yang diinginkan, dengan menggunakan tabel terjemahan.

Membuat tabel dari semua karakter huruf besar akan secara efektif mengubah teks node ke bentuk yang lebih rendah () - memungkinkan pencocokan case-insensitive (berikut ini adalah hak prerogatifnya) :

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

Panggilan python lengkap:

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

Tentu saja pendekatan ini memiliki kelemahan - seperti yang diberikan, itu hanya akan berfungsi untuk teks latin; jika Anda ingin membahas karakter unicode - Anda harus menambahkannya ke tabel terjemahan. Saya sudah melakukannya dalam sampel di atas - karakter terakhir adalah simbol Cyrillic "Й".


Dan jika kita hidup di dunia di mana browser mendukung xpath 2.0 dan lebih tinggi (🤞, tetapi tidak terjadi dalam waktu dekat ☹️) , kita dapat menggunakan fungsi lower-case()(namun, tidak sepenuhnya sadar-lokal), dan matches(untuk pencarian regex, dengan case -insensitive ( 'i') flag).

Todor Minakov
sumber
3

Dalam HTML yang Anda berikan:

<div>My Button</div>

Teksnya My Buttonadalah innerHTMLdan tidak memiliki spasi putih di sekitarnya sehingga Anda dapat dengan mudah menggunakan text()sebagai berikut:

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

Catatan : text()memilih semua anak simpul teks dari simpul konteks


Teks dengan spasi di depan / belakang

Masukkan teks yang relevan yang mengandung spasi putih di awal:

<div>   My Button</div>

atau pada akhirnya:

<div>My Button   </div>

atau di kedua ujungnya:

<div> My Button </div>  

Dalam kasus ini, Anda memiliki 2 opsi:

  • Anda bisa menggunakan contains()fungsi yang menentukan apakah string argumen pertama berisi string argumen kedua dan mengembalikan boolean benar atau salah sebagai berikut:

    my_element = driver.find_element_by_xpath("//div[contains(., 'My Button')]")
  • Anda bisa menggunakan normalize-space()fungsi yang mengupas memimpin dan mengekor ruang putih dari string, mengganti urutan karakter spasi dengan satu spasi, dan mengembalikan string yang dihasilkan sebagai berikut:

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

xpath untuk Teks variabel

Memetikan teks adalah variabel yang dapat Anda gunakan:

foo= "foo_bar"
my_element = driver.find_element_by_xpath("//div[.='" + foo + "']")
DebanjanB
sumber
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"));
mike oganyan
sumber
1

Masalah serupa: Temukan <button>Advanced...</button>

Mungkin ini akan memberi Anda beberapa ide (harap transfer konsep dari Java ke Python):

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

Gunakan driver.find_elements_by_xpath dan cocok dengan fungsi pencocokan regex untuk pencarian elemen yang tidak sensitif dengan teksnya.

driver.find_elements_by_xpath("//*[matches(.,'My Button', 'i')]")
Andriy Ivaneyko
sumber
matches()adalah fungsi xpath 2.0, dan sayangnya browser hanya memiliki dukungan untuk 1.0.
Todor Minakov
-19

Coba ini. Sangat mudah:

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

Ini benar-benar bekerja untuk saya di driver web selenium.

Amit
sumber
9
Ini tidak berfungsi jika teks dihasilkan oleh JavaScript.
palacsint
2
Ini adalah cara yang sangat baik untuk memeriksanya, karena Anda mentransfer seluruh isi halaman melalui kabel. Untuk halaman yang sangat kecil ini dapat diterima tetapi untuk halaman yang sangat besar Anda mentransfer semua konten file dan memeriksa di sisi server. Pendekatan yang lebih baik adalah melakukannya di sisi klien dengan xpath, javascript atau css.
thomas.han
Saya akan berpikir bahwa seluruh sumber halaman sudah harus ditransfer melalui kabel agar browser membuatnya?
René
3
Josh bertanya bagaimana menemukan elemen dengan teks, bukan untuk menguji apakah teks ada di sumber halaman.
Cedric
1
Untuk contoh di mana semua yang diperlukan adalah untuk menemukan teks statis pada halaman, solusi ini cukup baik. (Ini membantu dalam kasus saya).
Karlth