AI/Python

Selenium 기초: 동적 페이지 제어

jumemory 2025. 5. 30. 17:11

클릭, 스크롤, 페이지 이동, 요소 탐색까지 웹페이지를 “직접 조작”하는 자동화 도구

Selenium은 단순히 HTML을 받아와서 파싱하는 도구가 아닙니다.
Selenium은 브라우저를 실제로 열고, 사람이 하듯이 페이지를 조작하면서 데이터를 수집하는 도구입니다.

이 점이 requests + BeautifulSoup와 가장 큰 차이입니다.

requests + BeautifulSoup는 주로:

  • 서버에 요청해서
  • HTML을 받아오고
  • 그 HTML 안의 구조를 읽는 방식

이었다면,

Selenium은:

  • 브라우저를 실행하고
  • 페이지를 열고
  • 버튼을 클릭하고
  • 스크롤을 내리고
  • 페이지를 넘기고
  • 동적으로 로딩된 요소를 기다린 뒤
  • 화면에 실제로 나타난 데이터를 가져오는 방식

입니다.

즉, Selenium은
“웹페이지를 읽는 것”을 넘어서 “웹페이지를 조작하는 것” 에 강합니다.

이 파트를 이해하면 다음 상황에 대응할 수 있게 됩니다.

  • 페이지에 버튼 클릭이 필요한 경우
  • 스크롤을 내려야 데이터가 더 뜨는 경우
  • 검색어 입력 후 결과가 갱신되는 경우
  • 드롭다운 선택으로 목록이 바뀌는 경우
  • JavaScript가 실행된 뒤에야 데이터가 보이는 경우
  • 페이지 번호를 눌러 다음 목록으로 넘어가야 하는 경우

즉, Selenium은 특정 프로젝트 전용 도구가 아니라,
동적 웹페이지 자동화 전반에 쓰이는 범용적인 핵심 도구입니다.


1. Selenium은 왜 필요한가?

웹 크롤링을 하다 보면 requests + BeautifulSoup만으로는 안 되는 페이지를 자주 만납니다.

예를 들면 이런 경우입니다.

  • 처음 HTML에는 매물 데이터가 거의 없음
  • JavaScript가 실행된 뒤에 데이터가 채워짐
  • “더보기” 버튼을 눌러야 추가 목록이 나타남
  • 무한 스크롤이라 아래로 내려야 다음 데이터가 보임
  • 검색 필터를 클릭해야 원하는 목록이 바뀜
  • 로그인이나 팝업 닫기 같은 사용자 동작이 필요함

이런 페이지는 그냥 HTML 한 번 받아오는 방식으로는 부족할 수 있습니다.

즉, Selenium은
정적인 문서 수집이 아니라, 사용자 행동이 필요한 웹페이지를 다루기 위해 등장하는 도구입니다.


2. Selenium의 핵심 개념

Selenium을 처음 배울 때는 복잡해 보일 수 있지만, 핵심은 단순합니다.

Selenium은 크게 보면 다음 흐름으로 작동합니다.

  1. 브라우저를 실행한다
  2. 원하는 URL로 이동한다
  3. 페이지 안의 요소를 찾는다
  4. 클릭, 입력, 스크롤 같은 동작을 수행한다
  5. 결과가 바뀌면 다시 요소를 찾는다
  6. 텍스트나 속성 값을 추출한다

즉, Selenium은
브라우저 자동화 + 요소 탐색 + 데이터 추출
세 가지를 묶은 도구라고 보면 됩니다.


3. WebDriver란 무엇인가?

3-1. 정의

Selenium에서 브라우저를 제어하는 핵심 객체를 보통 WebDriver라고 부릅니다.

쉽게 말하면:

브라우저를 조종하는 리모컨 같은 역할

입니다.

예를 들어 크롬 브라우저를 띄우고 제어하려면 보통 Chrome WebDriver를 사용합니다.


3-2. 왜 중요한가?

우리가 Selenium으로 하는 모든 행동은 결국 WebDriver를 통해 이루어집니다.

예:

  • 페이지 열기
  • 현재 URL 확인
  • 요소 찾기
  • 클릭
  • 입력
  • 스크롤
  • 종료

즉, WebDriver는 Selenium의 중심입니다.


4. Selenium 기본 실행 구조

가장 기본적인 예시는 이런 식입니다.

 
from selenium import webdriver

driver = webdriver.Chrome()
driver.get("https://example.com")
 

이 코드의 의미는 다음과 같습니다.

  • webdriver.Chrome() → 크롬 브라우저를 자동 실행
  • driver.get(url) → 해당 URL로 이동

즉, 이 두 줄만으로도
“브라우저를 열고 페이지로 이동한다”는 가장 기본 동작이 이루어집니다.


5. driver는 무엇인가?

Selenium 예제에서 거의 항상 driver라는 이름이 등장합니다.

예:

 
driver = webdriver.Chrome()
 

여기서 driver는
브라우저를 제어하는 객체를 담고 있는 변수입니다.

즉, driver를 통해:

  • 페이지 이동
  • 요소 찾기
  • 클릭
  • 입력
  • 종료

를 하게 됩니다.

예:

 
driver.get("https://example.com")
print(driver.title)
driver.quit()
 

즉, driver는 Selenium 코드의 중심 조작 도구입니다.


6. 페이지 열기: get()

6-1. 정의

get()은 브라우저를 특정 URL로 이동시키는 메서드입니다.

예:

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

이건 사람이 주소창에 URL을 입력하고 엔터를 누른 것과 비슷합니다.


6-2. 왜 중요한가?

모든 크롤링과 자동화는 결국 “어느 페이지를 열 것인가”에서 시작합니다.

즉:

  • 목록 페이지 열기
  • 상세 페이지 열기
  • 검색 결과 페이지 열기

같은 작업이 다 get()에서 시작됩니다.


7. 페이지 정보 확인하기

Selenium으로 페이지를 열면 현재 페이지 정보도 확인할 수 있습니다.

7-1. 현재 제목

 
print(driver.title)
 

페이지 제목을 보여줍니다.


7-2. 현재 URL

 
print(driver.current_url)
 

현재 브라우저가 어느 URL에 있는지 보여줍니다.


7-3. 페이지 소스 보기

 
html = driver.page_source
print(html[:500])
 

이건 현재 브라우저에 렌더링된 HTML 소스를 문자열로 가져옵니다.

중요한 점은 driver.page_source는
브라우저가 실행된 뒤 시점의 HTML 이라는 것입니다.

즉, requests로 받은 초기 HTML과 다를 수 있습니다.
JavaScript가 실행되어 DOM이 바뀐 후의 HTML을 볼 수 있다는 점이 Selenium의 큰 장점 중 하나입니다.


8. 요소(element)란 무엇인가?

Selenium에서는 페이지 안의 버튼, 입력창, 제목, 카드 하나하나를 보통 요소(element) 라고 부릅니다.

예:

  • 버튼 하나
  • 검색창 하나
  • 가격 span 하나
  • 차량 카드 div 하나

이런 것이 모두 요소입니다.

즉, Selenium은 결국
원하는 요소를 찾아서 조작하거나 읽는 일이라고 이해하면 됩니다.


9. 요소 찾기: find_element() / find_elements()

9-1. 하나 찾기

 
element = driver.find_element(...)
 

이건 조건에 맞는 요소 하나를 찾습니다.


9-2. 여러 개 찾기

 
elements = driver.find_elements(...)
 

이건 조건에 맞는 요소 여러 개를 리스트처럼 찾습니다.


9-3. 왜 중요한가?

이건 BeautifulSoup의:

  • find()
  • find_all()

과 감각이 비슷합니다.

즉:

  • 하나의 버튼을 찾을 때 → find_element
  • 반복되는 카드 목록을 찾을 때 → find_elements

를 쓰게 됩니다.


10. 요소를 어떤 기준으로 찾을까? By

Selenium에서는 요소를 찾을 때 무슨 기준으로 찾을지를 명시합니다.
이때 자주 쓰는 것이 By입니다.

예:

 
from selenium.webdriver.common.by import By
 

그리고 다음처럼 씁니다.

 
driver.find_element(By.CLASS_NAME, "price")
 

즉:

  • By.CLASS_NAME → class 기준
  • "price" → 실제 class 이름

입니다.


11. 자주 쓰는 요소 탐색 기준

11-1. By.ID

id 기준으로 찾습니다.

 
driver.find_element(By.ID, "search-box")
 

11-2. By.CLASS_NAME

class 기준으로 찾습니다.

 
driver.find_element(By.CLASS_NAME, "price")
 

주의할 점은 여러 class가 공백으로 묶인 경우 전체를 그대로 넣는 방식은 조심해야 합니다.


11-3. By.TAG_NAME

태그 이름 기준입니다.

 
driver.find_elements(By.TAG_NAME, "a")
 

모든 링크 태그를 찾을 수 있습니다.


11-4. By.CSS_SELECTOR

CSS 선택자를 씁니다.

 
driver.find_element(By.CSS_SELECTOR, ".car-item .price")
 

이건 매우 강력하고 자주 쓰입니다.


11-5. By.XPATH

XPath라는 경로 표현 방식으로 찾습니다.

 
driver.find_element(By.XPATH, "//div[@class='price']")
 

XPath는 강력하지만 처음엔 다소 낯설 수 있습니다.
처음엔 CSS selector 중심으로 익히고, 필요할 때 XPath를 배우는 것도 좋습니다.


12. CSS Selector와 XPath는 어떻게 이해하면 좋을까?

CSS Selector

  • 웹 구조 감각과 자연스럽게 연결됨
  • 읽기 쉬운 경우가 많음
  • 크롤링과 프론트 감각을 함께 키우기 좋음

예:

 
".car-item .price"
 

XPath

  • 트리 구조를 아주 세밀하게 지정 가능
  • 특정 조건 탐색에 강한 경우가 있음
  • 복잡한 구조에서 유용할 수 있음

예:

 
"//div[@class='car-item']//span[@class='price']"
 

어떻게 선택하면 좋을까?

처음에는 CSS selector부터 익히는 것이 보통 더 직관적입니다.
하지만 어떤 페이지에서는 XPath가 더 편할 수 있으므로, 둘 다 존재를 알고 있어야 합니다.

즉, 중요한 건 도구 이름보다
“원하는 요소를 안정적으로 찾을 수 있는가” 입니다.


13. 요소에서 텍스트 추출하기

요소를 찾았으면 그 안의 텍스트를 가져와야 합니다.

예:

 
price = driver.find_element(By.CLASS_NAME, "price")
print(price.text)
 

이렇게 하면 화면에 보이는 텍스트를 가져옵니다.

즉, Selenium의 .text는
BeautifulSoup의 .get_text()와 비슷한 역할을 한다고 이해할 수 있습니다.


14. 속성 값 가져오기: get_attribute()

텍스트만 가져오는 게 아니라 속성 값도 자주 가져옵니다.

예:

 
link = driver.find_element(By.CSS_SELECTOR, "a.detail-link")
print(link.get_attribute("href"))
 

이건 링크 주소를 가져옵니다.

또 예를 들어:

 
img = driver.find_element(By.CSS_SELECTOR, "img.car-image")
print(img.get_attribute("src"))
 

이건 이미지 주소를 가져옵니다.

즉, Selenium에서도:

  • 텍스트 추출
  • 속성 추출

둘 다 중요합니다.


15. 클릭하기: click()

Selenium이 requests + BeautifulSoup와 크게 다른 지점 중 하나가 바로 클릭입니다.

예:

 
button = driver.find_element(By.CSS_SELECTOR, ".next-page")
button.click()
 

이 코드는 다음 페이지 버튼을 실제로 누르는 것과 비슷한 동작을 합니다.


클릭이 중요한 이유

실제 웹페이지에서는:

  • 더보기 버튼
  • 다음 페이지 버튼
  • 탭 전환 버튼
  • 필터 버튼
  • 팝업 닫기 버튼

같은 것이 매우 자주 등장합니다.

즉, Selenium은
사람이 하는 클릭 행동을 자동화할 수 있다는 점이 매우 강력합니다.


16. 입력하기: send_keys()

검색창이나 로그인 창처럼 텍스트를 입력해야 하는 경우도 많습니다.

예:

 
search_box = driver.find_element(By.ID, "search-box")
search_box.send_keys("현대 아반떼")
 

이건 사람이 키보드로 검색어를 입력하는 것과 비슷합니다.


추가로 자주 쓰는 것: 입력값 비우기

 
search_box.clear()
search_box.send_keys("기아 K5")
 

즉, 기존 내용을 지우고 새로 입력할 수 있습니다.


17. 엔터 입력하기

검색창에 입력 후 엔터를 눌러야 할 때도 있습니다.

예:

 
from selenium.webdriver.common.keys import Keys

search_box.send_keys("중고차")
search_box.send_keys(Keys.ENTER)
 

이렇게 하면 검색 버튼 클릭 없이 엔터 입력 효과를 줄 수 있습니다.


18. 여러 요소를 반복 처리하기

BeautifulSoup 때와 마찬가지로 Selenium에서도 목록형 구조가 매우 중요합니다.

예:

 
items = driver.find_elements(By.CSS_SELECTOR, ".car-item")

for item in items:
brand = item.find_element(By.CSS_SELECTOR, ".brand").text
price = item.find_element(By.CSS_SELECTOR, ".price").text
print(brand, price)
 

이건:

  • .car-item 카드들을 여러 개 찾고
  • 각 카드 안에서 브랜드와 가격을 추출합니다.

이 구조는 중고차 목록뿐 아니라:

  • 상품 리스트
  • 뉴스 기사 리스트
  • 채용 공고 리스트
  • 부동산 매물 리스트

등 거의 모든 목록형 동적 페이지에 응용됩니다.


19. 페이지 넘기기

동적 사이트에서는 다음 페이지로 이동해야 하는 경우가 많습니다.

예:

 
next_button = driver.find_element(By.CSS_SELECTOR, ".next-page")
next_button.click()
 

이후에는:

  • 페이지가 바뀌었는지
  • 목록이 갱신되었는지
  • 다시 요소를 찾아야 하는지

를 고려해야 합니다.

즉, 페이지 넘기기는 단순 클릭이 아니라
“클릭 후 새로운 화면 상태를 반영해 다시 탐색한다” 는 흐름까지 포함합니다.


20. 스크롤하기

일부 사이트는 스크롤을 내려야 데이터가 더 로딩됩니다.
이건 무한 스크롤 페이지에서 특히 중요합니다.

예:

 
driver.execute_script("window.scrollTo(0, document.body.scrollHeight);")
 

이건 페이지 맨 아래로 스크롤합니다.


왜 중요한가?

요즘 많은 웹페이지는 처음에 전체 데이터를 다 보여주지 않습니다.

예:

  • 아래로 내려야 다음 카드 로딩
  • 일정 높이까지 내려야 광고/팝업 처리
  • 스크롤 이벤트로 JavaScript가 실행됨

즉, 스크롤도 Selenium에서 매우 중요한 제어 동작입니다.


21. JavaScript 실행: execute_script()

Selenium은 브라우저 안에서 JavaScript를 직접 실행할 수도 있습니다.

예:

 
driver.execute_script("window.scrollTo(0, 500);")
 

또는 요소를 클릭이 잘 안 될 때:

 
driver.execute_script("arguments[0].click();", element)
 

이런 식으로 우회하기도 합니다.

즉, Selenium은 단순 클릭 도구가 아니라
브라우저 내부 동작까지 직접 제어할 수 있는 자동화 도구입니다.


22. 대기(wait)가 왜 중요한가?

Selenium은 브라우저를 조작하지만,
웹페이지는 항상 즉시 로딩되지 않습니다.

즉, 버튼을 눌렀다고 해서
바로 다음 요소가 나타난다는 보장이 없습니다.

이때 자주 생기는 문제가:

  • 요소를 찾으려 했는데 아직 안 뜸
  • 페이지 전환은 됐는데 DOM 갱신 전임
  • 비동기 로딩 중인데 코드는 너무 빨리 다음 단계로 감

입니다.

그래서 Selenium에서는 대기(wait) 개념이 매우 중요합니다.

이 파트에서는 개념 중심으로 이해하고,
더 자세한 대기 처리와 예외 처리는 다음 파트에서 깊게 다룰 수 있습니다.


23. 암시적 대기(Implicit Wait) 개념

예:

 
driver.implicitly_wait(5)
 

이건 요소를 찾을 때 최대 5초 정도 기다리겠다는 의미입니다.

즉, 페이지 로딩이 조금 느려도
바로 실패하지 않고 기다릴 수 있습니다.


24. 명시적 대기(Explicit Wait) 개념

특정 조건이 만족될 때까지 기다리는 방식입니다.

예:

  • 버튼이 클릭 가능해질 때까지 기다리기
  • 특정 요소가 화면에 나타날 때까지 기다리기
  • 텍스트가 변경될 때까지 기다리기

이건 실전에서 훨씬 더 강력하고 중요합니다.
다음 파트에서 예외 처리와 함께 더 자세히 보는 것이 자연스럽습니다.


25. Selenium에서 자주 만나는 예외 상황

Selenium은 강력하지만 그만큼 자주 에러도 만납니다.

예:

  • 요소를 못 찾음
  • 클릭하려는데 가려져 있음
  • 페이지가 덜 로딩됨
  • 이전 페이지 요소를 계속 들고 있어서 stale element 발생
  • 팝업 때문에 뒤 요소를 못 누름

즉, Selenium은 단순히 “클릭하는 코드”가 아니라
페이지 상태 변화까지 고려해야 하는 도구입니다.

이 점이 requests + BeautifulSoup보다 더 복잡한 이유입니다.


26. requests + BeautifulSoup와 Selenium 차이 다시 정리

requests + BeautifulSoup

  • HTML을 요청해 가져옴
  • 빠르고 가벼움
  • 정적 페이지에 강함
  • 브라우저를 실제로 열지 않음

Selenium

  • 브라우저를 실제로 열고 조작함
  • 클릭, 입력, 스크롤 가능
  • 동적 페이지에 강함
  • 상대적으로 느리고 무거움

즉, Selenium은 BeautifulSoup의 대체재가 아니라
필요한 상황이 다른 도구입니다.


27. Selenium이 범용적으로 중요한 이유

Selenium은 특정 사이트 크롤링에만 쓰는 도구가 아닙니다.
범용적으로 다음 영역까지 확장됩니다.

  • 쇼핑몰 자동화
  • 로그인 자동화
  • 검색 자동화
  • 뉴스/부동산/중고차 목록 수집
  • 웹 테스트 자동화
  • 폼 자동 입력
  • 브라우저 반복 작업 자동화
  • QA 테스트
  • 사내 업무 자동화

즉, Selenium은
웹페이지를 자동으로 다루는 전반적인 도구라고 이해해야 합니다.


28. 기본적인 Selenium 흐름 예시

 
from selenium import webdriver
from selenium.webdriver.common.by import By

driver = webdriver.Chrome()
driver.get("https://example.com")

items = driver.find_elements(By.CSS_SELECTOR, ".car-item")

cars = []

for item in items:
brand = item.find_element(By.CSS_SELECTOR, ".brand").text
price = item.find_element(By.CSS_SELECTOR, ".price").text

cars.append({
"brand": brand,
"price": price
})

print(cars)

driver.quit()
 

이 코드 안에는 Selenium의 가장 기본적인 흐름이 들어 있습니다.

  • 브라우저 열기
  • 페이지 이동
  • 요소 여러 개 찾기
  • 반복문으로 돌기
  • 하위 요소 텍스트 추출
  • 결과 저장
  • 브라우저 종료

이 흐름을 이해하면 다른 사이트에도 쉽게 응용할 수 있습니다.


29. 브라우저 종료하기: quit()

예:

 
driver.quit()
 

이건 브라우저를 완전히 종료합니다.

왜 중요할까요?

  • 테스트 중 브라우저가 계속 쌓이지 않게 하기 위해
  • 자원 낭비를 막기 위해
  • 프로세스를 깔끔하게 정리하기 위해

즉, Selenium에서는 시작만큼 종료도 중요합니다.


30. 범용적으로 꼭 익혀야 하는 Selenium 사고방식

30-1. 페이지는 “상태(state)”가 바뀐다

requests + BeautifulSoup는 보통 한 번 받은 HTML을 보는 느낌이 강합니다.
반면 Selenium은 클릭, 입력, 스크롤 후에 페이지 상태가 바뀝니다.

즉, Selenium에서는 항상:

  • 지금 어떤 상태인가
  • 클릭 후 무엇이 바뀌었나
  • 새로 다시 찾아야 하나

를 생각해야 합니다.


30-2. 큰 구조 먼저, 세부 요소 나중

반복되는 카드 목록을 먼저 찾고,
그 안에서 브랜드/가격/링크를 찾는 방식이 안정적입니다.


30-3. 바로 찾지 말고 “언제 나타나는지”도 생각해야 한다

동적 페이지에서는 요소 존재 여부뿐 아니라
등장 시점도 중요합니다.

즉, Selenium은 단순 탐색이 아니라 시간 개념이 들어갑니다.


30-4. 눈에 보인다고 바로 가져올 수 있는 것은 아니다

때로는:

  • 팝업이 가리고 있거나
  • iframe 안에 있거나
  • 로딩이 덜 끝났거나
  • 스크롤 후에야 활성화될 수 있습니다

즉, Selenium은 항상 화면 상태 + DOM 상태 + 타이밍을 함께 봐야 합니다.