데브코스-데이터엔지니어링

Selenium, WebDriver, Implicit / Explicit Wait, Mouse Event, Keyboard Event

묠니르묘묘 2024. 4. 6. 17:59

Selenium 라이브러리

  • Python을 이용해서 웹 브라우저를 조작할 수 있는 자동화 프레임워크
  • %pip install selenium 으로 설치
    • % 를 이용해서 노트북(.ipynb) 환경에서 터미널 코드 실행 가능

 

Web Driver

  • 웹 브라우저를 제어할 수 있는 자동화 프레임워크
  • %pip install webdriver-manager 으로 설치
  • Chrome (크롬) 브라우저를 사용하기에 크롬 설치 필수

 

# selenium 으로부터 webdriver 모듈 불러오기
from selenium import webdriver
from selenium.webdriver.chrome.service import Service
from webdriver_manager.chrome import ChromeDriverManager

# webdriver에서 Chrome() 객체 생성
driver = webdriver.Chrome(service=Service(ChromeDriverManager().install()))
# driver = webdriver.Chrome()

# http://www.example.com 으로 요청 보내기
driver.get("http://www.example.com")

# page_source 속성을 통해 Response의 HTML 문서 확인하기
print(driver.page_source)

위 코드 실행 시, Chrome 창이 계속 켜져있음.

이는 해당 창을 끄라고 명령을 내린 적이 없기 때문임.

 

# with-as 를 사용해서 창을 끄도록 해보자
with webdriver.Chrome(service=Service(ChromeDriverManager().install())) as driver:
    driver.get("http://www.example.com")
    print(driver.page_source)

with 안의 코드가 실행되면 자동으로 Chrome 창이 닫아짐

 

Driver 에서 특정 요소 추출하기

  • selenium 은 받아온 응답으로부터 특정 요소 추출 가능
  • 요소 하나 찾기
    • .find_element(by, target)
      • by : 대상을 찾는 기준 ( ID, TAG_NAME, CLASS_NAME …)
      • target : 대상의 속성
  • 요소 여러개 찾기
    • .find_elements(by, target)
      • by : 대상을 찾는 기준 ( ID, TAG_NAME, CLASS_NAME …)
      • target : 대상의 속성

 

# By 를 import 하기
from selenium.webdriver.common.by import By

# <p> 해당하는 요소 하나를 찾아보기
with webdriver.Chrome(service=Service(ChromeDriverManager().install())) as driver:
    driver.get("http://www.example.com")
    print(driver.find_element(By.TAG_NAME, "p").text)
    
# <p> 해당하는 요소 여러개 찾아보기
with webdriver.Chrome(service=Service(ChromeDriverManager().install())) as driver:
    driver.get("http://www.example.com")
    for element in driver.find_elements(By.TAG_NAME, "p"):
        print("Text:", element.text)

 

Implicit Wait (암시적 기다림)

  • 특정 요소에 대한 제약을 통한 기다림
  • 로딩이 다 될 때까지의 한계 시간의 의미를 가지는 것
  • e.g. 이 태그를 가져올 수 있을 때까지 기다리기
  • `.implicitly_wait()` 를 활용하여 사용

Explicit Wait

  • 다 로딩일 될 때까지 지정한 시간동안 기다리기
  • `WebDriverWait()` 와 아래 메서드를 활용하여 사용 가능
    • `until()` : 인자의 조건이 만족될 때까지
    • `until_not()` : 인자의 조건이 만족되지 않을 때까지
  • e.g. 다 로딩이 될 때까지 5초동안 기다리기

 

XPath 란?
- XML, HTML 문서 등의 요소의 위치를 경로로 표현하는 것
- 마치`데스크탑/폴더1/폴더2/음악.mp3` 같은 경로
# 스크래핑에 필요한 라이브러리를 불러와봅시다.

from selenium import webdriver
from selenium.webdriver.chrome.service import Service
from selenium.webdriver.common.by import By
from webdriver_manager.chrome import ChromeDriverManager

# 예시 사이트에 요청을 진행하고, 예시 사이트의 첫 번째 이벤트의 제목을 가져와봅시다.
driver = webdriver.Chrome(service=Service(ChromeDriverManager().install()))
driver.get("https://indistreet.com/live?sortOption=startDate%3AASC")

# XPath를 이용해서 특정 위치의 값 가져오기
# 이 때, 동적 페이지이기 때문에 스크래핑 시 데이터가 없어서 오류가 날 수 있음
# 따라서 Wait를 넣어줘야함
driver.find_element(By.XPATH, '//*[@id="__next"]/div/main/div[2]/div/div[4]/div[1]/div[1]/div/a/div[2]/p[1]').text

# Implicit Wait를 사용하기 위해 import하기
from selenium.webdriver.support.ui import WebDriverWait

# 10초동안 Implicit Wait를 진행하여 스크래핑이 잘 이루어지도록 수정
with webdriver.Chrome(service=Service(ChromeDriverManager().install())) as driver:
    driver.get("https://indistreet.com/live?sortOption=startDate%3AASC")
    driver.implicitly_wait(10)
    print(driver.find_element(By.XPATH, '//*[@id="__next"]/div/main/div[2]/div/div[4]/div[1]/div[1]/div/a/div[2]/p[1]').text)
    
# EC는 selenium에서 정의된 조건들
# EC의 expected_conditions는 '~가 존재하면' 이라는 의미
from selenium.webdriver.support import expected_conditions as EC

with webdriver.Chrome(service=Service(ChromeDriverManager().install())) as driver:
    driver.get("https://indistreet.com/live?sortOption=startDate%3AASC")
    # explicit wait으로 변경하여, 특정 요소가 존재할 때까지 10초동안 기다리기
    element = WebDriverWait(driver, 10).until(EC.presence_of_element_located((By.XPATH, '//*[@id="__next"]/div/main/div[2]/div/div[4]/div[1]/div[1]/div/a/div[2]/p[1]')))
    print(element.text)

 

Mouse Event (마우스 이벤트) 처리하기

# 스크래핑에 필요한 라이브러리를 불러와봅시다.

from selenium import webdriver
from selenium.webdriver import ActionChains
from selenium.webdriver.chrome.service import Service
from selenium.webdriver.common.by import By
from webdriver_manager.chrome import ChromeDriverManager

# 주어진 웹사이트를 누른 후, 우리가 원하는 버튼 요소를 찾은 후 마우스 이벤트를 실행시켜봅시다.
driver = webdriver.Chrome(service=Service(ChromeDriverManager().install()))
driver.get("https://hashcode.co.kr")
driver.implicitly_wait(2)

# 로그인 버튼 찾기
button = driver.find_element(By.CLASS_NAME, 'UtilMenustyle__Link-sc-2sjysx-4.ewJwEL')
# 로그인 버튼 클릭하기
ActionChains(driver).click(button).perform()

위 코드 실행 시, hashcode 홈페이지가 켜지고, 그 페이지에 있는 로그인 버튼 자동 클릭

 

Keyboard Event (키보드 이벤트) 처리하기

# 스크래핑에 필요한 라이브러리를 불러와봅시다.

from selenium import webdriver
from selenium.webdriver import ActionChains
from webdriver_manager.chrome import ChromeDriverManager
from selenium.webdriver.common.actions.action_builder import ActionBuilder
from selenium.webdriver import Keys, ActionChains
from selenium.webdriver.chrome.service import Service
from selenium.webdriver.common.by import By

import time

driver = webdriver.Chrome()
driver.get("https://hashcode.co.kr")
time.sleep(0.5)

# 내비게이션 바에서 "로그인" 버튼을 찾아서 눌리기
button = driver.find_element(By.CLASS_NAME, 'UtilMenustyle__Link-sc-2sjysx-4.ewJwEL')
ActionChains(driver).click(button).perform()
time.sleep(0.5)

# "아이디" input 요소에 아이디 입력하기
id_input = driver.find_elements(By.CLASS_NAME, "FymRFM681OjzOdzor5nk")[0]
ActionChains(driver).send_keys_to_element(id_input, "아이디@gmail.com").perform()
time.sleep(0.5)

# "패스워드" input 요소에 비밀번호 입력하기
pw_input = driver.find_elements(By.CLASS_NAME, "FymRFM681OjzOdzor5nk")[1]
ActionChains(driver).send_keys_to_element(pw_input, "비밀번호").perform()
time.sleep(0.5)

# "로그인" 버튼을 눌러서 로그인 완료하기
login_button = driver.find_element(By.CLASS_NAME, "itAWTII94uCyf9uUgREi")
ActionChains(driver).click(login_button).perform()
time.sleep(0.5)

위 코드 실행 시, 홈페이지 켜서 로그인 버튼 눌려서 로그인 화면 들어가고, 아이디와 비밀번호 입력하여 로그인 완료시킴