Selenium 크롤링 - 동적 웹 페이지 자동화
개요
Selenium은 웹 브라우저 자동화를 위한 강력한 도구입니다:
- 웹 브라우저 자동화: 실제 브라우저를 제어하여 웹 페이지 조작
- JavaScript 실행: JavaScript 코드 실행 및 동적 콘텐츠 처리
- 사용자 시뮬레이션: 클릭, 입력, 스크롤 등 사용자 행동 시뮬레이션
- 다양한 브라우저: Chrome, Firefox, Safari 등 다양한 브라우저 지원
1. Selenium 개요
주요 특징
- 동적 콘텐츠: JavaScript로 생성되는 콘텐츠 처리 가능
- 실제 브라우저: 실제 사용자 환경과 동일한 조건
- 강력한 기능: 복잡한 웹 애플리케이션 자동화
- 디버깅: 브라우저에서 직접 확인 가능
장점
- 완전한 렌더링: JavaScript로 생성되는 모든 콘텐츠 접근 가능
- 사용자 행동 시뮬레이션: 실제 사용자처럼 상호작용
- 디버깅 용이: 브라우저에서 직접 확인 가능
- 강력한 선택자: CSS 선택자, XPath 등 다양한 요소 선택 방법
2. Selenium 설치 및 설정
Selenium 설치
1
2
3
4
5
6
7
| # pip 설치
pip install selenium
# WebDriver 설치 (Chrome)
# ChromeDriver 다운로드: https://chromedriver.chromium.org/
# 또는 자동 설치
pip install webdriver-manager
|
기본 설정
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
| 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
from selenium.webdriver.common.action_chains import ActionChains
from selenium.webdriver.common.keys import Keys
from selenium.webdriver.chrome.options import Options
from webdriver_manager.chrome import ChromeDriverManager
import time
import pandas as pd
# Chrome 옵션 설정
def setup_chrome_options():
"""Chrome 옵션 설정"""
options = Options()
# 헤드리스 모드 (브라우저 창 숨기기)
options.add_argument('--headless')
# 성능 최적화
options.add_argument('--no-sandbox')
options.add_argument('--disable-dev-shm-usage')
options.add_argument('--disable-gpu')
options.add_argument('--disable-extensions')
# User-Agent 설정
options.add_argument('--user-agent=Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36')
# 창 크기 설정
options.add_argument('--window-size=1920,1080')
return options
# WebDriver 생성
def create_driver():
"""WebDriver 생성"""
options = setup_chrome_options()
# ChromeDriver 자동 설치 및 생성
driver = webdriver.Chrome(
service=webdriver.chrome.service.Service(ChromeDriverManager().install()),
options=options
)
return driver
# 기본 WebDriver 생성
driver = create_driver()
|
3. Selenium 기본 사용법
페이지 접근 및 요소 찾기
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
| def basic_selenium_example():
"""Selenium 기본 사용법 예시"""
try:
# 페이지 접근
driver.get("https://example.com")
# 페이지 제목 확인
title = driver.title
print(f"페이지 제목: {title}")
# 요소 찾기 (다양한 방법)
# ID로 찾기
element_by_id = driver.find_element(By.ID, "element_id")
# 클래스명으로 찾기
element_by_class = driver.find_element(By.CLASS_NAME, "class_name")
# CSS 선택자로 찾기
element_by_css = driver.find_element(By.CSS_SELECTOR, ".class_name")
# XPath로 찾기
element_by_xpath = driver.find_element(By.XPATH, "//div[@class='class_name']")
# 텍스트로 찾기
element_by_text = driver.find_element(By.LINK_TEXT, "링크 텍스트")
# 부분 텍스트로 찾기
element_by_partial_text = driver.find_element(By.PARTIAL_LINK_TEXT, "부분 텍스트")
# 여러 요소 찾기
elements = driver.find_elements(By.CLASS_NAME, "class_name")
print(f"찾은 요소 수: {len(elements)}")
return driver
except Exception as e:
print(f"Selenium 오류: {e}")
return None
# 기본 예시 실행
# basic_selenium_example()
|
요소 조작
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
| def element_interaction_example():
"""요소 조작 예시"""
try:
# 페이지 접근
driver.get("https://example.com")
# 텍스트 입력
input_element = driver.find_element(By.ID, "input_id")
input_element.clear() # 기존 텍스트 지우기
input_element.send_keys("입력할 텍스트")
# 클릭
button_element = driver.find_element(By.ID, "button_id")
button_element.click()
# 체크박스 선택/해제
checkbox = driver.find_element(By.ID, "checkbox_id")
if not checkbox.is_selected():
checkbox.click()
# 라디오 버튼 선택
radio_button = driver.find_element(By.ID, "radio_id")
radio_button.click()
# 드롭다운 선택
from selenium.webdriver.support.ui import Select
dropdown = Select(driver.find_element(By.ID, "dropdown_id"))
dropdown.select_by_visible_text("옵션 텍스트")
dropdown.select_by_value("옵션 값")
dropdown.select_by_index(0)
# 키보드 입력
input_element.send_keys(Keys.ENTER) # Enter 키
input_element.send_keys(Keys.TAB) # Tab 키
input_element.send_keys(Keys.ARROW_DOWN) # 화살표 키
return True
except Exception as e:
print(f"요소 조작 오류: {e}")
return False
# 요소 조작 예시 실행
# element_interaction_example()
|
대기 및 조건부 실행
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
| def wait_and_conditional_example():
"""대기 및 조건부 실행 예시"""
try:
# 페이지 접근
driver.get("https://example.com")
# 명시적 대기 (WebDriverWait 사용)
wait = WebDriverWait(driver, 10) # 최대 10초 대기
# 요소가 클릭 가능할 때까지 대기
clickable_element = wait.until(
EC.element_to_be_clickable((By.ID, "button_id"))
)
clickable_element.click()
# 요소가 보일 때까지 대기
visible_element = wait.until(
EC.visibility_of_element_located((By.ID, "element_id"))
)
# 요소가 사라질 때까지 대기
wait.until(
EC.invisibility_of_element_located((By.ID, "loading_id"))
)
# 텍스트가 나타날 때까지 대기
wait.until(
EC.text_to_be_present_in_element((By.ID, "status_id"), "완료")
)
# URL이 변경될 때까지 대기
wait.until(
EC.url_contains("success")
)
# 암시적 대기 (전역 설정)
driver.implicitly_wait(10) # 모든 요소 찾기 시 최대 10초 대기
# 강제 대기
time.sleep(2) # 2초 대기
return True
except Exception as e:
print(f"대기 및 조건부 실행 오류: {e}")
return False
# 대기 및 조건부 실행 예시
# wait_and_conditional_example()
|
4. Selenium 고급 기능
JavaScript 실행
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
| def javascript_execution_example():
"""JavaScript 실행 예시"""
try:
# 페이지 접근
driver.get("https://example.com")
# JavaScript 실행
result = driver.execute_script("return document.title;")
print(f"JavaScript 실행 결과: {result}")
# JavaScript로 요소 스크롤
driver.execute_script("window.scrollTo(0, document.body.scrollHeight);")
# JavaScript로 요소 클릭
element = driver.find_element(By.ID, "button_id")
driver.execute_script("arguments[0].click();", element)
# JavaScript로 요소에 텍스트 입력
input_element = driver.find_element(By.ID, "input_id")
driver.execute_script("arguments[0].value = 'JavaScript로 입력';", input_element)
# JavaScript로 요소 스타일 변경
driver.execute_script("arguments[0].style.border = '2px solid red';", element)
# JavaScript로 요소 제거
driver.execute_script("arguments[0].remove();", element)
# JavaScript로 새 창 열기
driver.execute_script("window.open('https://example.com', '_blank');")
# JavaScript로 팝업 차단
driver.execute_script("window.alert = function() {};")
return True
except Exception as e:
print(f"JavaScript 실행 오류: {e}")
return False
# JavaScript 실행 예시
# javascript_execution_example()
|
액션 체인 (ActionChains)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
| def action_chains_example():
"""액션 체인 예시"""
try:
# 페이지 접근
driver.get("https://example.com")
# ActionChains 객체 생성
actions = ActionChains(driver)
# 요소 찾기
element = driver.find_element(By.ID, "element_id")
# 마우스 오버
actions.move_to_element(element).perform()
# 더블 클릭
actions.double_click(element).perform()
# 우클릭 (컨텍스트 메뉴)
actions.context_click(element).perform()
# 드래그 앤 드롭
source_element = driver.find_element(By.ID, "source_id")
target_element = driver.find_element(By.ID, "target_id")
actions.drag_and_drop(source_element, target_element).perform()
# 키보드 조합
actions.key_down(Keys.CONTROL).send_keys('c').key_up(Keys.CONTROL).perform()
# 복합 액션
actions.move_to_element(element).click().send_keys("텍스트").perform()
# 액션 체인 저장 및 실행
actions.move_to_element(element).click().perform()
return True
except Exception as e:
print(f"액션 체인 오류: {e}")
return False
# 액션 체인 예시
# action_chains_example()
|
쿠키 및 세션 관리
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
| def cookie_session_example():
"""쿠키 및 세션 관리 예시"""
try:
# 페이지 접근
driver.get("https://example.com")
# 쿠키 추가
driver.add_cookie({
'name': 'cookie_name',
'value': 'cookie_value',
'domain': 'example.com'
})
# 쿠키 가져오기
cookies = driver.get_cookies()
print(f"쿠키 수: {len(cookies)}")
for cookie in cookies:
print(f"쿠키: {cookie['name']} = {cookie['value']}")
# 특정 쿠키 가져오기
specific_cookie = driver.get_cookie('cookie_name')
print(f"특정 쿠키: {specific_cookie}")
# 쿠키 삭제
driver.delete_cookie('cookie_name')
# 모든 쿠키 삭제
driver.delete_all_cookies()
# 로컬 스토리지 접근
driver.execute_script("localStorage.setItem('key', 'value');")
value = driver.execute_script("return localStorage.getItem('key');")
print(f"로컬 스토리지 값: {value}")
# 세션 스토리지 접근
driver.execute_script("sessionStorage.setItem('key', 'value');")
value = driver.execute_script("return sessionStorage.getItem('key');")
print(f"세션 스토리지 값: {value}")
return True
except Exception as e:
print(f"쿠키 및 세션 관리 오류: {e}")
return False
# 쿠키 및 세션 관리 예시
# cookie_session_example()
|
5. Selenium 실무 적용 예시
로그인 자동화
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
| def automated_login():
"""로그인 자동화"""
try:
# 로그인 페이지 접근
driver.get("https://example.com/login")
# 로그인 폼 요소 찾기
username_input = driver.find_element(By.ID, "username")
password_input = driver.find_element(By.ID, "password")
login_button = driver.find_element(By.ID, "login_button")
# 로그인 정보 입력
username_input.clear()
username_input.send_keys("your_username")
password_input.clear()
password_input.send_keys("your_password")
# 로그인 버튼 클릭
login_button.click()
# 로그인 성공 확인
wait = WebDriverWait(driver, 10)
success_element = wait.until(
EC.presence_of_element_located((By.CLASS_NAME, "success_message"))
)
print("로그인 성공!")
return True
except Exception as e:
print(f"로그인 오류: {e}")
return False
# 로그인 자동화 실행
# automated_login()
|
폼 자동 작성
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
| def automated_form_filling():
"""폼 자동 작성"""
try:
# 폼 페이지 접근
driver.get("https://example.com/form")
# 폼 요소들 찾기
name_input = driver.find_element(By.ID, "name")
email_input = driver.find_element(By.ID, "email")
phone_input = driver.find_element(By.ID, "phone")
# 체크박스들
checkbox1 = driver.find_element(By.ID, "checkbox1")
checkbox2 = driver.find_element(By.ID, "checkbox2")
# 라디오 버튼
radio_button = driver.find_element(By.ID, "radio_option1")
# 드롭다운
from selenium.webdriver.support.ui import Select
dropdown = Select(driver.find_element(By.ID, "dropdown"))
# 텍스트 영역
textarea = driver.find_element(By.ID, "textarea")
# 폼 작성
name_input.send_keys("홍길동")
email_input.send_keys("hong@example.com")
phone_input.send_keys("010-1234-5678")
# 체크박스 선택
if not checkbox1.is_selected():
checkbox1.click()
if not checkbox2.is_selected():
checkbox2.click()
# 라디오 버튼 선택
radio_button.click()
# 드롭다운 선택
dropdown.select_by_visible_text("옵션 1")
# 텍스트 영역 작성
textarea.send_keys("자동으로 작성된 텍스트입니다.")
# 폼 제출
submit_button = driver.find_element(By.ID, "submit_button")
submit_button.click()
# 제출 성공 확인
wait = WebDriverWait(driver, 10)
success_message = wait.until(
EC.presence_of_element_located((By.CLASS_NAME, "success_message"))
)
print("폼 제출 성공!")
return True
except Exception as e:
print(f"폼 작성 오류: {e}")
return False
# 폼 자동 작성 실행
# automated_form_filling()
|
데이터 수집
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
| def data_collection_example():
"""데이터 수집 예시"""
try:
# 데이터 페이지 접근
driver.get("https://example.com/data")
# 데이터 요소들 찾기
data_elements = driver.find_elements(By.CLASS_NAME, "data-item")
collected_data = []
for element in data_elements:
try:
# 각 데이터 항목에서 정보 추출
title = element.find_element(By.CLASS_NAME, "title").text
price = element.find_element(By.CLASS_NAME, "price").text
description = element.find_element(By.CLASS_NAME, "description").text
link = element.find_element(By.TAG_NAME, "a").get_attribute("href")
data_item = {
"title": title,
"price": price,
"description": description,
"link": link
}
collected_data.append(data_item)
except Exception as e:
print(f"데이터 항목 추출 오류: {e}")
continue
# 데이터를 DataFrame으로 변환
df = pd.DataFrame(collected_data)
# CSV 파일로 저장
df.to_csv("collected_data.csv", index=False, encoding="utf-8-sig")
print(f"수집된 데이터 수: {len(collected_data)}")
print("데이터가 'collected_data.csv'에 저장되었습니다.")
return collected_data
except Exception as e:
print(f"데이터 수집 오류: {e}")
return []
# 데이터 수집 실행
# data_collection_example()
|
페이지네이션 처리
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
| def pagination_handling():
"""페이지네이션 처리"""
try:
# 첫 페이지 접근
driver.get("https://example.com/list")
all_data = []
page_num = 1
while True:
print(f"페이지 {page_num} 처리 중...")
# 현재 페이지 데이터 수집
data_elements = driver.find_elements(By.CLASS_NAME, "data-item")
for element in data_elements:
try:
title = element.find_element(By.CLASS_NAME, "title").text
price = element.find_element(By.CLASS_NAME, "price").text
data_item = {
"page": page_num,
"title": title,
"price": price
}
all_data.append(data_item)
except Exception as e:
print(f"데이터 항목 추출 오류: {e}")
continue
# 다음 페이지 버튼 찾기
try:
next_button = driver.find_element(By.CLASS_NAME, "next-page")
# 버튼이 비활성화되어 있으면 종료
if not next_button.is_enabled():
break
# 다음 페이지로 이동
next_button.click()
# 페이지 로딩 대기
wait = WebDriverWait(driver, 10)
wait.until(
EC.presence_of_element_located((By.CLASS_NAME, "data-item"))
)
page_num += 1
except Exception as e:
print(f"다음 페이지 버튼 찾기 오류: {e}")
break
# 데이터를 DataFrame으로 변환
df = pd.DataFrame(all_data)
# CSV 파일로 저장
df.to_csv("paginated_data.csv", index=False, encoding="utf-8-sig")
print(f"총 수집된 데이터 수: {len(all_data)}")
print("데이터가 'paginated_data.csv'에 저장되었습니다.")
return all_data
except Exception as e:
print(f"페이지네이션 처리 오류: {e}")
return []
# 페이지네이션 처리 실행
# pagination_handling()
|
6. Selenium 최적화 및 모범 사례
성능 최적화
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
| def optimize_selenium_performance():
"""Selenium 성능 최적화"""
# Chrome 옵션 최적화
options = Options()
# 헤드리스 모드
options.add_argument('--headless')
# 성능 최적화 옵션들
options.add_argument('--no-sandbox')
options.add_argument('--disable-dev-shm-usage')
options.add_argument('--disable-gpu')
options.add_argument('--disable-extensions')
options.add_argument('--disable-plugins')
options.add_argument('--disable-images') # 이미지 로딩 비활성화
options.add_argument('--disable-javascript') # JavaScript 비활성화 (필요한 경우)
# 메모리 사용량 최적화
options.add_argument('--memory-pressure-off')
options.add_argument('--max_old_space_size=4096')
# 네트워크 최적화
options.add_argument('--aggressive-cache-discard')
options.add_argument('--disable-background-timer-throttling')
# 창 크기 최적화
options.add_argument('--window-size=1920,1080')
return options
# 최적화된 WebDriver 생성
def create_optimized_driver():
"""최적화된 WebDriver 생성"""
options = optimize_selenium_performance()
driver = webdriver.Chrome(
service=webdriver.chrome.service.Service(ChromeDriverManager().install()),
options=options
)
# 암시적 대기 시간 설정
driver.implicitly_wait(5)
# 페이지 로드 타임아웃 설정
driver.set_page_load_timeout(30)
return driver
# 최적화된 WebDriver 사용
# optimized_driver = create_optimized_driver()
|
에러 처리 및 재시도
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
| import time
from functools import wraps
def retry_on_failure(max_retries=3, delay=1):
"""실패 시 재시도 데코레이터"""
def decorator(func):
@wraps(func)
def wrapper(*args, **kwargs):
for attempt in range(max_retries):
try:
return func(*args, **kwargs)
except Exception as e:
if attempt == max_retries - 1:
print(f"최대 재시도 횟수 초과: {e}")
raise
print(f"시도 {attempt + 1} 실패, {delay}초 후 재시도: {e}")
time.sleep(delay)
return None
return wrapper
return decorator
# 재시도 기능이 있는 Selenium 함수
@retry_on_failure(max_retries=3, delay=2)
def robust_selenium_operation():
"""견고한 Selenium 작업"""
try:
# WebDriver 생성
driver = create_optimized_driver()
# 페이지 접근
driver.get("https://example.com")
# 요소 찾기 및 조작
element = driver.find_element(By.ID, "element_id")
element.click()
# 결과 반환
result = driver.find_element(By.CLASS_NAME, "result").text
# WebDriver 종료
driver.quit()
return result
except Exception as e:
print(f"Selenium 작업 오류: {e}")
if 'driver' in locals():
driver.quit()
raise
# 견고한 Selenium 작업 실행
# result = robust_selenium_operation()
|
스크린샷 및 디버깅
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
| def screenshot_and_debugging():
"""스크린샷 및 디버깅"""
try:
# WebDriver 생성
driver = create_optimized_driver()
# 페이지 접근
driver.get("https://example.com")
# 스크린샷 촬영
screenshot_path = "screenshot.png"
driver.save_screenshot(screenshot_path)
print(f"스크린샷 저장: {screenshot_path}")
# 특정 요소 스크린샷
element = driver.find_element(By.ID, "element_id")
element.screenshot("element_screenshot.png")
print("요소 스크린샷 저장: element_screenshot.png")
# 페이지 소스 저장
page_source = driver.page_source
with open("page_source.html", "w", encoding="utf-8") as f:
f.write(page_source)
print("페이지 소스 저장: page_source.html")
# 콘솔 로그 가져오기
logs = driver.get_log('browser')
for log in logs:
print(f"브라우저 로그: {log}")
# 네트워크 로그 가져오기
performance_logs = driver.get_log('performance')
for log in performance_logs:
print(f"성능 로그: {log}")
# WebDriver 종료
driver.quit()
return True
except Exception as e:
print(f"스크린샷 및 디버깅 오류: {e}")
if 'driver' in locals():
driver.quit()
return False
# 스크린샷 및 디버깅 실행
# screenshot_and_debugging()
|
7. 실무 활용 팁
1. 동적 콘텐츠 처리
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
| def handle_dynamic_content():
"""동적 콘텐츠 처리"""
driver = create_optimized_driver()
try:
# 페이지 접근
driver.get("https://spa.example.com")
# 동적 콘텐츠 로딩 대기
wait = WebDriverWait(driver, 20)
# 특정 요소가 나타날 때까지 대기
dynamic_element = wait.until(
EC.presence_of_element_located((By.CLASS_NAME, "dynamic-content"))
)
# 스크롤하여 더 많은 콘텐츠 로드
driver.execute_script("window.scrollTo(0, document.body.scrollHeight);")
time.sleep(2)
# 무한 스크롤 처리
last_height = driver.execute_script("return document.body.scrollHeight")
while True:
# 스크롤 다운
driver.execute_script("window.scrollTo(0, document.body.scrollHeight);")
time.sleep(2)
# 새로운 높이 계산
new_height = driver.execute_script("return document.body.scrollHeight")
if new_height == last_height:
break
last_height = new_height
# 동적 콘텐츠 수집
dynamic_elements = driver.find_elements(By.CLASS_NAME, "dynamic-content")
print(f"동적 콘텐츠 수: {len(dynamic_elements)}")
return dynamic_elements
finally:
driver.quit()
|
2. 복잡한 폼 처리
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
| def handle_complex_forms():
"""복잡한 폼 처리"""
driver = create_optimized_driver()
try:
# 폼 페이지 접근
driver.get("https://example.com/complex-form")
# 파일 업로드
file_input = driver.find_element(By.ID, "file-upload")
file_input.send_keys("/path/to/file.pdf")
# 날짜 선택기
date_input = driver.find_element(By.ID, "date-picker")
date_input.click()
# 달력에서 날짜 선택
calendar = WebDriverWait(driver, 10).until(
EC.visibility_of_element_located((By.CLASS_NAME, "calendar"))
)
target_date = calendar.find_element(By.XPATH, "//td[text()='15']")
target_date.click()
# 자동완성 입력
autocomplete_input = driver.find_element(By.ID, "autocomplete")
autocomplete_input.send_keys("검색어")
# 자동완성 옵션 선택
wait = WebDriverWait(driver, 10)
option = wait.until(
EC.element_to_be_clickable((By.CLASS_NAME, "autocomplete-option"))
)
option.click()
# 슬라이더 조작
slider = driver.find_element(By.ID, "slider")
actions = ActionChains(driver)
actions.drag_and_drop_by_offset(slider, 100, 0).perform()
return True
finally:
driver.quit()
|
3. 다중 창 처리
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
| def handle_multiple_windows():
"""다중 창 처리"""
driver = create_optimized_driver()
try:
# 첫 번째 창
driver.get("https://example.com")
main_window = driver.current_window_handle
# 새 창 열기
driver.execute_script("window.open('https://example2.com', '_blank');")
# 모든 창 핸들 가져오기
all_windows = driver.window_handles
for window in all_windows:
if window != main_window:
# 새 창으로 전환
driver.switch_to.window(window)
# 새 창에서 작업
title = driver.find_element(By.TAG_NAME, "h1").text
print(f"새 창 제목: {title}")
# 새 창 닫기
driver.close()
# 원래 창으로 돌아가기
driver.switch_to.window(main_window)
return True
finally:
driver.quit()
|
4. 모바일 시뮬레이션
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
| def mobile_simulation():
"""모바일 시뮬레이션"""
# 모바일 옵션 설정
mobile_emulation = {
"deviceMetrics": {"width": 375, "height": 667, "pixelRatio": 2.0},
"userAgent": "Mozilla/5.0 (iPhone; CPU iPhone OS 11_0 like Mac OS X) AppleWebKit/604.1.38 (KHTML, like Gecko) Version/11.0 Mobile/15A372 Safari/604.1"
}
options = Options()
options.add_experimental_option("mobileEmulation", mobile_emulation)
driver = webdriver.Chrome(
service=webdriver.chrome.service.Service(ChromeDriverManager().install()),
options=options
)
try:
# 모바일 페이지 접근
driver.get("https://m.example.com")
# 모바일 전용 요소 찾기
mobile_menu = driver.find_element(By.CLASS_NAME, "mobile-menu")
mobile_menu.click()
# 터치 제스처 시뮬레이션
actions = ActionChains(driver)
actions.move_to_element(mobile_menu).click_and_hold().move_by_offset(100, 0).release().perform()
return True
finally:
driver.quit()
|
8. 주의사항 및 모범 사례
법적 고려사항
- robots.txt 확인: 웹사이트의 robots.txt 파일 확인
- 이용약관 준수: 웹사이트 이용약관 준수
- 저작권 존중: 저작권이 있는 콘텐츠 사용 시 주의
- 개인정보 보호: 개인정보 수집 시 관련 법규 준수
기술적 고려사항
- 요청 제한: 서버에 과부하를 주지 않도록 요청 제한
- User-Agent 설정: 적절한 User-Agent 설정
- 에러 처리: 적절한 에러 처리 및 재시도 로직
- 리소스 관리: WebDriver 리소스 적절한 관리
성능 최적화
- 헤드리스 모드: 불필요한 UI 렌더링 비활성화
- 이미지 로딩: 필요하지 않은 경우 이미지 로딩 비활성화
- JavaScript: 필요하지 않은 경우 JavaScript 비활성화
- 캐싱: 중복 요청 방지를 위한 캐싱
실무 팁
- 적절한 대기 시간 설정: 너무 짧으면 요소를 찾지 못하고, 너무 길면 성능 저하
- 요소 선택자 최적화: ID > CSS 선택자 > XPath 순으로 우선순위
- 리소스 정리: 작업 완료 후 반드시 driver.quit() 호출
- 로깅 및 모니터링: 스크래핑 과정을 적절히 로깅하고 모니터링
마무리
Selenium은 웹 브라우저 자동화를 위한 강력한 도구입니다. JavaScript로 생성되는 동적 콘텐츠를 처리할 수 있고, 실제 사용자 행동을 시뮬레이션할 수 있습니다.
적절한 설정과 최적화를 통해 안정적이고 효율적인 웹 자동화 시스템을 구축할 수 있으며, 실무에서는 동적 콘텐츠 처리, 복잡한 폼 처리, 다중 창 처리 등의 고급 기능을 활용할 수 있습니다.
다만 법적, 윤리적 고려사항을 준수하여 사용해야 하며, 성능 최적화와 에러 처리를 통해 안정적인 시스템을 구축해야 합니다.