Python - Selenium

장현욱(Artlogy)·2022년 11월 7일
0

Python

목록 보기
1/1
post-thumbnail

작업 환경

  • Python 3.8 버전 이상
  • Window10
  • Selenium 4.5.0 ( 4.x.x 이상 쓰세요 )
  • Pyautogui
  • Packaging

기본 문법

from selenium import webdriver
from selenium.webdriver.chrome.service import Service
from webdriver_manager.chrome import ChromeDriverManager
from selenium.webdriver.chrome.options import Options
chrome_options = Options()
driver = webdriver.Chrome(options= chrome_options, service=Service(ChromeDriverManager().install()))
driver.get("http://url.com")
driver.implicitly_wait(1)

셀레니움을 활용한 크롤링의 기본 형태는 위 와 같다.

webdriver

위 코드에서는 Chrome을 쓰고 있지만, 관공서나 정부 프로젝트로 크롤링을 원한다면 Edge를 사용하는걸 권장한다. (우리 같은 개발자야 크롬을 거의 필수처럼 쓰고있지만 다른곳은 그렇지 않다.)
셀레니움에서 크롤링을 지원하는 브라우저는 다음과 같다.

지원하는 브라우저

  • Microsoft Edge
  • Google Chrome
  • FireFox
  • IE
  • Safari

지원하고자하는 브라우저를 선택했다면 Option과 드라이버를 선택해주면 된다.

Options

크롤링으로 사용 할 브라우저의 옵션을 정한다.
많은 옵션이 존재하지만 자주쓰는 것만 작성 해볼까한다.

pageLoadStrategy (페이지 로드전략)

options.page_load_strategy = 'normal'
  • normal(default) : 페이지 로드시 모든 리소스가 다운로드 될 때 까지 기다림
  • eager : DOM만 준비 될 때까지 기다림 대신 이미지 같은 리소스는 로딩 상태 일 수 있으니 주의
  • none : 안 기다림

acceptInsecureCerts ( 안전하지 않은 세션 허용 )

options.accept_insecure_certs = False

False가 기본이며, 안전하지 않은 인증 및 세션이 있을 경우 오류를 반환한다.
안전하지 않은 인증 및 세션 검사를 무시 하고 싶을경우엔 True로 바꿔준다.

Timeout ( 제한 시간 )

options.script_timeout(30000)
options.page_load_timeout(300000)
options.implicit_wait_timeout(0)
  • script_timeout : 현재 페이지에서 실행중인 스크립트를 중단 할 시간을 정한다. 기본값 30,000초
  • page_load_timeout : 페이지 로드 제한시간을 설정한다. 기본값 300,000초
  • implicit_wait_timeout : 요소를 찾을 때 암시적 요소 대기시간을 정한다. 기본값 0초

headless ( 브라우저 open여부 )

options.headless = False

False가 기본이며, 브라우저창을 띄운다.
True시 브라우저창을 띄우지 않고 크롤링이 실행된다.

window-size ( 창 크기 설정 )

options.add_argument("window-size=1920x1080")

disable-gpu ( gpu 사용하지 않음 )

options.add_argument("disable-gpu")

start-fullscreen ( F11 풀스크린 )

options.add_argument("start-fullscreen")

disable-dev-shm-usage(안전하지 않음 경고 무시)

options.add_argument("disable-dev-shm-usage")

no-sandbox (* 크롬전용 샌드박스 기능 사용안함)

options.add_argument("no-sandbox")

크롬 샌드박스에 대한 자세한 설명

lang (언어)

options.add_argument("lang=ko") # 한국어

다운로드

options.add_experimental_option('prefs',{'download.default_directory':r'C:\python'	//다운로드 기본 경로 변경
,'download.prompt_for_download': False		//prompt 창 띄울지 여부
,'donwload.directory_upgrade':True			//경로 업그레이드 여부
,'safebrowsing.enabled':True				//안전한 파일만 다운할지 여부
})

GUI가 없는 곳에서 크롤링시 세팅 (ex: ubuntu, wsl)

options.add_argument('headless')
options.add_argument('no-sandbox') # 크롬일 경우
options.add_argument('disable-dev-shm-usage')

Controll

셀레니움으로 제어하는 법을 알아 보자.
스코프 크기를 기준으로
1. browser
2. window
3. dom(frame)
4. wait
5. script
순으로 진행하겠다.

Browser

불러오기 ( Driver Load )

URL = 'https://www.selenium.dev/ko/documentation/'
options = Options()
driver = webdriver.Chrome(options= chrome_options, service=Service(ChromeDriverManager().install()))
driver.get(url=URL)

핵심은 driver.get(url=)을 통해 원하는 url을 불러 올 수 있다는 점이다.

현재 URL 불러오기

print(driver.current_url)

닫기

dirver.quit()
브라우저를 닫음과 동시에 크롤링을 종료한다는 의미이기도 하다.

Window

브라우저안에서 여러 창을 띄워 사용 할 때도 있다. ( ex : 팝업창, Tab )

window_handles

for item in driver.window_handles:
	print(item)
driver.window_handles[0] # 스택 형태로 쌓이기 때문에 0번째 인덱스는 맨 처음 윈도우
driver.window_handles[-1] # 새로운 창

window focus change

driver.swich_to.window(drvier.window_handles[-1]) # 새창으로 포커스 이동

창 닫기

driver.close()

현재 포커스하고 있는 창을 닫는다.

Dom(Frame)

FindElement

driver.find_element(by=By.CSS_SELECTOR, value="#trigger1")  # id가 trigger1 요소 선택
driver.find_elements(by=By.CSS_SELECTOR, value="#trigger1>div") # id가 trigger1인 하위 div요소들을 선택

나는 요소 검색 방법으로 css_selector가 편해서 위 처럼 많이 쓰지만,
다른 방법도 많다 xpath, class_name등등 원하는 걸로 하자.

Input(Event)

만약 요소에 이벤트를 발생 하고 싶다면 다음과 같이 진행하면 된다.

String 입력

search_box = driver.find_element(by=By.CSS_SELECTOR, value="#trigger1")
search_box.send_keys('artlogy.github.io')

파일 업로드

search_box = driver.find_element(by=By.CSS_SELECTOR, value="input[type=file]")
upload.send_keys(file_path)

파일을 업로드 할 수 있는 input요소를 선택한 후 업로드 할 file_path를 넣어주면 된다.

특정 키보드 키 입력

from selenium.webdriver.common.keys import Keys
search_box = driver.find_element(by=By.CSS_SELECTOR, value="#trigger1")
search_box.send_keys(Keys.ENTER)

다른 이벤트

search_box = driver.find_element(by=By.CSS_SELECTOR, value="#trigger1")
search_box.click() # 클릭이벤트
search_box.submit() # 제출
search_box.clear() # input clear

더 많은 이벤트

from selenium.webdriver import ActionChains
action_chains = ActionChains(driver)
action_chains.drag_and_drop(source, target).perform() #source요소를 target요소로 drag and drop

좀 더 세밀한 이벤트가 필요하다면 ActionChains를 사용하면 된다.

Frame

요샌 잘 안쓰지만 옛날 웹이나 정부사이트는 frame단위로 구분 된 것이 많다.
frame안에 요소를 선택 할려면 해당 frame으로 스위칭이 필요하다.

frame focus change

driver.switch_to.frame("fameName")

여기서 프레임이름은 해당 프레임의 ID를 넣으면된다.

frame return default

driver.switch_to.default_content() # 최상위 프레임으로 

driver.switch_to.parent_frame() # 상위 프레임으로 바꾸고 싶을 경우

하위 프레임을 사용하고 다시 돌아가고 싶을땐 위 코드를 이용하면 된다.

Wait

Option 파트에서도 다뤘지만, 페이지마다 로드시간이 다르고 요소마다 로드시간이 다르기 때문에
원하는 오브젝트가 로드 될 때까지 wait를 걸어주는 것도 매우 중요하다.

wait_till_load_webpage(웹페이지로딩대기)은 options에서 정하는거니 제외하겠다.

implicitly_waits (암묵적 대기)

driver.implicitly_wait(time_to_wait=0)

페이지 이동, url의 앤드포인트가 변경되는 명령을 줬을 때
다음 작업(페이지 요소)가 넘어 올때까지 기다리는 최대 시간이다.
default는 0초며, 만약 10초로 설정했어도 1초만에 로드가 된다면 기다리지 않고 진행한다.

Explicitly_waits (명시적 대기)

WebDriverWait(driver,0).until(EC.element_to_be_clickable((By.CSS_SELECTOR, '#txppIframe')))

implicitly_waits로 모든 것이 해결되면 좋겠지만, 요즘 웹페이지는 사용자와의 상호작용에 따라 나타나는 동적 요소도 존재하기 때문에 Explicitly_waits로 해당 요소를 명시하여 기다리는 기능 또한 필요하다.

time.sleep

import time
time.sleep(5)

쓰다보면 implicitly_waits, Explicitly_waits 둘다 완벽하지 않다는 걸 깨닫는다.
그땐 최후의 보루로 time.sleep()을 쓰면 좋다. 물론 무조건적인 대기를 하기 때문에, 크롤링 속도에 지대한 영향을 미치므로 최대한 자제하면서 필요한 곳에만 쓰자.

Javascript

driver.execute_scripts('window.scrollTo(0, document.body.scrollHeight);')

driver.execute_script로 js코드를 실행 할 수 있다.
위 코드는 스크롤을 맨 아래로 내리는 코드이다.

브라우저 창 다루기

뒤로가기

driver.back()

앞으로가기

driver.forward()

브라우저 최소화/최대화

driver.minimize_window()
driver.maxmize_window()

스크린샷 저장

driver.save_screenshot("screenshotName.png")

경고창 다루기

from selenium.webdriver.common.alert import Alert

Alert(driver).accept() #확인
Alert(driver).dismiss() #취소

print(Alert(driver).text) #경고창 내용
Alert(driver).send_keys(keysToSend=Keys.ESCAPE) #경고창 무시

쿠키 다루기

쿠키 추가

cookie = {"name":"foo", "value":"bar"}
driver.add_cookie(cookie)

쿠키 가져오기

cookies = driver.get_cookies()

0개의 댓글