Selenium으로 테스트를 하거나 매크로를 만들다보면 간혹 ElementNotVisibleException
에러가 발생합니다. 잘 동작하는 코드였는데 어쩔때는 이런 에러를 발생시키며 동작하지 않을 때가 있습니다. 이유는 Ajax 등으로 웹페이지가 로딩되는 시간 차이가 있기 때문입니다. 그래서 페이지 로딩이 완료되지 않은 상태에서 find_element_by_id
등으로 존재하지 않은 아이템을 찾으려고 하니 이런 에러가 발생할 수 밖에 없습니다.
해결 방법은 페이지가 로딩될 때까지 기다리는 것입니다.
Selenium은 다음 두가지 방법의 wait을 제공합니다.
- Implicitly wait: 정해진 시간만큼 충분히 기다리기
- Explicitly wait: 어떤 조건이 만족할 때까지 기다리기
Implicitly wait
Implicitly wait을 10초로 설정하면 페이지가 로딩되는데 10초까지 기다립니다. 만약 페이지 로딩이 2초에 완료되었다면 더 기다리지 않고 다음 코드를 수행합니다. 기본 설정은 0초로 되어있고, 한번만 설정하면 driver를 사용하는 모든 코드에 적용이 됩니다.
아래 코드처럼 get을 호출하기 전에 wait 시간을 10초로 설정하면, get이 페이지가 모두 로딩될 때까지 기다린 후 find_element_by_id
으로 element를 찾습니다.
from selenium import webdriver
driver = webdriver.Chrome("chrome path")
driver.implicitly_wait(10) # seconds
driver.get("http://somedomain/url_that_delays_loading")
myDynamicElement = driver.find_element_by_id("myDynamicElement")
Explicitly wait
Explicitly wait은 명시적으로 어떤 조건이 성립했을 때까지 기다립니다. 조건이 성립하지 않으면 timeout으로 설정된 시간만큼 최대한 기다립니다.
다음 코드는 ID가 someid인 element가 clickable이 될 때까지 기다리고, 그 element를 리턴하는 코드입니다. get() 코드 다음으로 wait.until() 코드를 추가하시면 됩니다. wait.until()은 특정 조건이 만족될 때까지 기다리고 그 element를 리턴합니다.
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
driver = webdriver.Chrome("chrome path")
driver.get("http://somedomain/url_that_delays_loading")
# wait until someid is clickable
wait = WebDriverWait(driver, 10)
element = wait.until(EC.element_to_be_clickable((By.ID, 'someid')))
먼저 WebDriverWait 객체를 생성합니다. 인자로 driver와 timeout이 들어갑니다. 이 객체는 재사용할 수 있기 때문에 전역에 객체를 만들고 그 이후에 재사용하면 좋습니다.
조건을 설정하는 방법은 wait.until(조건)
처럼 인자에 기다릴 조건을 넣으시면 됩니다.
위의 예제에서 조건에 해당하는 것은 아래 코드인데요. ID가 someid인 element가 clickable이 될 때까지 기다린다는 의미입니다.
EC.element_to_be_clickable((By.ID, 'someid')
아래 코드 처럼 By를 변경하여 class name이나 name으로 element를 찾게 할 수도 있습니다.
EC.element_to_be_clickable((By.CLASS_NAME, 'some_classname')
EC.element_to_be_clickable((By.NAME, 'some_name')
clickable이 싫다면 아래 처럼 element_to_be_clickable
를 다른 조건으로 변경할 수도 있습니다.
EC.title_is(...)
EC.title_contains(...)
EC.presence_of_element_located(...)
EC.visibility_of_element_located(...)
EC.visibility_of(...)
EC.presence_of_all_elements_located(...)
EC.text_to_be_present_in_element(...)
EC.text_to_be_present_in_element_value(...)
EC.frame_to_be_available_and_switch_to_it(...)
EC.invisibility_of_element_located(...)
EC.element_to_be_clickable(...)
EC.staleness_of(...)
EC.element_to_be_selected(...)
EC.element_located_to_be_selected(...)
EC.element_selection_state_to_be(...)
EC.element_located_selection_state_to_be(...)
EC.alert_is_present(...)
모든 코드에 적용되는 implicitly wait과 다르게, explicitly wait은 코드를 넣은 위치에서만 기다립니다.
참고
Related Posts
- Python - Yaml 파일 파싱하는 방법
- Python - pip와 requirements.txt로 패키지 관리
- 유튜브 쇼츠(Shorts) 자막 끄기/켜기
- SOLID 원칙, 객체지향 설계 5가지 원칙
- Ubuntu 20.04 - Nginx로 React를 배포하는 방법
- 애드센스 '구글 검색 기능' 블로그에 추가
- 트위터 이메일 안오게, 알림 끄기
- 인스타그램 동영상, 사진 저장 방법
- Git 설치 방법 (Ubuntu, Windows)
- Python pip 설치 (Ubuntu / Windows)
- 마우스 우클릭 복사 방지 해제 방법 (크롬)
- Python 에러 해결, 'conda' 용어가 cmdlet, 함수, 스크립트 ... 인식되지 않습니다.
- Python 에러 해결, AttributeError: module 'jwt' has no attribute 'encode'
- Atom - 코드 자동 정렬
- Sublime Text - 코드 자동 정렬, 단축키 설정
- VSCode에서 탭 간격 설정 (Tab to 4 spaces)
- Visual Studio Code에서 코드 자동 정렬
- 구글 검색 기록 삭제, 자동 저장 끄기 (PC, 모바일)
- 안드로이드 개발자 옵션 활성화, USB 디버깅 켜기
- 유튜브 채널 차단, 해제 방법 (PC, 모바일)
- 유튜브 미리보기 자동재생 끄기 (자동 소리 끄기/켜기)
- PC에서 유튜브 모바일 버전(m.youtube.com)으로 보기
- 모바일에서 유튜브 PC버전으로 보기
- 유튜브 시간 링크 만들기, 댓글에 시간 태그 입력하기
- 유튜브 스크립트 함께 보기, 자막 추출 방법
- 유튜브 알고리즘 초기화, 검색 기록과 시청 기록 삭제
- 유튜브 '싫어요' 숫자 다시 보이게 하기
- 구글 크롬, 방금 닫은 탭 다시 열기
- Maven으로 Java프로젝트 build하는 방법
- node.js, npm 버전 확인 방법 (터미널, cmd 명령어)
- GitLab - 'pre-receive hook declined' 에러 해결
- Javacript Heap Out Of Memory 문제 해결
- SSH key 생성하고 GitHub에 등록
- GMT, UTC의 차이점
- Linux(Ubuntu)에 Adobe Photoshop, Illustrator 설치하는 방법