3 분 소요

[BeautifulSoup] Wait, Mouse, Keyboard를 활용한 동적 웹사이트 스크래핑

Selenium을 이용한 동적 웹사이트 스크래핑: Wait, Mouse, Keyboard


blog2

동적 웹사이트를 스크래핑하기 위해 Selenium을 활용한 방법에 대해 알아보겠습니다. 이 포스트에서는 웹 페이지의 로딩 시간을 고려한 Wait 기법과 마우스 및 키보드 이벤트 처리 방법을 다루겠습니다.

1. Wait and Call

동적 웹사이트를 스크래핑할 때, Selenium은 페이지의 로딩 시간을 고려해야 합니다. 이를 위해 Implicit WaitExplicit Wait을 사용할 수 있습니다.

Implicit Wait과 Explicit Wait

  • Implicit Wait: 웹 드라이버가 특정 요소를 찾기 위해 지정한 시간 동안 기다립니다. 요소가 로드되면 즉시 다음 단계로 진행합니다.
  • Explicit Wait: 특정 조건이 충족될 때까지 기다립니다. 예를 들어, 특정 요소가 나타날 때까지 대기합니다.

스크래핑할 사이트: IndieStreet 이벤트

IndieStreet의 이벤트 리스트를 스크래핑하기 위해 아래의 웹사이트를 사용합니다: IndieStreet Events

1. 스크래핑에 필요한 라이브러리 불러오기

먼저, Selenium을 통해 스크래핑에 필요한 라이브러리를 불러옵니다.

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

2. XPath 이해하기

이 웹사이트의 요소는 랜덤하게 생성된 클래스 이름을 가지고 있으므로, XPath를 사용하여 요소를 선택합니다. XPath는 HTML 문서의 요소 위치를 경로로 표현하는 방식입니다.

예시 XPath:

[@id="__next"]/div/main/div[2]/div/div[4]/div[1]/div[1]/div/a/div[2]/p[1]

3. 암시적 기다림 (Implicit Wait) 적용하기

암시적 기다림을 설정하여 페이지가 로드될 때까지 대기하는 방법입니다.

with webdriver.Chrome(service=Service(ChromeDriverManager().install())) as driver:
    driver.get('https://indistreet.com/live?sortOption=startDate%3AASC')
    
    driver.implicitly_wait(10)  # 10초 동안 기다림
    
    print(driver.find_element(By.XPATH, '//*[@id="__next"]/div/main/div[2]/div/div[4]/div[1]/div[2]/div/a/div[2]/p[1]').text)

4. 명시적 기다림 (Explicit Wait) 적용하기

특정 요소가 로드될 때까지 대기하는 방법입니다.

from selenium.webdriver.support.ui import WebDriverWait
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')
    
    element = WebDriverWait(driver, 10).until(EC.presence_of_element_located((By.XPATH, '//*[@id="__next"]/div/main/div[2]/div/div[4]/div[1]/div[2]/div/a/div[2]/p[1]')))
    print(element.text)

5. 여러 공연 제목 가져오기

이벤트 제목을 여러 개 가져오기 위해 XPath를 일반화합니다.

with webdriver.Chrome(service=Service(ChromeDriverManager().install())) as driver:
    driver.get('https://indistreet.com/live?sortOption=startDate%3AASC')
    driver.implicitly_wait(10)  # 10초 대기
    
    for i in range(1, 11):
        e = driver.find_element(By.XPATH, '//*[@id="__next"]/div/main/div[2]/div/div[4]/div[1]/div[{}]/div/a/div[2]/p[1]'.format(i))
        print(e.text)

출력 예시

  • Knock Live Rock band
  • 이디어츠 1st EP 발매기념 공연
  • 도라페스트 4탄
  • NO PASARAN! Vol.1
  • 2019년 5월 17일 카페 아이다호 공연 - 권유 (gwon.u)
  • LIVE in NOV 2019
  • LIVE in DEC 2019
  • Thursday Mood
  • 오롯한 라이브와 함께

2. 마우스 이벤트 처리하기

Selenium을 이용해서 마우스 이벤트를 동작해봅시다.

Mouse Event

웹 페이지에서 일어나는 일들을 Event라고 합니다. 마우스로 일어날 수 있는 대표적인 이벤트는 다음과 같습니다:

  • 마우스 움직이기 (move)
  • 마우스 누르기 (press down)
  • 마우스 떼기 (press up)

저희는 버튼을 찾은 후 이를 클릭하는 것을 목표로 합니다.

마우스 입력 과정

  1. 입력하고자 하는 대상 요소를 찾습니다. (find_element() 이용)
  2. 입력하고자 하는 내용을 click을 통해 전달합니다.
  3. .perform()을 통해 동작합니다.

아래 예시는 id가 textInput인 요소를 클릭하는 예제입니다.

button = driver.find_element(By.ID, "button")
ActionChains(driver).click(button).perform()

스크래핑에 필요한 라이브러리 불러오기

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(0.5)

button = driver.find_element(By.CLASS_NAME, "nav-link.nav-signin")
ActionChains(driver).click(button).perform()

3. 키보드 이벤트 처리하기

Selenium을 이용해서 키보드 이벤트를 동작해봅시다.

Keyboard Event

웹 페이지에서 일어나는 일들을 Event라고 합니다. 키보드로 일어날 수 있는 대표적인 이벤트는 다음과 같습니다:

  • 키보드 누르기 (press down)
  • 키보드 떼기 (press up)

저희는 입력창(input 태그의 form)에 키보드 입력을 진행하는 것을 목표로 합니다.

키보드 입력 과정

  1. 입력하고자 하는 대상 요소를 찾습니다. (find_element() 이용)
  2. 입력하고자 하는 내용을 send_keys_to_element를 통해 전달합니다.
  3. .perform()을 통해 동작합니다.

아래 예시는 id가 textInput인 요소에 “abc”를 입력하는 예제입니다.

text_input = driver.find_element(By.ID, "textInput")
ActionChains(driver).send_keys_to_element(text_input, "abc").perform()

로그인 자동화 코드

이제, 로그인 과정을 자동화해봅시다.

import time

# driver를 이용해 해당 사이트에 요청을 보내봅시다.
driver = webdriver.Chrome(service=Service(ChromeDriverManager().install()))
driver.get('https://hashcode.co.kr')
time.sleep(1)

# 내비게이션 바에서 "로그인" 버튼을 찾아 눌러봅시다.
button = driver.find_element(By.CLASS_NAME, "nav-link.nav-signin")
ActionChains(driver).click(button).perform()
time.sleep(1)

# "아이디" input 요소에 여러분의 아이디를 입력합니다.
id_input = driver.find_element(By.ID, "user_email")
ActionChains(driver).send_keys_to_element(id_input, "내 아이디").perform()
time.sleep(1)

# "패스워드" input 요소에 여러분의 비밀번호를 입력합니다.
pw_input = driver.find_element(By.ID, "user_password")
ActionChains(driver).send_keys_to_element(pw_input, "내 비번").perform()
time.sleep(1)

# "로그인" 버튼을 눌러서 로그인을 완료합니다.
login_btn = driver.find_element(By.ID, "btn-sign-in")
ActionChains(driver).click(login_btn).perform()
time.sleep(1)

오류 처리

위 코드를 실행하면 다음과 같은 오류가 발생할 수 있습니다.

NoSuchElementException: Unable to locate element: {"method":"css selector","selector":".nav-link.nav-signin"}

이는 요소를 찾지 못했음을 의미합니다. 정확한 클래스를 사용했는지, 페이지가 로드된 후 요소가 렌더링되는 시간을 고려해야 합니다. 필요하다면 implicitly_wait를 조정하여 페이지가 로드될 때까지 기다리도록 설정할 수 있습니다.


결론

Selenium을 활용한 마우스 및 키보드 이벤트 처리로 해시코드 사이트에 로그인하는 과정을 자동화해 보았습니다. 이 과정을 통해 웹 페이지의 다양한 요소와 상호작용할 수 있는 방법을 익힐 수 있었습니다.

댓글남기기