requests로 안 되던 사이트, 파이썬 Selenium으로 긁어보기
지난 편에서 이런 이야기로 마무리했던 거 기억하시나요. 분명 브라우저 화면에는 목록이 쭉 떠 있는데, 코드로 긁으면 텅 빈 리스트만 돌아오던 그 상황이요.
혹시 직접 겪어보셨어요? requests로 받아서 print 찍어봤더니 정작 필요한 내용은 하나도 없고, 껍데기만 나오던 그 답답함. F12 눌러서 확인해보면 화면엔 멀쩡히 다 있는데 말이죠.
저도 처음에 이거 붙잡고 한참 헤맸거든요. 오타인가, 클래스명을 잘못 넣었나, 계속 코드만 들여다봤어요. 근데 코드 문제가 아니었어요.
왜 화면엔 보이는데 코드론 안 잡힐까
이걸 이해하려면 requests가 뭘 하는 애인지부터 봐야 해요.
requests는 팩스로 서류 받는 거랑 비슷해요. 상대 서버가 처음 딱 한 번 보내주는 종이(초기 HTML)만 손에 들어와요. 근데 요즘 사이트들은 그 종이에 "나머지 내용은 담당자가 와서 채워드립니다"라고만 적혀 있는 경우가 많거든요. 그 담당자가 바로 자바스크립트예요. 팩스는 담당자를 부를 수가 없죠. 그래서 빈칸인 채로 받는 거예요.
이렇게 접속한 다음에 자바스크립트가 내용을 나중에 채워 넣는 페이지를 동적 페이지라고 불러요. 무한 스크롤로 계속 내려야 목록이 뜨는 사이트, 더보기 버튼을 눌러야 내용이 나오는 사이트, 로그인해야만 보이는 페이지... 이런 게 다 동적 페이지예요. 한마디로 "사람이 브라우저에서 손으로 뭔가 해야 나오는 것들"이죠.
그래서 등장하는 게 파이썬 Selenium이에요.
Selenium은 신입사원한테 일 시키는 거랑 비슷해요. "저 사이트 들어가서 스크롤 쭉 내리고, 더보기 눌러서, 화면에 다 뜬 거 적어와" 하고 진짜 브라우저를 켜서 사람처럼 조종하는 거예요. 사람이 브라우저에서 할 수 있는 건 Selenium도 다 할 수 있어요. 화면이 다 그려진 "완성본"을 보는 거니까요.
여기서 잠깐, 중요한 이야기 하나 하고 갈게요.
requests로 되면 그냥 requests 쓰세요. 지난 편에서 배운 게 여전히 1순위예요. Selenium은 브라우저를 통째로 띄우니까 느리고 무거워요. 신입사원 불러서 브라우저 켜고 기다리게 하는 만큼 시간이 걸리잖아요. 그러니까 Selenium은 "requests로 텅 비어 나올 때만 꺼내는 카드"라고 생각하시면 돼요.
python selenium 입문: 설치는 딱 한 줄
설치부터 볼게요. 터미널에 이거 하나면 끝나요.
pip install selenium
여기서 예전 블로그 자료 보신 분들, 잠깐만요.
옛날 자료에는 꼭 "chromedriver를 따로 다운받아서 경로를 지정하세요"라는 내용이 나와요. 버전 맞춰서 드라이버 받고, 폴더에 넣고, 경로 적어주고... 이거 진짜 삽질 포인트였거든요.
근데 지금은 그거 안 하셔도 돼요. Selenium 4부터는 드라이버를 알아서 자동으로 다운받고 관리해줘요(Selenium Manager라고 불러요). 컴퓨터에 크롬 브라우저만 깔려 있으면 끝이에요.
혹시 옛날 자료 보고 따라 하시다가 "chromedriver 경로가 어쩌고" 하는 부분 나오면, 그 부분은 그냥 무시하세요. 지금은 필요 없는 과정이에요.
브라우저 열고 페이지 접속하기
그럼 진짜 브라우저를 하나 열어볼게요.
from selenium import webdriver # 셀레니움 불러오기
driver = webdriver.Chrome() # 크롬 창이 하나 열립니다 (드라이버 자동 관리)
driver.get("https://example.com") # 원하는 주소로 이동
print(driver.title) # 페이지 제목 출력
driver.quit() # 다 썼으면 브라우저 닫기 (꼭!)
# 실행 결과:
# Example Domain
이거 실행하면 진짜로 빈 크롬 창이 하나 뜨고, 알아서 주소로 이동해요. 처음 보면 좀 신기하실 거예요. 내 코드가 브라우저를 조종하는 거니까요.
driver는 그 신입사원이라고 생각하시면 돼요. 앞으로 "이거 해라 저거 해라" 시킬 대상이에요.
요소 찾기: find_element과 By
페이지를 열었으면 이제 원하는 내용을 콕 집어야겠죠. 요소를 찾을 땐 By를 같이 써요.
from selenium.webdriver.common.by import By # By 불러오기
element = driver.find_element(By.CLASS_NAME, "title") # class가 title인 요소 1개
print(element.text) # 눈에 보이는 글자 꺼내기
link = element.get_attribute("href") # 링크 주소 꺼내기
find_element은 조건에 맞는 첫 번째 하나만 가져와요. 찾은 다음에 .text로 눈에 보이는 글자를 꺼내고, .get_attribute("href")로 링크 주소 같은 속성값을 꺼내요.
여러 개를 한 번에 가져오고 싶으면 find_elements(뒤에 s가 붙어요)를 써요. 이건 리스트로 돌려줘요.
items = driver.find_elements(By.CSS_SELECTOR, "ul.list li") # 여러 개 → 리스트로
for item in items: # 하나씩 돌면서
print(item.text) # 글자 출력
By에는 By.ID, By.TAG_NAME, By.XPATH 같은 것도 있긴 한데, 입문 단계에선 방금 쓴 CLASS_NAME이랑 CSS_SELECTOR 두 개만 알아도 웬만한 건 다 돼요. 나머지는 나중에 필요할 때 하나씩 찾아보셔도 늦지 않아요.
동적 크롤링의 진짜 핵심: 기다리기
자, 여기가 오늘 글에서 제일 중요한 부분이에요.
동적 페이지는 접속하자마자 내용이 뜨는 게 아니에요. 자바스크립트가 데이터를 채우는 데 아주 잠깐 시간이 걸리거든요. 사람 눈엔 순식간이라 티가 안 나는데, 코드는 그 찰나에 먼저 도착해버려요. 그래서 아직 안 뜬 요소를 찾으려다가 에러가 나요.
처음에 이거 몰라서 "분명 클래스명 맞는데 왜 못 찾지?" 하고 한참 헤매시는 분들 많아요. 근데 없는 게 아니라 아직 안 뜬 것일 확률이 높아요.
그럼 기다리면 되겠네, 싶어서 이렇게 하는 분들이 있어요.
import time
time.sleep(5) # 무조건 5초 기다리기 (권장하지 않아요)
이건 별로 좋은 방법이 아니에요. 왜냐면 time.sleep(5)는 무조건 5초를 통째로 낭비하거든요. 요소가 1초 만에 떠도 5초를 다 기다려요. 반대로 5초보다 더 걸리면 그래도 에러가 나고요.
그래서 Selenium은 더 똑똑한 방법을 줘요. 바로 WebDriverWait예요.
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.common.by import By
# class가 result인 요소가 뜰 때까지 최대 10초만 기다립니다
element = WebDriverWait(driver, 10).until(
EC.presence_of_element_located((By.CLASS_NAME, "result"))
)
print(element.text) # 뜨는 즉시 바로 다음으로 넘어갑니다
이건 엘리베이터 기다리기랑 비슷해요. time.sleep이 "무조건 3분 서 있기"라면, WebDriverWait은 "오면 바로 타되, 최대 3분까지만 기다림"이에요. 요소가 빨리 뜨면 빨리 넘어가고, 안 뜨면 최대치까지만 기다리다 포기해요. 훨씬 효율적이죠.
동적 페이지를 다룰 땐 이 WebDriverWait가 거의 무조건 필요하다고 보시면 돼요.
스크롤이랑 headless는 맛보기로
무한 스크롤 사이트는 스크롤을 내려야 다음 목록이 뜨잖아요. 이럴 땐 이렇게 스크롤을 내려요.
import time
for _ in range(3): # 3번 정도 내려보기
driver.execute_script("window.scrollTo(0, document.body.scrollHeight);") # 맨 아래로
time.sleep(2) # 새 목록이 뜰 시간 잠깐 대기
그리고 창을 아예 안 띄우고 뒤에서 조용히 돌리는 headless 모드라는 것도 있어요. 아까 그 신입사원한테 모니터 끄고 머릿속으로 똑같이 처리하게 시키는 거랑 비슷해요. 결과는 같은데 화면에 창이 안 떠서 작업할 때 방해가 안 돼요.
from selenium import webdriver
from selenium.webdriver.chrome.options import Options
options = Options()
options.add_argument("--headless=new") # 창 없이 백그라운드로 실행
driver = webdriver.Chrome(options=options)
이 둘은 지금 단계에선 "이런 것도 있구나" 정도만 알아두시면 충분해요.
driver.quit()은 꼭 해주세요
작업이 끝나면 driver.quit()으로 브라우저를 반드시 닫아주세요.
이거 안 하면 어떻게 되냐면요, Selenium을 실행할 때마다 크롬 창이 하나씩 계속 쌓여요. 눈에 안 보이는 백그라운드 프로세스까지 같이요. 나중에 작업표시줄에 크롬이 우수수 떠 있거나 컴퓨터가 갑자기 느려지면, 이거 의심해보세요. 저도 초반에 이거 안 닫아서 크롬을 수십 개 띄워놓은 적 있거든요.
에러가 나도 무조건 닫히게 하려면 try/finally로 감싸는 습관을 들이시면 좋아요.
try:
driver.get("https://example.com") # 여기서 에러가 나더라도
# ... 크롤링 작업 ...
finally:
driver.quit() # 이 줄은 반드시 실행됩니다
그리고 수집한 결과는 지난 편들에서 배운 대로 엑셀로 저장하면 돼요. find_elements로 제목이랑 링크를 리스트에 모아두고, pandas나 openpyxl로 xlsx 파일로 떨구면 끝이에요.
처음에 자주 만나는 에러 두 가지
NoSuchElementException — 요소를 못 찾았다는 에러예요. 앞에서 말한 것처럼 대부분 "아직 안 뜬 것"이 원인이에요. WebDriverWait로 기다렸다가 찾으면 해결되는 경우가 많아요. 그래도 안 되면 클래스명이나 선택자에 오타가 없는지 다시 확인해보세요.
AttributeError: 'WebDriver' object has no attribute 'find_element_by_id' — 이건 옛날 문법을 그대로 쓴 경우예요. 2021년 이전 블로그에 나오는 driver.find_element_by_id("x") 같은 문법은 Selenium 4에서 완전히 사라졌어요. 지금은 driver.find_element(By.ID, "x") 형태만 돼요. 옛날 자료 보고 그대로 따라 치면 딱 이 에러 만나요. 그러니 오래된 자료를 볼 땐 이 부분을 꼭 최신 문법으로 바꿔주세요.
직접 해보기
지난 편에서 requests로 긁었더니 텅 비어서 안 됐던 그 사이트, 기억나시죠. 이번엔 Selenium으로 다시 도전해보세요.
- 초급: 그냥 접속해서 제목 하나만 출력해보기 (
driver.title) - 중급:
find_elements로 목록 여러 개를 한 번에 수집해서 출력하기 - 도전: 스크롤을 몇 번 내려서 더 많은 항목을 긁어오기
힌트를 드리면, 목록이 바로 안 뜨는 것 같으면 WebDriverWait부터 넣어보세요. 그리고 어떤 클래스명을 넣어야 할지 모르겠으면 F12로 요소를 확인하는 방법, 지난 편에서 했던 그대로예요.
막히는 부분은 댓글로 남겨주세요. 어디서 걸리는지 같이 봐드릴게요.
requests로 안 되던 사이트, 이제 Selenium이라는 카드가 손에 생겼죠. 정적이든 동적이든 이제 웬만한 페이지는 다 긁을 수 있게 된 거예요. 다음 편에서는 이 둘을 무기 삼아서 네이버랑 구글 검색 결과를 통째로 긁어올 거예요. 검색어 넣고 결과 목록을 쫙 수집하는, 직장인이 진짜 써먹는 자동화로 넘어가 볼게요.
제 글이 도움이 되셨다면 댓글 & 공감 부탁드려요 😀
'Application > Python' 카테고리의 다른 글
| [Python] 19. 파이썬 알림 봇 만들기 - 슬랙과 카카오톡으로 실시간 알림 받기 (1) | 2026.07.31 |
|---|---|
| [Python] 18. 네이버·구글 검색 결과, 파이썬으로 자동 수집하는 가장 쉬운 방법 (0) | 2026.07.30 |
| [Python] 16. 크롤링 기초 - requests와 BeautifulSoup으로 웹 데이터 자동 수집하기 (0) | 2026.07.24 |
| [Python] 15. 파이썬으로 양식 일괄 발송 시스템 만들기 (엑셀 명단 → 개인 문서 → 자동 메일) (0) | 2026.07.22 |
| [Python] 14. 파이썬으로 첨부파일과 HTML 메일 보내기 (0) | 2026.07.21 |