웹 애플리케이션 자동화 및 테스트를 위한 포터블 *프레임워크이다. Java,Ruby,Python 등 다양한 언어를 지원한다. 아파치 라이선스하에 오픈 소스로 이용할 수 있다.
거기에, 웹 스크래핑(크롤링)도 지원해준다. Selenium과 Python을 활용해서 크롤링을 해보자.
* 프레임워크와 라이브러리의 차이
| 프레임워크 | 라이브러리 |
|---|---|
| 폴더명, 파일명에 규칙 있음. | 폴더명, 파일명에 규칙 없음. |
| ex) 비행기로 목적지 가기 | ex) 가위로 종이 자르기 |
| 자유도↓ | 자유도↑ |
pip install selenium

가상환경에 selenium을 설치한다. pip list 로 설치된 라이브러리 확인 가능하다.
Selenium을 활용해서 나무위키의 텍스트들을 한번 crawling해보자.

Selenium은 로그인, 스크롤 등 사용자 행동을 자동화할 수 있어, JavaScript 기반으로 동적으로 구성된 웹 페이지에도 직접 접근하고 조작할 수 있다는 것이 가장 큰 특징이다. 이는 정적인 HTML 구조만을 크롤링할 수 있는 BeautifulSoup과의 가장 큰 차이점이다.

Chrome 브라우저에서 F12 키를 누르면 개발자 도구가 열리며, 웹페이지의 HTML 태그 구조를 직접 확인할 수 있다.
from selenium import webdriver
from selenium.webdriver.common.by import By
import time
크롤링을 시작할 때는 보통 위의 세 가지 모듈을 기본적으로 import해준다.
- selenium.webdriver: 실제 브라우저를 자동으로 열고 제어하기 위한 핵심 모듈이다.
- By: 특정 요소를 태그, 클래스, id 등 다양한 기준으로 찾기 위해 사용되는 셀렉터 도구다.
- time: 웹 페이지가 완전히 로드될 때까지 잠시 기다리는 sleep() 같은 함수에 사용된다.
이 세 가지는 Selenium으로 웹 페이지를 탐색하고 데이터를 수집할 때 가장 기본이 되는 도구들이며, 이후 자동화 과정의 출발점이 된다.
from selenium.webdriver.chrome.options import Options
chrome_options=Options()
chrome_options.add_experimental_option("detach",True)
위 옵션은 크롬 브라우저 창이 코드 실행 후에 자동으로 닫히지 않게 해주는 설정이다. Selenium은 기본적으로 창을 냅다 닫아버려서, 눈으로 확인하고 싶은 분들께 강추한다. (4.6이상 version 사용가능)
driver=webdriver.Chrome(options=chrome_options)
driver.get(url) # 사용자 입력 url
time.sleep(10)
Selenium에서 webdriver.Chrome() 을 사용하면, 실제 크롬 브라우저를 자동으로 실행할 수 있다.
이때 사용하는 크롬 드라이버(ChromeDriver) 는 구글에서 공식적으로 제공하며, 최신 버전의 Selenium에서는 따로 설치할 필요 없이 자동으로 다운로드되고 연결된다.
크롬 드라이버 실행:
webdriver.Chrome()을 통해 크롬 브라우저 인스턴스를 생성한다.웹 페이지 접속:
driver.get(url)을 이용해 원하는 URL로 이동한다.페이지 로딩 대기:
JavaScript 렌더링이 완료되기까지 약간의 시간이 필요하므로,time.sleep(10)으로 잠시 대기한다.


F12 를 눌러 위 빨간색 부분을 클릭하면, 내가 크롤링하고 싶은 부분이 어떤 JS코드로 작성되어 있는지 구문을 확인할 수 있다.
이 과정을 통해서, 웹페이지의 어떤 정보를 활용하여 크롤링할 것인지 정하면 된다. 아래의 다양한 Locator중 방법을 선택해서, 접근할 수 있다.
태그를 복사해본 결과, 해당 페이지의 본문은 다양한 HTML 태그와 링크로 구성되어 있는 것을 확인할 수 있다.따라서, HTML 태그들과 CSS 클래스가 어떻게 사용되고 있는지 구조를 살펴보았다.
| 태그 | 역할 | 위 태그에서의 예시 |
|---|---|---|
<div> | 웹 페이지 내용에서 논리적 구분을 정의하는 태그 | <div class="M8xPxt04">...</div> |
<a> | 하이퍼링크를 걸어주는 태그 | <a href="/w/심리상담">심리상담</a> |
<br> | 텍스트에서 줄을 바꾸는 줄바꿈(line break)을 나타내는 태그 | <br> |
| 클래스 이름 | 역할 | 비고 |
|---|---|---|
| M8xPxt04 | 본문 전체 블록 (문단 컨테이너) | 보통 텍스트가 있는 주요 블록 |
| LY6OJ4Og | 내부 링크 (<a>)에 공통적으로 붙음 | 내부 문서 링크 스타일 지정 |
| _7V+kjHDF | 외부 링크에 적용된 스타일 | 외부 학회 링크에 적용됨 |
클래스 이름들은 난수처럼 보이는 문자열로 되어 있는데, 이는 대부분 자동 빌드 툴이나 프레임워크(Vue 등) 에서 생성한 것으로, 의미 있는 명칭이 아닐 수 있다. 이 중에서도 M8xPxt04 클래스는 실제 본문 콘텐츠에 반복적으로 등장하며, 크롤링 대상 블록을 식별하는 데 유용하게 사용할 수 있다.

다른 본문에 해당하는 부분들도 M8xPxt04 클래스를 사용하는 것을 확인할 수 있다. By.CLASS_NAME 을 활용해서 크롤링을 진행하자
document = driver.find_elements(By.CLASS_NAME, 'M8xPxt04')
앞서 확인한 M8xPxt04 클래스는 실제 본문 텍스트가 담긴 블록 요소에 해당한다.
따라서 해당 클래스를 기준으로 find_elements()를 사용하면, 해당 조건을 만족하는 모든 요소들을 한 번에 가져올 수 있다.
여기서 find_elements()는 find_element()와 달리, 복수의 요소들을 리스트 형태로 반환하며,
조건에 맞는 모든 태그에 접근하고자 할 때 사용된다.
>>print(document)
[<selenium.webdriver.remote.webelement.WebElement (session="9e5da2b47ce958851828291477068187", element="f.178E7223E4C225C410A685AD10772AB1.d.6612046AEAF5DFD5A9715D3ABA2258FF.e.12")>,...
실제로 print해보면 영문을 알 수 없는 값들이 들어가 있는 것을 확인할 수 있다. 실제로 text 값을 확인하기 위해서는 .text로 접근해야 하기 때문이다.
Python을 활용해서 전체 본문을 모두 긁어오기 위해
texts=[block.text.strip() for block in document if block.text.strip()] # text가 존재하면
crawled_results=" ".join(texts)
print(crawled_results)
위와 같이 text.strip()으로 값이 없다면(빈 문자열이면) pass하고 나머지는 모두 texts 리스트에 넣어 띄어쓰기 단위로 결합하면, M8xPxt04 클래스를 가지는 text값을 모두 불러올 수 있다.


이번에 Selenium을 쓰긴했지만 사실 동적으로 클릭을 한다거나 스크롤을 내린다거나 특정 액션을 취하거나 하지는 않았다...! Selenium으로 굳이 크롤링 안해도 됐을 것 같은데, 뭔가 굳이굳이 스마트폰으로 1+1 계산한 기분..? 그래서 다음에는 실제로 스크롤을 내리거나 검색하거나 클릭해야 보이는 것들을 크롤링해봐야겠다.