Programming

[python] Selenium - 웹페이지 링크로 페이지 이동 - find_element와 ExpectedConditions 응용

IT오이시이 2023. 5. 4. 17:30
728x90

Selenium은 웹 애플리케이션 테스트 자동화 도구입니다. 
Selenium은 테스트를 자동화하는 데 매우 유용하며, 웹 애플리케이션 개발자, QA 엔지니어, 소프트웨어 테스트 엔지니어 등에게 많이 사용됩니다. Selenium을 사용하면 반복적이고 시간이 많이 소요되는 테스트를 자동화하여 작업 시간과 노력을 절약할 수 있습니다.
웹 애플리케이션을 테스트하고 검증하는 데  Selenium WebDriver라는 API를 사용하여 브라우저를 제어하고, 테스트를 자동화할 수 있습니다.
일반적인 웹페이지 에서는 작동이 잘 되지만 특정 조건에 따라 페이지 내용이 달라지는 동적 웹페이지 같은 경우 오류 대처를 위한 방법으로 작성을 해보았습니다.

 

[python] Selenium 웹스크래핑 - 웹페이지 자동화 테스트
- 웹페이지 객체 찾는 방법 정리 - https://couplewith.tistory.com/427
- 웹페이지 링크 찾고 이동하기 -  https://couplewith.tistory.com/428 
- 웹페이지 크롤링- 제목과 내용 수집하기 -  https://couplewith.tistory.com/424

 

- 웹페이지 링크로 이동 -

 

[python] Selenium - 동적 웹페이지에서 객체 찾고 이동 하기 - find_element와 ExpectedConditions 기초

 
셀레니움은 웹 페이지를 자동으로 이동하거나 값을 입력하고 전송하거나,  페이지에 이벤트를 실행 할 수 있습니다. 예를 들어 로그인 화면에 아이디와 패스워드를 입력하고 로그인 버튼을 누른다든지 아니면 웹페이지 게시물에 댓글을 달거나 좋아요 버튼을 누르는 등을 할 수 있습니다. 이것을 하기 위해서는 객체를 찾고 클릭 이벤트를 실행해야  합니다.

웹페이지의 특정 요소를 찾고 링크나 버튼 같은 객체를 찾고 클릭하는 방법과 관련된 예외 처리에 대하여  정리하였습니다.


일반적인 Static html에서는 쉽겠지만 동적 웹페이지에서는 웹페이지 내용이 다양하게 변경되므로  예외처리와 객체가 없는 상황 대처도 필요 합니다.

찾는 페이지 요소에 따라 다른 방식을 채택해야 할 것 같고, 선택하는 방식도 상황에 맞게 정리해야 할 것 같습니다.
 
웹페이지의 요소를 찾는 부분은 예시를 들어 (https://couplewith.tistory.com/427) 를 참고 하면 됩니다. 그런데 페이지 크롤링을 하다가  웹 페이지에 따라서 실행이 잘 되다가도  오류  Exception 상황이 되는 내용도 함께 정리를 해봅니다.
 

- 주요 내용 목차 -

1. 웹페이지 소스에서 요소를 찾는 방법(1) - find_element* 
2. 웹페이지 화면에서 보이는 요소를 찾는 방법 (2) - ExpectedConditions

3. 웹페이지 객체(링크)를 찾고 해당 객체(링크)를 클릭하여 이동하는 방법 : .click()
4. 웹페이지 링크 텍스트를 찾아 다른 페이지로 이동하는 방법 
5. Try ~ except 문을 이용한 페이지 오류 대처 방법
6. 화면에 보이는 클래스나 CSS Path로 Element 를 찾는 방법 : Visibility_of_element_located

 

 1. 웹페이지 소스에서 요소를 찾는 방법(1) - find_element* 

 
아래 예시는 html 소스의 구조에서 객체를 찾는 방법입니다. 즉 웹페이지의 소스가 Ajax또는 동적으로 작성이 완료 되었을때 실행 가능 합니다.
find_element*는 문자열이든 xpath, css 태그로도 객체를 찾을 수 있습니다. (  find_element 와 ' By.* ' 에 대한 설명은 이전 게시물을 참고 바랍니다. : https://couplewith.tistory.com/427)
다만 객체가 없거나 늦게 로딩이되면 오류가 발생합니다.

1)  find_*로 문자열이 일치하는 영역 찾기 : find_element() 및 find_elements() 를 이용하여 객체를 찾는 방법이 권장 됩니다.

driver.find_element(By.partialLinkText("여기")).click();

elements = driver.find_elements(By.partialLinkText("여기"))
for element in elements:
      element.click()

 
2) 문자열이 부분적으로 일치하는 영역 찾기 (`여기`라는 문구가 포함된 영역)
  ' find_element* ' 는 위와 같은 함수 인데 Deprecated예정입니다.

driver.find_element_by_partial_link_text("여기").click()

 
*  최근 Selenium 4에서는 이들 메소드가 대체될 예정이며, 새롭게 개발된 find_element() 및 find_elements() 메소드를 사용할 것을 권장하고 있으며  find_element_by_***() 는 Deprecated 될 예정입니다.
 

 

2. 웹페이지 화면에서 보이는 요소를 찾는 방법 (2) - ExpectedConditions

 
Selenium의 ExpectedConditions는 웹 애플리케이션 테스트 시  특정 조건에 따라 수행 하는 방법으로 자주 쓰이는 클래스입니다. 이 클래스를 사용하면 애플리케이션이 특정 조건을 충족할 때까지 대기하고, 조건이 충족되면 다음 단계로 이동할 수 있습니다.

아래 두가지 방법은  웹페이지에 찾을 객체가 없을 경우도 있다는 가정으로  웹화면에서 객체의 위치를 찾는 방법입니다.

* EC.visibility_of_element_located 와 EC.element_to_be_clickable 는 

ExpectedConditions 을 이용한 방법으로  `visibility_of_element_located` 는 요소가 화면에 보이는(visible) 상태일 때,  `element_to_be_clickable `는 요소가 클릭 가능한(clickable) 상태 인지를 확인 합니다.

결국 두가지 모두 화면에 해당 요소가 보이는 상태를 확인하는 것에는 같이 사용이 가능하고, 추가로 클릭이 가능 한지 확인 하는 경우에  `**clickable` 을 사용하는 차이로 보면 됩니다.

EC.visibility_of_element_located()
 - 화면에 보이는(Visible) 상태를 확인

EC.element_to_be_clickable()
 - 화면에 요소가 보이고 클릭 가능한지 확인

 
다음과 같이 CSS_SELECTOR 를 이용한 페이지 요소 선택 방법을 활용 할 수 있습니다.

# EC.visibility_of_element_located : 화면에 보이면 작동(5초대기)
WebDriverWait(driver, 5 ).until( EC.visibility_of_element_located( (By.CSS_SELECTOR, 'div.uoc-icon') ))

# EC.element_to_be_clickable : 클릭이 가능하면 작동 (5초대기)
WebDriverWait(driver, 5 ).until( EC.element_to_be_clickable( (By.CSS_SELECTOR, 'div.uoc-icon') ))

 
 

2.1 동적 웹 페이지 크롤링시 고려 해야 하는 오류  예외 처리 

 
* 해당 요소가 화면에 보이는 속도가 느리거나, 실제 요소가 화면에 없거나,  웹페이지가 변경 되는 경우 등에 대한 대비가 필요합니다. 화면에 보이거나 클릭이 가능한 상태를 확인하는데 5초간 기다리고 작동 하도록 하는 예외 처리도 가능합니다.

웹페이지 크롤링 시 고려해야 하는 오류
  1. 페이지에 요소(element)가 없거나, 페이지 오류가 발생한 경우
  2. 웹브라우저 랜더링이 느린경우
  3. 페이지 내용이 변경된 경우 

 
 

2.2 동적 웹페이지 화면에서 요소를 찾는 예시

 
해당 요소가 없거나 페이지 로딩이 느릴 경우 Timeout이 예외 발생되는 것을 대비해야 합니다.  아래와 같이 예외 이벤트가 발생됨을 이용해서 Try ~ except ~ finally 문으로  정리 하였습니다.
 

from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.common.exceptions import TimeoutException

driver.get("https://example.com", verify=False)

try:
    # 요소가 화면에 보이는(Visible) 상태가 될 때까지 대기하고 클릭
    element = WebDriverWait(driver, 10).until( EC.visibility_of_element_located( (By.CSS_SELECTOR, 'div.uoc-icon')))
    element.click()

    # 요소가 클릭 가능한 상태가 될 때까지 대기하고 클릭
    element = WebDriverWait(driver, 10).until( EC.element_to_be_clickable( (By.CSS_SELECTOR, 'div.uoc-icon')))
    element.click()

except TimeoutException as e:
    print("TimeoutException occurred:", e)
    
finally:
    driver.quit()

 
 

3.   웹페이지 객체(링크)를 찾고 해당 객체(링크)를 클릭하여 이동하는 방법 - .click()

- 다음과 같이 직접적인 html element를 찾고 해당 객체를 클릭하는 방법도 있습니다.
그러나 특정 페이지 내용이 상황에따라 바뀌거나 브라우저에 출력되는 시간과  달라서 객체를 찾지 못는 상황도 고려 해야 합니다.
웹페이지의 링크를 찾고 클릭을 하면 실제 페이지가 이동하거나 내용이 바뀔수 있습니다. 이럴 경우 "ExpectedConditions "를 사용 하면 됩니다.

# 1. find_element 로 웹 링크를 찾고 클릭하는 방법
driver.find_element(By.PARTIAL_LINK_TEXT, "click here").click()

# 2. ExpectedConditions 으로 웹 링크를 찾고 클릭하는 방법
link = WebDriverWait(driver, 10).until(EC.presence_of_element_located((By.LINK_TEXT, link_text)))
ink.click()

 

 

4. 웹페이지 링크 텍스트를 찾아 다른 페이지로 이동하기 

 
   다음과 같이 웹페이지 링크의 이름이 "click here" 라는 위치를 찾고 해당 링크를 클릭하는 방법입니다.

 

4.1  Selenium을 이용한 웹페이지 링크로 다른 페이지로 이동하는 방법

 
1) 웹드라이버의 환경 설정으로 SSL에 대한 예외 상황을 처리 하도록 하였습니다.

# 웹드라이버 option 설정 (생락가능)
options = webdriver.ChromeOptions()
options.add_argument('--ignore-certificate-errors')
options.add_argument(user_agent)

 
2) 웹브라우저에 웹 페이지를 로딩합니다.

# 웹페이지 열기
driver.get('https://example.com')
driver.implicitly_wait(4) # default 0 seconds : implicitly_wait

 
3) 웹브라우저에서 "Click here" 라는 문장을 가진 링크를 찾아 클릭을 합니다.

# 링크의 텍스트를 찾기
link_text = 'click here'

# 링크를 찾아서 클릭
link = WebDriverWait(driver, 10).until(EC.presence_of_element_located((By.LINK_TEXT, link_text)))
ink.click()

 
4)  간단한 웹페이지 링크 호출 소스 예시

from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC


user_agent  = '--user-agent=Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/90.0.4430.85 Safari/537.36'

# 웹드라이버 option 설정 (생락가능)
options = webdriver.ChromeOptions()
options.add_argument('--ignore-certificate-errors')
options.add_argument(user_agent)

# 웹드라이버 설정
# driver = webdriver.Chrome('/path/to/chromedriver')
driver = webdriver.Chrome(options=options)


# 웹페이지 열기
driver.get('https://example.com')
driver.implicitly_wait(4)  # default 0 seconds : implicitly_wait


# 링크 텍스트 찾기
link_text = 'Click here'

# 링크를 찾아서 클릭
link = WebDriverWait(driver, 10).until(EC.presence_of_element_located((By.LINK_TEXT, link_text)))
link.click()

# 웹드라이버 종료
driver.quit()

 

 

5.  Try ~ except  문을 이용한 페이지 오류 대처  방법

  - 페이지가 로딩되면 찾고자 하는 Element가 없을 수도 있기 때문에 Except 문을 이용해서 예외 처리가 필요합니다.

from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC


user_agent  = '--user-agent=Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/90.0.4430.85 Safari/537.36'

# 웹드라이버 option 설정 (생락가능)
options = webdriver.ChromeOptions()
options.add_argument('--ignore-certificate-errors')
options.add_argument(user_agent)

# 웹드라이버 설정
# driver = webdriver.Chrome('/path/to/chromedriver')
driver = webdriver.Chrome(options=options)


# 웹페이지 열기
driver.get('https://example.com')
driver.implicitly_wait(4)  # default 0 seconds : implicitly_wait


# 링크 텍스트 찾기
link_text = 'Page 2'

# 링크를 찾아서 클릭
try:
    element = WebDriverWait(driver, 10).until(EC.presence_of_element_located((By.LINK_TEXT, "Page 2")))
    element.click()
    print("Clicked on Page 2 link")
except NoSuchElementException:
    print("Page 2 link not found")


# 웹드라이버 종료
driver.quit()

 

 

6. 화면에 보이는 클래스나 CSS Path로 Element 를 찾는 방법  Visibility_of_element_located


페이지의 HTML 구조를 정확하고 확실하게 알 수 있다면 페이지의 Class 명이나 CSS Path로  찾는 것이 효과적입니다. 이때 By.CSS_SELECTOR,  By.CLASS_NAME 를 이용하면 됩니다. 다만 페이지 구조가 바뀌거나 유형이 다양한 경우에는 계속 확인이 필요합니다.

 EC.visibility_of_element_located((By.CSS_SELECTOR, 'div.uoc-icon')))

 

# 웹드라이버 설정
driver = webdriver.Chrome('/path/to/chromedriver')

# 웹페이지 열기
driver.get('https://example.com')
driver.implicitly_wait(4)  # default 0 seconds : implicitly_wait

# 페이지 아래까지 스크롤 합니다.
driver.execute_script("window.scrollTo(0, document.body.scrollHeight);")

# 페이지 파싱 및 제목 추출
page_soup = BeautifulSoup(driver.page_source, 'html.parser')
page_title = page_soup.title.text
print(no, page_title, page_url)

# 페이지 특정 CSS SELECTOR 영역을 선택하고 클릭 click()
try:
        like_button = WebDriverWait(driver, 5).until(
            EC.visibility_of_element_located((By.CSS_SELECTOR, 'div.uoc-icon')))
        like_text = like_button.text.strip()
        
        # (방법1) 요소를 찾고 클릭
        like_button.click()
        
        # (방법2) 요소를 찾고 클릭할 수 있는 위치로 이동
        ActionChains(driver).move_to_element(like_button).perform()
        # 클릭 실행
        ActionChains(driver).click().perform()
except TimeoutException:
       #like_button = driver.find_element(By.CSS_SELECTOR, 'div.uoc-icon.empathy_up_without_ani.like_on')
       print("Like button is not found.")
except ElementClickInterceptedException:
       print("ElementClickInterceptedException: Like button is not clickable.")

 
[설명]
위 코드에서는 페이지에서 `div.uoc-icon` 이라는 CSS Selector를 가진 요소를 찾아 클릭을 하는 예시입니다.
(1) WebDriverWait 함수를 사용하여 해당 요소가 페이지에 나타날 때까지 최대 5초를 기다리도록 설정했습니다. 5초 이내 해당 요소를 찾지 못하는 경우 TimeoutException이 예외가 발생하는 경우를 대비하여  Try문을 사용 하였습니다. 

(2) 이때 "Like button is not found." 라는  메시지가 출력하고 종료 하는 것입니다.

(3) 해당 요소가 페이지에 없거나 잘못된 CSS Selector를 사용했을 경우  WebDriverWait 함수의 시간 제한이 너무 짧았거나 인터넷 연결이 느렸을 경우 해결 방법입니다.

(4) `div.uoc-icon` 를 찾은 경우  해당 요소의 Text를 조회 합니다. like_text = like_button.text.strip()

(5)  찾은 요소를 클릭 click()으로 클릭을 합니다. like_button.click()
      # 클릭 예외 사항 "exception ElementClickInterceptedException" 를 추가 하였다.

(6) 해당요소를 찾고 클릭하는 다른 방법으로 ActionChains를 사용하여 해당 요소로 이동을 합니다.
       ActionChains(driver).move_to_element

(7) 찾은 요소에 클릭을 실행합니다. ActionChains(driver).click().perform()
   - 다음과 같이 해당 링크를 찾고 클릭을 하는 방법은 두가지 가 있습니다.

like_button = WebDriverWait(driver, 5).until( EC.visibility_of_element_located((By.CSS_SELECTOR, 'div.uoc-icon')))

# (방법1) 요소를 찾고 클릭
like_button.click()

# (방법2) 요소를 찾고 클릭할 수 있는 위치로 이동하여 클릭 실행
ActionChains(driver).move_to_element(like_button).perform()
ActionChains(driver).click().perform()

 
 
[참고]
1. Find Element by Partial Link Text using Selenium : https://pythonexamples.org/python-selenium-find-element-by-partial-link-text/
2.Locating Hyperlinks by Link Text :  https://selenium-python.readthedocs.io/locating-elements.html

728x90
반응형