Programming

[python] Selenium - implicitly wait 과 explicitly wait 이해

IT오이시이 2023. 5. 25. 15:59
728x90

[python] Selenium - implicitly wait 과 explicitly wait 이해

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

 
Selenium 글의 소개

[Selenium 을 배워 가는 이유는 ?]

아시는 분들도 있겠지만  어려운 분들도 있어서 간단한  정리해 봅니다.

Selenium은 자동으로 웹페이지를 호출하고 페이지의 버튼이나 입력을 할수 있도록 프로그램을 만드는 도구 입니다.

예를 들어 뉴스나 블로그를 읽고 좋아요 버튼을 누른다든지 댓글을 달 수 도 있습니다.
선거철 사회적 문제가 되었던 "댓글부대 드루킹 " 등과 같은 악용 사례도 이런 기술을 이용하면 됩니다.

최근에는 빅데이터 수집과 인공지능을 위해서 다양한  데이터 수집과 분석을 합니다.
여기에서 실시간으로 변화하는 다양한 데이터을 수집하려면 웹서비스에 로그인하고 파일을 받는다든지,  쇼핑몰의 인기 상품이나, 중요한 뉴스의 이슈를 찾는 다든지 등을 빠르게 처리 하려면 사람보다는 자동화가 필요합니다.

2000년 인터넷 검색 초창기에는 "웹서퍼"라는 직업이 있었어요. 전세계 웹페이지를 읽고 분류해서 Directory 서비스를 만드는 것이었지요. 그 작업을 하려면 Web Crawler 같은 도구가 필요 했어요. 그 당시는 검색 개발자가 프로그램을 직접 짰지만 지금은 Selenium과 같은 라이브러리를 사용하면 정말 개발이 꿀같이 쉬워 집니다.

Selenium 은 그런 웹페이지의 데이터와 관련된 일을 할수 있는 프로그램 도구 입니다.

AI를 위한 데이터 수집과 관리를 위해서 다양한 웹 사이트의 데이터를 수집하거나, CRM이나 마케팅에서 고객의 반응을 빠르게 받고 응답하거나,  고객센터 Q&A 게시판에 올라오는 글을 처리하는 등  각종 관리페이지의 데이터 처리를 하기위해 RPA (Robot Processing Automation) 같은 업무 자동화에도 사용이 됩니다. ^^


 

Selenium  에서 접하는 Wait 정리

- 페이지의 Element 또는 페이지 로딩, 작업의 수행을 위해 Wait은 다양한 방법으로 구현이 가능합니다. Wait 관련해서  정리해 보았습니다.

Selenium이 작동하려면 웹페이지  로딩이 필요 합니다. 주로 웹페이지의 특정 Element를 찾아야 하는데 페이지가 완전히 로딩이 되어야 합니다.  웹페이지는 여러 자바스크립트, 스타일시트, 이미지, Ajax 등이 포함되어 동적으로 구현 되는데 네트웍 속도와 브라우저 성능에 따라 페이지 마다 로딩 속도가 다릅니다.

이런 페이지의 콘텐츠 리소스를 Selenium이 인식 하려면 약간의 Wait이 필요하고 각양 각색의  페이지들은 계속 수정되어 해당 Element가 없을 수도 있는데.
Selenium 은 페이지에 있는지 없는지 판단이 안되므로 여기의 Wait으로 판단하는데 사용합니다.


웹페이지 로딩되는데는 일정 시간이 필요하여 Wait으로  Selenium 을 제어 할 수 있습니다.


 

1.  Implicitly wait :  n 초이내 대기


Implicitly Wait(driver.implicitly_wait) 는 Selenium WebDriver에서 기본적으로 제공되는 기능입니다.
이 기능을 사용하면 WebDriver는 요청한 작업(요소 찾기, 페이지 이동 등)을 수행하기 전에 일정 시간 동안 기다립니다. 이 시간 동안 WebDriver는 페이지의 로딩을 기다리며, 요소가 로드될 때까지 자동으로 대기합니다.

Implicitly wait을 10초로 설정하면 페이지가 로딩되는데 10초까지 기다립니다.
만약 페이지 로딩이 2초에 완료되었다면 더 기다리지 않고 다음 코드를 수행합니다.

기본 설정은 0초로 되어있고, 한번만 설정하면 driver를 사용하는 모든 코드에 적용이 됩니다.

driver.implicitly_wait(10)  # 10초 동안 대기

*  WebDriver는 페이지가 로딩되는데 까지 최대 10초 동안 요청한 작업을 수행도록 기다립니다. 요소가 로드되면 즉시 다음 작업을 수행합니다.


만약 Element 요소가 지정된 시간 내에 로드되지 않거나 없다면 예외가 발생합니다.




 

2. Explicitly wait (expected_conditions)  :  n 초이내 대기

Explicitly wait은 명시적으로 어떤 조건이 성립했을 때까지 대기 합니다. (expected_conditions)
조건이 성립하지 않으면 timeout으로 설정된 시간 만큼 최대한 대기후 timeout Exception으로 넘어 갑니다.
`from selenium.webdriver.support import expected_conditions as EC` 를 선언 이 필요하며, WebDriverWait(driver, 3).until 과 같은 형식으로 구현 합니다.

다음 코드는 웹페이지의 ID가 someid인 element가 clickable이 될 때까지 기다리고, 그 element를 리턴하는 코드입니다. get() 코드 다음으로 wait.until() 코드를 추가하시면 됩니다. wait.until()은 특정 조건이 만족될 때까지 기다리고 그 element를 리턴합니다.

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

wait = WebDriverWait(driver, 10)
element = wait.until(EC.presence_of_element_located((By.ID, 'myElement')))

*위의 예제에서 WebDriverWait 클래스는 최대 10초 동안 기다립니다. 조건이 충족되면(여기서는 'myElement'라는 ID를 가진 요소의 등장) 대기가 종료되고 해당 요소를 반환합니다. 조건이 지정된 시간 내에 충족되지 않으면 예외가 발생합니다.

 

3. time.sleep(n)  : n 초 대기


Selenium의 Wait도 사용을 하지만 절대적으로 지정된 시간만큼 대기를 할때는 time.sleep()을 사용 할 수도 있습니다.  절대적인 특정 시간이 지난 후에 다음 작업이 수행 되어야 하는 경우에는 sleep 를 사용하면 됩니다.

  • 프로그램이 일시적으로 실행을 멈추고 특정 시간 동안 대기해야 할 때
  • 특정 작업이 완료되기를 기다리는 동안 다른 작업을 수행하지 않고 대기해야 할 때
  • 반복문에서 일정한 시간 간격으로 반복 실행을 제어 하고자 할 때

 

import time

print(" > start sleep ")
time.sleep(3)
print(" > 3sec. Stoppd ")

# Next Process

 
 

4.  driver.set_page_load_timeout()


driver.set_page_load_timeout(n)는 Selenium WebDriver에서 사용되는 메서드로, 페이지 로드 시간 제한을 설정하는 데 사용됩니다. 이 메서드를 사용하면 WebDriver는 페이지가 로드되는 데 소비되는 시간이 지정된 제한 시간을 초과하면 예외를 발생시킵니다.

from selenium import webdriver

driver = webdriver.Chrome()
driver.set_page_load_timeout(10)

* 위의 예제에서 driver.set_page_load_timeout(10)을 호출하여 페이지 로드 타임아웃을 10초로 설정합니다. 이때페이지가 10초 안에 로드되지 않으면 TimeoutException 예외를 발생시킵니다.
 
* 페이지 로드 타임아웃을 설정하는 이유는 다음과 같습니다: 

  • 네트워크 지연이나 느린 서버로 인해 페이지 로드가 예상보다 오래 걸릴 수 있습니다.
  • 페이지 로드가 지연되는 경우 불필요한 대기 시간을 피하기 위해 타임아웃을 설정합니다.
  • 페이지 로드가 너무 오래 걸리는 경우에 대비하여 타임아웃을 설정하고 적절한 예외 처리를 수행할 수 있습니다.

 
 

[Implicitly wait과 Explicitly wait  예시]

다음 소스는 블로그 페이지의 제목을 출력하는 예제 입니다. Implicitly wait과 Explicitly wait 을 사용하여 작성 하였습니다.
 

from selenium import webdriver
from selenium.common.exceptions import ElementClickInterceptedException, TimeoutException, \
    UnexpectedAlertPresentException
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from bs4 import BeautifulSoup
import time

start_time = time.time()
def get_elapsed():
    global start_time  # global variable
    end_time = time.time()
    elapsed_time = end_time - start_time
    return " > Elapsed: {:.2f} seconds".format(elapsed_time)

go_url = 'https://couplewith.tistory.com/42'
user_agent = '--user-agent=Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/112.0.0.0 Safari/537.36 Edg/112.0.1722.58'
options = webdriver.EdgeOptions()
options.add_argument('--ignore-certificate-errors')
options.add_argument("--disable-notifications");
options.add_experimental_option("prefs", {"profile.default_content_setting_values.notifications": 1})
options.add_argument(user_agent)
driver = webdriver.Edge(options=options)


page_timeout = 30  # Set a timeout value in seconds
action_timeout = 3  # Set event timeout
no = 0
page_title = ''

driver.set_page_load_timeout(page_timeout)

try:
        driver.get(go_url)
        driver.implicitly_wait(3)  # default 0 seconds : implicitly_wait

        # scroll to the bottom of the page
        driver.execute_script("window.scrollTo(0, document.body.scrollHeight);")
        page_soup = BeautifulSoup(driver.page_source, 'html.parser')
        page_title = page_soup.title.text


        like_button = WebDriverWait(driver, 3).until(EC.element_to_be_clickable((By.CSS_SELECTOR, 'div.uoc-icon')))
        like_text = like_button.text.strip()


        #time.sleep(3)

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. - TimeoutException")
except ElementClickInterceptedException:
        print(">  ElementClickInterceptedException: Like button is not clickable.- ", get_elapsed())
except UnexpectedAlertPresentException:
        print(">  UnexpectedAlertPresentException Alert: 유효하지 않은 요청입니다.- ", get_elapsed())
finally:
        driver.set_page_load_timeout(0)
        print(no, page_title, go_url, like_text, get_elapsed())

 
 

728x90
반응형