Selenium 101
작성일:
Python Selenium 이용한 웹 스크래핑 방법, 웹 자동화
Selenium 가이드: 웹 자동화
1. Selenium 이란?
Selenium은 웹 브라우저 자동화를 위한 아래와 같은 용도
- 웹 애플리케이션 테스트 자동화
- 웹 스크래핑 및 데이터 추출
- 반복적인 웹 작업 자동화
- 크로스 브라우저 테스팅
주요 기능
- 브라우저 제어: 다양한 브라우저에서 웹 페이지를 자동으로 로드하고 조작할 수 있습니다.
- DOM 조작: 웹 페이지의 DOM 요소를 검색하고 조작할 수 있습니다.
- 폼 자동화: 폼을 자동으로 작성하고 제출할 수 있습니다.
- 스크린샷 캡처: 웹 페이지의 스크린샷을 캡처할 수 있습니다.
- 헤드리스 모드: 브라우저 창을 띄우지 않고 백그라운드에서 작업을 수행할 수 있습니다.
Selenium은 다양한 프로그래밍 언어를 지원하며, 웹 개발자와 QA 엔지니어들에게 필수적인 도구로 사용
2. 지원하는 웹 드라이버 종류
Selenium은 다양한 웹 브라우저를 지원합니다. 주요 웹 드라이버는 다음과 같습니다:
- ChromeDriver (Google Chrome)
- GeckoDriver (Mozilla Firefox)
- EdgeDriver (Microsoft Edge)
- SafariDriver (Apple Safari)
- IEDriverServer (Internet Explorer)
각 브라우저의 버전에 맞는 웹 드라이버를 설치해야 합니다.
3. 기본적인 웹 페이지 호출 방법 (Chrome 드라이버 사용)
$ pip install selenium webdriver_manager
Chrome 드라이버를 사용하여 웹 페이지를 호출하는 기본적인 Python 코드는 다음과 같습니다:
from selenium import webdriver
from selenium.webdriver.chrome.service import Service
from webdriver_manager.chrome import ChromeDriverManager
## WebDriver 객체 생성
## ChromeDriverManager().install():
## webdriver_manager 라이브러리는 현재 시스템과 호환되는 ChromeDriver 버전을 찾아서 다운로드
## 다운로드된 ChromeDriver 파일은 로컬에 저장되며, 해당 파일의 경로를 반환
driver = webdriver.Chrome(service=Service(ChromeDriverManager().install()))
## 웹 페이지 열기
driver.get('https://www.example.com')
## 브라우저 종료
driver.quit()
]
4. DOM 을 찾기 위한 find_element
사용법
Selenium은 다양한 방법으로 웹 요소를 찾을 수 있습니다. 주요 메서드는 다음과 같습니다:
메서드 | 설명 |
---|---|
find_element(By.ID, 'id') |
ID 속성으로 요소 찾기 |
find_element(By.NAME, 'name') |
name 속성으로 요소 찾기 |
find_element(By.XPATH, 'xpath') |
XPath로 요소 찾기 |
find_element(By.CSS_SELECTOR, 'css_selector') |
CSS 선택자로 요소 찾기 |
find_element(By.CLASS_NAME, 'class_name') |
클래스 이름으로 요소 찾기 |
find_element(By.TAG_NAME, 'tag_name') |
HTML 태그 이름으로 요소 찾기 |
find_element(By.LINK_TEXT, 'link_text') |
링크 텍스트로 요소 찾기 |
find_element(By.PARTIAL_LINK_TEXT, 'partial_link_text') |
부분적인 링크 텍스트로 요소 찾기 |
By.ID
는 가장 빠르고 신뢰할 수 있는 방법이지만, 모든 요소에 고유한 ID가 있는 것은 아닙니다.By.XPATH
는 매우 유연하지만, 복잡한 XPath는 성능에 영향을 줄 수 있습니다.By.CSS_SELECTOR
는By.XPATH
보다 일반적으로 더 빠르고 읽기 쉽습니다.By.LINK_TEXT
와By.PARTIAL_LINK_TEXT
는 특히 네비게이션 테스트에 유용합니다.
예시
from selenium.webdriver.common.by import By
## ID로 요소 찾기
element = driver.find_element(By.ID, 'search-input')
## 여러 요소 찾기
# 1. ID로 요소 찾기
elements_by_id = driver.find_elements(By.CSS_SELECTOR, '#example-id')
for element in elements_by_id:
print(f"ID: {element.text}")
# 2. 클래스명으로 요소 찾기
elements_by_class = driver.find_elements(By.CSS_SELECTOR, '.example-class')
for element in elements_by_class:
print(f"Class: {element.text}")
# 3. 태그명으로 요소 찾기
elements_by_tag = driver.find_elements(By.CSS_SELECTOR, 'div')
for element in elements_by_tag:
print(f"Tag: {element.text}")
# 4. 계층 구조로 요소 찾기 (자식 요소)
elements_by_hierarchy = driver.find_elements(By.CSS_SELECTOR, 'div > p')
for element in elements_by_hierarchy:
print(f"Hierarchy (child): {element.text}")
# 5. 계층 구조로 요소 찾기 (후손 요소)
elements_by_descendant = driver.find_elements(By.CSS_SELECTOR, 'div p')
for element in elements_by_descendant:
print(f"Hierarchy (descendant): {element.text}")
# 6. 여러 클래스 조합으로 요소 찾기
elements_by_multiple_classes = driver.find_elements(By.CSS_SELECTOR, '.class1.class2')
for element in elements_by_multiple_classes:
print(f"Multiple Classes: {element.text}")
# 7. 속성 값으로 요소 찾기
elements_by_attribute = driver.find_elements(By.CSS_SELECTOR, '[attribute-name="value"]')
for element in elements_by_attribute:
print(f"Attribute: {element.text}")
5. 주요 DOM 조작 기능
find_elements 메서드를 사용하여 여러 요소가 조회되면 모든 일치하는 요소를 리스트(배열)로 처리 해야함
click()
: 요소를 클릭
button = driver.find_element(By.ID, 'submit-button')
button.click()
send_keys()
: 텍스트를 입력
input_field = driver.find_element(By.NAME, 'username')
input_field.send_keys('myusername')
text
: 요소의 텍스트
paragraph = driver.find_element(By.CLASS_NAME, 'content')
print(paragraph.text)
get_attribute
: 요소의 속성 값을 가져옵니다.
link = driver.find_element(By.TAG_NAME, 'a')
href = link.get_attribute('href')
6. 동적 웹 페이지 처리: WebDriverWait 사용
동적 웹 페이지에서는 요소가 즉시 로드되지 않을 수 있습니다. 이런 경우 WebDriverWait를 사용하여 특정 조건이 만족될 때까지 대기할 수 있습니다.
WebDriverWait 기본 사용법
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.common.by import By
# 최대 10초 동안 대기하며, 'a.ClassName' 선택자를 가진 요소가 나타날 때까지 기다립니다.
node = WebDriverWait(driver, 10).until(
EC.presence_of_element_located((By.CSS_SELECTOR, "a.ClassName"))
)
이 코드는 다음과 같은 기능을 수행합니다:
- 최대 10초 동안 대기합니다.
- CSS 선택자 “a.ClassName”에 해당하는 요소가 DOM에 존재할 때까지 기다립니다.
- 요소가 발견되면 해당 요소를 반환합니다.
- 지정된 시간 내에 요소가 나타나지 않으면 TimeoutException을 발생시킵니다.
주요 Expected Conditions
WebDriverWait와 함께 사용할 수 있는 주요 Expected Conditions는 다음과 같습니다:
조건 | 설명 |
---|---|
presence_of_element_located |
요소가 DOM에 존재하는지 확인 |
visibility_of_element_located |
요소가 보이는지 확인 |
element_to_be_clickable |
요소가 클릭 가능한지 확인 |
text_to_be_present_in_element |
요소에 특정 텍스트가 있는지 확인 |
title_contains |
페이지 제목에 특정 텍스트가 포함되어 있는지 확인 |
예시 코드
from selenium import webdriver
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.common.by import By
from selenium.common.exceptions import TimeoutException
driver = webdriver.Chrome()
driver.get("https://example.com")
try:
# 클릭 가능한 버튼을 기다립니다.
button = WebDriverWait(driver, 10).until(
EC.element_to_be_clickable((By.ID, "submit-button"))
)
button.click()
# 특정 텍스트가 포함된 요소를 기다립니다.
element = WebDriverWait(driver, 10).until(
EC.text_to_be_present_in_element((By.CLASS_NAME, "result"), "성공")
)
print("작업이 성공적으로 완료되었습니다.")
except TimeoutException:
print("요소를 찾는 데 시간이 초과되었습니다.")
finally:
driver.quit()
- 이 방법을 사용하면 동적으로 로드되는 웹 페이지의 요소를 안정적으로 처리할 수 있습니다. 페이지 로딩 시간이 일정하지 않거나, AJAX 요청으로 콘텐츠가 동적으로 변경되는 경우에 특히 유용합니다.
- WebDriverWait를 사용하면 명시적 대기를 구현할 수 있어, 불필요한 고정 대기 시간을 줄이고 테스트의 안정성과 효율성을 높일 수 있습니다[1].
7. Headless 모드 및 기타 옵션
Headless 모드는 GUI 없이 브라우저를 실행하는 방법으로 서버 환경이나 백그라운드 작업에 유용
from selenium import webdriver
from selenium.webdriver.chrome.service import Service
from selenium.webdriver.chrome.options import Options
from webdriver_manager.chrome import ChromeDriverManager
chrome_options = Options()
chrome_options.add_argument('--headless')
chrome_options.add_argument('--disable-gpu') # 필요한 경우
chrome_options.add_argument('user-agent=Mozilla/5.0 ...') # User-Agent 설정
driver = driver = webdriver.Chrome(service=Service(ChromeDriverManager().install()), options=chrome_options)
driver.get('https://example.com')
print(driver.title)
driver.quit()
기타 유용한 옵션:
--start-maximized
: 브라우저를 최대화하여 시작--disable-extensions
: 확장 프로그램 비활성화--disable-gpu
: GPU 하드웨어 가속 비활성화--no-sandbox
: 샌드박스 비활성화 (주의: 보안상 위험할 수 있음)window-size=1200x600
: 브라우저 창 크기 설정user-agent=Mozilla/5.0 ...
: User-Agent 설정
8. 원격 디버깅: –remote-debugging-port 옵션 사용
Chrome 브라우저의 원격 디버깅 기능을 활용하면 Selenium 스크립트 실행 중 브라우저의 상태를 실시간으로 검사하고 디버깅할 수 있습니다. 이는 복잡한 웹 애플리케이션 자동화 시 매우 유용합니다.
–remote-debugging-port 옵션 사용법
from selenium import webdriver
from selenium.webdriver.chrome.service import Service
from selenium.webdriver.chrome.options import Options
from webdriver_manager.chrome import ChromeDriverManager
chrome_options = Options()
chrome_options.add_argument('--remote-debugging-port=9222')
driver = webdriver.Chrome(service=Service(ChromeDriverManager().install()), options=chrome_options)
driver.get('https://example.com')
이 코드는 다음과 같은 기능을 수행합니다:
- Chrome 브라우저를 9222 포트에서 원격 디버깅이 가능한 상태로 실행합니다.
- 개발자는 Chrome DevTools Protocol을 통해 브라우저에 연결하여 디버깅할 수 있습니다.
원격 디버깅의 장점
- 실시간 상태 확인: 자동화 스크립트 실행 중 브라우저의 상태를 실시간으로 확인할 수 있습니다.
- 네트워크 트래픽 분석: 페이지 로드 시 발생하는 네트워크 요청을 분석할 수 있습니다.
- JavaScript 디버깅: 페이지에서 실행되는 JavaScript 코드를 디버깅할 수 있습니다.
- DOM 요소 검사: 동적으로 생성되는 DOM 요소를 실시간으로 검사할 수 있습니다.
주의사항
- 원격 디버깅 포트를 열면 보안 위험이 있을 수 있으므로, 개발 환경에서만 사용하고 프로덕션 환경에서는 사용을 피해야 합니다.
- 포트 번호는 다른 프로세스와 충돌하지 않도록 주의해야 합니다.
원격 디버깅 연결 : Shell 에서 Chrome 브라우저 실행
원격 디버깅 연결을 위해 Chrome 브라우저를 Shell에서 직접 실행
- Windows
"C:\Program Files\Google\Chrome\Application\chrome.exe"
- macOS
/Applications/Google\ Chrome.app/Contents/MacOS/Google\ Chrome
- Linux
google-chrome
원격 디버깅 포트 열기
- 원격 디버깅을 위해 특정 포트를 열고 Chrome을 실행
google-chrome --remote-debugging-port=9222
기타 유용한 옵션
- 사용자 프로필 디렉토리 설정:
google-chrome --remote-debugging-port=9222 --user-data-dir=/tmp/chrome
- 독립적인 프로필 생성: 기존 Chrome 인스턴스와 충돌 방지
- 보안 강화: 기존 사용자 데이터 보호
- 성능 및 안정성 향상
- 헤드리스 모드로 실행:
google-chrome --headless
- 특정 URL로 시작:
google-chrome --headless https://example.com
- User Agent 설정:
google-chrome --user-agent="Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.36"
- 창 크기 설정:
google-chrome --window-size=1200,800
- 확장 프로그램 비활성화:
google-chrome --disable-extensions
주의사항
- 위의 명령어들은 Chrome이 기본 설치 경로에 있다고 가정합니다. 만약 다른 경로에 설치되어 있다면 해당 경로를 사용해야 합니다.
- 일부 옵션은 보안상의 이유로 주의해서 사용해야 합니다. 특히
--no-sandbox
옵션은 보안을 약화시킬 수 있으므로 개발 환경에서만 사용해야 합니다. - 헤드리스 모드를 사용할 때는 GUI가 없으므로 콘솔 출력을 통해 결과를 확인해야 합니다.
댓글남기기