Selenium Webdriver (Python)에서 특정 텍스트가 포함 된 요소를 찾으려면 어떻게합니까?


259

Selenium (Python 인터페이스 사용 및 여러 브라우저에서)으로 복잡한 Javascript 인터페이스를 테스트하려고합니다. 양식의 여러 버튼이 있습니다.

<div>My Button</div>

"My Button"(또는 "my button"또는 "button"과 같이 대소 문자를 구분하지 않는 부분 일치)을 기반으로 버튼을 검색하고 싶습니다.

나는 명백한 것을 놓치고 있다고 느끼는 정도로 놀랍도록 어려운 것을 발견하고 있습니다. 내가 지금까지 가장 좋은 것은 :

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

그러나 이것은 대소 문자를 구분합니다. 내가 시도한 또 다른 것은 페이지의 모든 div를 반복하고 element.text 속성을 확인하는 것입니다. 그러나 다음과 같은 상황이 발생할 때마다 :

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

div.outer에는 "My Button"도 텍스트로 사용됩니다. 그 문제를 해결하기 위해 div.outer가 div.inner의 부모인지 확인하려고했지만 그 방법을 알 수 없었습니다 (element.get_element_by_xpath ( '..')는 요소의 부모를 반환하지만 div.outer와 같지 않은 테스트). 또한 적어도 Chrome 웹 드라이버를 사용하면 페이지의 모든 요소를 ​​반복하는 것이 실제로 느린 것 같습니다.

아이디어?

편집 :이 질문은 약간 모호하게 나왔습니다. 더 구체적인 버전을 여기 에서 묻고 대답했습니다 : 자식 요소 텍스트를 포함하지 않고 Selenium WebDriver에서 요소를 텍스트로 얻는 방법 (파이썬 API를 통해)?


현재 답변이 효과가 없었습니다. 이 사람은 한 : sqa.stackexchange.com/a/2486을
알레한드로

답변:


328

다음을 시도하십시오 :

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

3
답장을 보내 주셔서 감사합니다. 제가 필요한 것의 50 %였습니다 (시작). 내가 도착한 형식은 "(// * [contains (text (), '"+ text + "')] | // * [@ value = '"+ text + "'])"입니다. 요소 노드 내부뿐만 아니라 'value'속성을 통해 텍스트가 설정된 입력 요소 내부에도 텍스트가 제공됩니다 (예 : <button value = "My Button"/>). 참고하지만 값은 텍스트 만 포함하는 것이 아니라 엄격하게 일치해야합니다.
Ivan Koshelev

9
또한 다른 검색 엔진 방문자에게도 언급 할 가치가 있습니다. 링크를 찾고 있다면 방법 find_element(s)_by_link_textfind_element(s)_by_partial_link_text방법이 있습니다
Dan Passaro

3
텍스트가 동적이면 어떻게 되나요? 즉, 따옴표가 포함될 수 있습니다. 이 방법으로 문제가 해결되지 않습니까?
IcedDante

3
특정 이름을 검색하면 문제가 발생하는 것 같습니다. 예를 들어 다음을 보자. "// * [contains (text (), '"+ username + "')]"if username = "O'Reilly"; 그러면 xpath가 유효하지 않게됩니다. 이 주위에 방법이 있습니까?
Sakamoto Kazuma

대상 텍스트에 여러 줄이 있으면 작동하지 않는 것 같습니다.
Shawn

29

다음과 같은 xpath를 시도 할 수 있습니다.

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

고맙습니다 ... 그래서 inner와 outer를 구별하는 데 도움이되지만 실제로 xpath와 잘 작동합니다. 모든 div를 반복하는 문제 만있었습니다. xpath의 내 문제는 대소 문자를 구분하지 않는 방법을 알 수 없다는 것입니다.
josh

2
이 작동해야하므로 XPath는 2.0 소문자 기능을 갖고, 「// DIV [포함 (소문자 (텍스트 ()) "{0} ')] 포맷 (텍스트).
andrean

감사! 비록 내 이해는 xpath 2.0이 주요 브라우저에서 지원되지 않는다는 것입니다.
josh josh

selenium은 브라우저 고유의 방법으로 xpath 식을 직접 평가하므로 셀레늄과 함께 사용중인 브라우저에 따라 다릅니다. 일반적으로 6, 7 및 8 만 xpath 2.0을 지원하지 않아야합니다.
andrean

.format내 일식에서 인식되지 않습니다. 그것은주고 오류. 어떤 생각, 왜?
anujin

16

페이지 객체 패턴과 함께 사용할 수도 있습니다. 예 :

이 코드를 사용해보십시오 :

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

13

// *는 HTML 태그를 찾습니다. Button 및 div 태그에 공통적 인 텍스트가 있고 // *가 범주 인 경우 예상대로 작동하지 않습니다. 특정을 선택해야하는 경우 HTML 요소 태그를 선언하여 가져올 수 있습니다. 처럼:

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

5

흥미롭게도 거의 모든 답변은 xpath의 기능 과 관련이 있으며 OP의 요청과 달리 contains()대소 문자를 구분 한다는 사실을 무시합니다 .
대소 문자를 구분하지 않으면 xpath 1.0 (현대 브라우저가 지원하는 버전) 에서 달성 할 수 있지만 translate()기능 을 사용하는 것은 좋지 않습니다 . 변환 표를 사용하여 소스 문자를 원하는 형식으로 대체합니다.

모든 대문자 문자의 테이블을 구성하면 노드의 텍스트를 효과적으로 더 낮은 () 형식으로 변환하여 대소 문자를 구분하지 않는 일치를 허용합니다 (여기서는 특권이 있습니다) .

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

전체 파이썬 호출 :

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

당연히이 방법에는 단점이 있습니다. 주어진 바와 같이 라틴어 텍스트에 대해서만 작동합니다. 유니 코드 문자를 다루려면 번역 테이블에 해당 문자를 추가해야합니다. 위 샘플에서 마지막 문자는 키릴 문자입니다 "Й".


그리고 브라우저가 xpath 2.0 이상을 지원하는 세계에 살았다면 (곧 올 수는 없지만) , lower-case()(로케일을 완전히 인식하지는 못함) 기능을 사용할 수 있었으며 matches(정규 검색을 위해 경우에 따라) -둔감 한 ( 'i') 플래그).


3

제공 한 HTML에서 :

<div>My Button</div>

텍스트 My ButtoninnerHTML주위에 공백이 없으므로 text()다음과 같이 쉽게 사용할 수 있습니다 .

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

참고 : text()컨텍스트 노드의 모든 텍스트 노드 자식을 선택합니다


선행 / 후행 공백이있는 텍스트

시작 부분에 공백이 포함 된 관련 텍스트를 넣으십시오 .

<div>   My Button</div>

또는 끝에 :

<div>My Button   </div>

또는 양쪽 끝에서 :

<div> My Button </div>  

이 경우 두 가지 옵션이 있습니다.

  • contains()첫 번째 인수 문자열에 두 번째 인수 문자열이 포함되어 있는지 여부를 판별하고 다음과 같이 부울 true 또는 false를 리턴 하는 함수를 사용할 수 있습니다 .

    my_element = driver.find_element_by_xpath("//div[contains(., 'My Button')]")
  • normalize-space()문자열에서 선행 및 후행 공백을 제거하고 공백 문자 시퀀스를 단일 공백으로 바꾸고 결과 문자열을 다음과 같이 반환하는 함수를 사용할 수 있습니다 .

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

변수 텍스트에 대한 xpath

텍스트가 변수 인 경우 다음을 사용할 수 있습니다.

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

비슷한 문제 : 찾기 <button>Advanced...</button>

어쩌면 이것은 당신에게 몇 가지 아이디어를 줄 것입니다 (개념을 Java에서 Python으로 옮기십시오) :

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


-19

이 시도. 이것은 정말 쉽습니다:

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

이것은 실제로 셀레늄 웹 드라이버에서 효과적이었습니다.


9
JavaScript로 텍스트를 생성하면 작동하지 않습니다.
palacsint

2
와이어를 통해 페이지의 전체 내용을 전송하기 때문에 이것은 확인하는 매우 좋은 방법입니다. 매우 작은 페이지의 경우 허용되지만 매우 큰 페이지의 경우 파일의 모든 내용을 전송하고 서버 측에서 확인합니다. 더 나은 방법은 xpath, javascript 또는 css를 사용하여 클라이언트 측에서 수행하는 것입니다.
thomas.han

브라우저가 렌더링하기 위해 전체 페이지 소스를 와이어로 전송해야한다고 생각합니까?
René

3
Josh는 텍스트가 페이지 소스에 있는지 테스트하지 않고 텍스트로 요소를 찾는 방법을 묻습니다.
Cedric

1
모든 것이 필요한 경우 페이지에서 정적 텍스트를 찾는 것이이 솔루션으로 충분합니다. (제 경우에 도움이되었습니다).
Karlth
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.