[파이썬 10] 크롤링 심화, 로그인은 셀레니움으로


requests와 BeautifulSoup 조합은 정적인 HTML 페이지에는 잘 통하지만, 두 가지 상황에서 한계에 부딪힌다. 하나는 로그인이 필요한 페이지, 다른 하나는 자바스크립트로 나중에 데이터가 그려지는 페이지다. 이런 경우에 쓰는 도구가 셀레니움(Selenium)이다.


1. 셀레니움이 뭐고 requests와 뭐가 다른가


셀레니움은 원래 웹사이트 테스트 자동화를 위해 만들어진 브라우저 제어 도구지만, 크롤링에도 널리 쓰인다. requests가 HTML 원본을 그대로 가져오는 데 그친다면, 셀레니움은 실제 브라우저(크롬 등)를 코드로 직접 조작해서 클릭, 입력, 스크롤 같은 사람의 행동을 그대로 재현한다. 그래서 자바스크립트가 실행된 이후의 최종 화면, 즉 정적 크롤러로는 보이지 않는 데이터까지 가져올 수 있다는 게 핵심 차이다.


pip install selenium webdriver-manager


2. 기본 사용법, 브라우저 띄우고 페이지 열기


from selenium import webdriver

from selenium.webdriver.chrome.service import Service

from webdriver_manager.chrome import ChromeDriverManager


service = Service(ChromeDriverManager().install())

driver = webdriver.Chrome(service=service)


driver.get("https://example.com")

print(driver.title)


webdriver-manager 라이브러리를 쓰면 크롬 드라이버 버전을 직접 관리할 필요 없이 자동으로 맞는 버전을 설치해준다. 예전에는 크롬 버전과 드라이버 버전을 수동으로 맞춰야 해서 번거로웠는데, 이 부분이 자동화되면서 진입장벽이 낮아졌다.


3. 로그인 자동화하기


로그인 폼의 입력창과 버튼을 찾아서 값을 채워넣고 클릭하는 방식으로 로그인 과정을 코드로 재현한다. 이때 브라우저 개발자 도구(F12)로 입력창의 id나 class 이름을 미리 확인해두는 과정이 필요하다.


from selenium.webdriver.common.by import By

from selenium.webdriver.support.ui import WebDriverWait

from selenium.webdriver.support import expected_conditions as EC


driver.get("https://example.com/login")


WebDriverWait(driver, 10).until(

EC.presence_of_element_located((By.NAME, "username"))

)


driver.find_element(By.NAME, "username").send_keys("내아이디")

driver.find_element(By.NAME, "password").send_keys("내비밀번호")

driver.find_element(By.CSS_SELECTOR, "button[type='submit']").click()


WebDriverWait는 페이지 요소가 로딩될 때까지 기다려주는 역할을 하는데, 이게 없으면 페이지가 아직 다 로딩되지 않은 상태에서 요소를 찾으려다 오류가 나는 경우가 많다. 로그인이 실제로 성공했는지는 로그인 후 화면에 뜨는 특정 요소(에러 메시지 유무 등)로 확인하는 방식이 일반적으로 쓰인다.


4. 로그인 후 데이터 가져오기


로그인에 성공한 뒤에는 원하는 페이지로 이동해서 데이터를 추출하면 된다. 셀레니움으로 렌더링이 끝난 최종 HTML을 가져온 뒤, 그 HTML을 BeautifulSoup에 넘겨서 파싱하는 조합이 실무에서 흔히 쓰인다. 셀레니움이 브라우저 조작과 자바스크립트 렌더링을 담당하고, BeautifulSoup이 데이터 추출을 담당하는 역할 분담인 셈이다.


from bs4 import BeautifulSoup


html = driver.page_source

soup = BeautifulSoup(html, 'html.parser')

title = soup.find('h1').text

print(title)


5. 헤드리스 모드, 브라우저 창 없이 실행


매번 브라우저 창이 뜨는 게 번거롭다면, 헤드리스(headless) 모드로 화면 없이 백그라운드에서 실행할 수 있다.


from selenium.webdriver.chrome.options import Options


options = Options()

options.add_argument('--headless')

options.add_argument('--no-sandbox')


driver = webdriver.Chrome(service=service, options=options)


서버 환경이나 예약 실행 스크립트에서는 화면을 띄울 필요가 없기 때문에 헤드리스 모드가 표준처럼 쓰인다.


6. 주의할 점


로그인 자동화 스크립트를 잘못된 자격정보로 여러 번 반복 실행하면 계정이 일시적으로 차단되는 경우가 있다는 점, 그리고 일부 사이트는 캡차나 2단계 인증으로 자동화 자체를 막는 경우가 있다는 점을 감안해야 한다. 또한 셀레니움은 실제 브라우저를 구동하는 방식이라 requests/BeautifulSoup 조합보다 훨씬 느리고 자원을 많이 쓰기 때문에, 로그인이 필요 없는 페이지라면 굳이 셀레니움을 쓸 필요 없이 이전 편에서 다룬 requests 조합으로 충분하다는 점도 참고할 만하다.


7. 정리


로그인이 필요하거나 자바스크립트로 렌더링되는 페이지는 requests만으로는 한계가 있고, 이럴 때 셀레니움으로 실제 브라우저를 조작해 최종 화면까지 가져온 뒤 BeautifulSoup으로 데이터를 뽑는 조합이 표준적으로 쓰인다. 다만 속도가 느리고 자원을 많이 쓰기 때문에, 정적 페이지에는 굳이 쓸 필요가 없다는 점을 구분해서 판단하는 게 중요하다.