1️⃣ 셀레니움?

크롤링(혹은 스크래핑) 툴로 유명한 셀레니움. 셀레니움은 웹 애플리케이션의 자동화와 테스트를 위해 만들어진 프레임워크입니다. 이 기능들을 이용해 기존 방법으로 스크래핑이 어려운 동적 페이지들을 스크래핑하는 데 많이 이용됩니다.

셀레니움은 “자동화” 프레임워크라고 전 단락에서 이야기했죠. 이 말은 웹페이지에 띄워지는 요소들, 그리고 웹페이지에서 할 수 있는 동작들을 제어할 수 있다는 것입니다. 서치박스에 검색어를 입력한다던가, 다음 페이지로 이동한다던가, 페이지에 있는 이미지를 다운로드 받는 등의 기능도 셀레니움으로 구현이 가능합니다.

웹 페이지의 소스를 읽어와 스크래핑하는 방법 (HTML + Beautifulsoup) 은 자바스크립트로 동적으로 생성된 정보를 가져올 수 없다는 한계가 있었습니다. 셀레니움을 통하면 웹페이지에서 특정 동작을 취하게끔 할 수 있기 때문에 그러한 한계를 돌파할 수 있죠.

셀레니움은 파이썬과 함께 많이 언급되지만, 자바로 프로그래밍된 프레임워크이며 따라서 파이썬과 자바 외로도 다양한 언어에서 사용할 수 있는 툴입니다.

Info
본 포스트에서는 “파이썬”에서 셀레니움을 사용하는 방법에 대해 다룹니다.



2️⃣ Installation

(1) 셀레니움 설치(파이썬)

pip로 설치해줍니다.

1
pip install selenium

(2) 크롬 드라이버 다운로드

크로미움 사이트에서 다운로드 합니다.
구글에서 chrome driver 를 검색하거나 아래 url에 들어가서 받아주세요.

https://chromedriver.chromium.org/downloads

Info
115버전 이상부터는 cfT (chrome for Testing)으로 통합해서 사용할 수도 있습니다.



3️⃣ 사용하기

(1) 셀레니움 시작

셀레니움을 시작할 때에는 크롬드라이버 객체를 생성하고, 이를 통해 크롤링하려는 url을 열어야 합니다.
이렇게 하면 “테스트용 크롬”이 열리면서 해당 크롬에서 크롤링이 진행됩니다.

크롬드라이버 객체는 이렇게 열린 “테스트용 크롬”이라고 보면 되는거죠!

(1) 크롬드라이버 지정
(2) url driver 객체 생성

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
import selenium
from selenium import webdriver
from selenium.webdriver.common.by import By

chromdriverPath = "크롬/설치파일/path"
url = "크롤링할url"

# 크롬드라이버 객체 생성
try:
    driver = webdriver.Chrome(chromdriverPath)
    driver.implicitly_wait(sleepTime)
except Exception as e:
    print(f"An error occurred: {e}")

# 크롤링할 url driver 객체 생성
driver.get(url)

(2) 셀레니움 사용하기

먼저, 셀레니움에는 웹페이지의 요소를 특정하여 “객체”로 만드는 게 시작입니다.
요소를 특정할 때에는 find_element 혹은 find_elements 메서드를 사용합니다.

find_element
조건에 맞는 요소 “하나”를 특정하여 객체를 만듭니다. 조건에 맞는 요소가 여러개일 경우, 가장 첫 요소가 특정됩니다.

find_elements
조건에 맞는 요소 “전부”를 특정합니다. 조건에 맞는 요소들을 리스트에 담아 반환합니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
import selenium
from selenium import webdriver
from selenium.webdriver.common.by import By

# 요소를 특정해 객체를 생성
object_1 = find_element(By.요소를찾을방법, "요소조건")
object_2 = find_elements(By.요소를찾을방법, "요소조건")

# 요소를 찾을 방법은 아래와 같습니다.
By.CSS_SELECTOR
By.NAME
By.XPATH
By.LINK_TEXT
By.PARTIAL_LINK_TEXT
By.TAG_NAME

# 예시1. find_element (쿠키 알림창 닫기 버튼)
target = "#onetrust-close-btn-container > button"
cookie_colose_button = driver.find_element(By.CSS_SELECTOR, target)

# 예시2. find_elements (멀티로우)
target = "body > div.abc > div.abc.def.gh > div > section.table-section > mat-table > mat-row"
mat_row_list = driver.find_elements(By.CSS_SELECTOR, target)


이렇게 특정한 객체에서 content(내용)을 추출할 수 있습니다.
대표적인 예로, 특정한 객체 안에 있는 글자를 .text() 메서드로 추출해봅시다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
# element
target = "#onetrust-close-btn-container > title"
object_title = driver.find_elements(By.CSS_SELECTOR, target)
print(object_title.text)

>>> "타이틀내용 123"

# elements
target = "body > div.abc > div.abc.def.gh > table-section > mat-table > mat-row"
mat_row_list = driver.find_elements(By.CSS_SELECTOR, target)

for row in mat_row_list:
    print(row.text)

>>> "1번 행 : 내용 123"
>>> "2번 행 : abasdwd"
>>> "3번 행 : 안녕하세요"
>>> "4번 행 : 내용23"
>>> ...

그리고 특정한 객체에 “동작”을 부여할 수도 있습니다.
사람이 하는 것 처럼 클릭, 검색창에 입력, 체크박스, 창 닫기 등을 할 수 있습니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# 클릭
button = driver.find_elements(By.CSS_SELECTOR, "body > div.abc > next-page")
button.click()

# 새 창으로 이동 (0:첫 번째 창, 1:두 번째 창 ...)
driver.switch_to.window(driver.window_handles[1])

# 창 닫기
driver.close()

# 검색창에 검색어 넣기
driver.find_element("id",'search-box').send_keys(searchWord)

# 검색창을 공백으로 비우기
driver.find_element("id",'search-box').clear()

# 스크롤 (화면의 x, y 좌표로 스크롤)
driver.execute_script("window.scrollTo(x, y)")

(3) 추가 기능

최소화

1
2
3
4
5
6
import selenium
from selenium import webdriver

driver = webdriver.Chrome(chromdriverPath)
driver.minimize_window()
driver.get(url)

창 숨기기 (백그라운드 크롤링)

1
2
3
4
5
6
7
8
import selenium
from selenium import webdriver

options = webdriver.ChromeOptions()
options.add_argument("headless")     # 창 숨기기 옵션 추가

driver = webdriver.Chrome(chromdriverPath, chrome_options=options)
driver.get(url)

info
백그라운드 실행은 사이트에 따라 불가능한 경우도 있습니다.
이럴 때에는 Chrome 의 정보를 꾸며내어 사이트의 탐지를 우회하는 방법을 사용해야 합니다.

User Agent 수정

1
2
3
4
5
import selenium
from selenium import webdriver

options = webdriver.ChromeOptions()
options.add_argument("User Agent 정보")



(4) 웹페이지에서 요소를 찾는 방법

요소를 특정하기 위해서는 웹사이트에서 요소를 찾아갈 수 있는 경로(주소)가 필요합니다.
앞서 설명한 것과 같이 id나 class 등이 있습니다.

그러나 복잡한 웹사이트에서는 하나하나 경로를 찾아 적기가 힘듭니다.
이럴 때엔 크롬 개발자도구의 요소 복사 기능을 사용하면 편합니다.

아래는 쿠키 알림창을 닫는 버튼의 경로(주소)를 찾는 예시입니다.

F12 버튼을 클릭하면 개발자 도구가 열립니다.
여기서 “검사할 페이지 요소” 를 이용해서

닫는 버튼의 html 소스상 위치를 찾아냅니다.

이 부분을 오른쪽 마우스 클릭 후 Copy 에서 해당 요소의 경로(주소)를 복사할 수 있습니다.
여기서 CSS selector, XPath 등의 경로를 복사할 수 있습니다.

이렇게 찾은 CSS selector Path 로 닫기 버튼 요소를 찾은 뒤, Click 동작을 취해주면 쿠키창을 닫을 수 있죠.

1
2
button = driver.find_elements(By.CSS_SELECTOR, "쿠키창CSSselectorPATH")
button.click()

(5) 셀레니움 종료

셀레니움으로 동작하고 있는 브라우저의 창 “하나만” 닫을 경우엔 close 메서드를 사용합니다. 하지만 셀레니움 자체가 종료되지는 않을 수 있으니 주의하세요. 셀레니움 자체가 종료되지 않으면 불필요한 리소스가 소모될 수 있습니다.

셀레니움 전체를 종료시키려면 quit 메서드를 사용하면 됩니다.

1
2
driver.close()   # 활성화된 창만 1개 종료
driver.quit()    # 셀레니움 전체 종료



4️⃣ TroubleShooting

CSS에서 공백이 있는 경우엔 공백 대신 닷(.) 을 사용해줍니다.

1
2
3
4
5
6
# 원본
body > div.row mr-0 ml-0 ng-star-inserted > div.col-sm-6 col-md-6 col-lg-6 details-tile > div.row mr-0 ml-0 mb-36

# 수정
body > div.row.mr-0.ml-0.ng-star-inserted > div.col-sm-6.col-md-6.col-lg-6.details-tile > div.row.mr-0.ml-0.mb-36



5️⃣ Reference

셀레니움에 대한 설명 : 위키피디아 : 셀레늄
셀레니움 설치 : https://wikidocs.net/91474
셀레니움 사용하기 : https://velog.io/@agzg
HTML 요소에 대한 설명 : https://okiidokii.tistory.com/105
요소의 경로를 찾는 방법 : https://heodolf.tistory.com/80#google_vignette
셀레니움 스크롤 : https://hello-bryan.tistory.com/194
셀레니움 종료 : https://ssoondata.tistory.com/132
셀레니움 최소화 : https://ko.code-paper.com
셀레니움 백그라운드 : https://ssoondata.tistory.com/m/131
셀레니움 백그라운드 : https://beomi.github.io