셀레니움 (Selenium)
- 동적 웹 페이지와 Ui를 다룰 수 있게 해주고 웹 브라우저를 조작할 수 있는 Python 자동화 프레임워크
Selenium 시작하기
(✅ Chrome 설치 필수)
1. Selenium 라이브러리 설치
%pip install selenium
%pip install webdriver-manager
2. 웹 브라우저를 제어할 수 있게 해주는 WebDriver가 필요
# selenium으로부터 webdriver 모듈을 불러옵니다.
from selenium import webdriver
from selenium.webdriver.chrome.service import Service
from webdriver_manager.chrome import ChromeDriverManager
3. 요청 보내보기 .get(url)
# http://www.example.com 으로 요청을 보내봅시다.
driver.get("http://www.example.com")
4. 응답 받은 후, page_source 속성을 통해 응답된 HTML문서 확인
# page_source 속성을 확인해봅시다.
print(driver.page_source)
<html><head>
<title>Example Domain</title>
<meta charset="utf-8">
<meta http-equiv="Content-type" content="text/html; charset=utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<style type="text/css">
body {
background-color: #f0f0f2;
margin: 0;
padding: 0;
font-family: -apple-system, system-ui, BlinkMacSystemFont, "Segoe UI", "Open Sans", "Helvetica Neue", Helvetica, Arial, sans-serif;
}
div {
width: 600px;
margin: 5em auto;
padding: 2em;
background-color: #fdfdff;
border-radius: 0.5em;
box-shadow: 2px 3px 7px 2px rgba(0,0,0,0.02);
}
a:link, a:visited {
color: #38488f;
text-decoration: none;
}
@media (max-width: 700px) {
div {
margin: 0 auto;
width: auto;
}
}
</style>
</head>
<body>
<div>
<h1>Example Domain</h1>
<p>This domain is for use in illustrative examples in documents. You may use this
domain in literature without prior coordination or asking for permission.</p>
<p><a href="https://www.iana.org/domains/example">More information...</a></p>
</div>
</body></html>
5. Chrome 종료 명령 내리기
- with-as 구문을 통해 주어진 명령이 끝나면 driver를 종료하도록 설정 가능
# with-as를 사용해서 위 코드를 다시 적어봅시다.
with webdriver.Chrome(service=Service(ChromeDriverManager().install())) as driver:
driver.get("http://www.example.com")
print(driver.page_source)
6. Driver에서 특정 요소 추출하기
- 요소 하나 찾기
- .find_element(by, target)
- by : 대상을 찾는 기준 (ID, TAG_NAME, CLASS_NAME),...
- target : 대상의 속성
- 요소 여러개 찾기
- .find_elements(by, target)
- by : 대상을 찾는 기준 (ID, TAG_NAME, ClASS_NAME, ...)
- target : 대상의 속성
- 위 명령어를 사용하려면 By를 import해야 함
from selenium.webdriver.common.by import By
- p 태그에 해당하는 요소 하나 찾기 .find_element(by, target)
# p 태그에 해당하는 요소 하나를 찾아봅시다.
with webdriver.Chrome(service=Service(ChromeDriverManager().install())) as driver:
driver.get("http://www.example.com")
print(driver.find_element(By.TAG_NAME,"p").text)
- p 태크에 해당하는 요소 여러개를 찾기 .find_elements(by, target)
# p 태그에 해당하는 요소 여러개를 찾아봅시다.
with webdriver.Chrome(service=Service(ChromeDriverManager().install())) as driver:
driver.get("http://www.example.com")
for i in driver.find_elements(By.TAG_NAME,"p"):
print("Text: "i.text)
Wait and Call
1. Wait을 이용해 동적 웹 사이트를 스크래핑 해보기
- Selenium은 동적 웹 사이트에 대한 지원을 진행하기 위해 명시적 기다림(Explicit Wait)과 암묵적 기다림(Implicit Wait)을 지원
- Explicit Wait: 다 로딩이 될 때까지 지정한 시간 동안 기다림 (e.g. 로딩이 완료 될 때까지 5초동안 기다려!)
- Implicit Wait: 특정 요소에 대한 제약을 통한 기다림 (e.g. 이 태그를 가져올 수 있을 때까지 기다려!)
2. XPath 활용
- XPath는 XML, HTML 문서 등의 요소 위치를 경로로 표현하는 것을 의미 (ex.컴퓨터 시스템에서 "데크스탑/폴더1/폴더2/음악.mp3" 와 같은 구조)
- 원하는 Website(Chrome 환경)에 접속해 원하는 요소에 우클릭 후 검사 클릭
- 하이라이트 된 Elements에 우클릭 -> Copy -> Copy XPath를 클릭하면 해당 요소의 경로를 복사할 수 있음
3. 예시 사이트에 요청
예시 사이트 : https://indistreet.com/live?sortOption=startDate%3AASCc
찾는 요소 : //*[@id="__next"]/div/main/div[2]/div/div[4]/div[1]/div[1]/div/a/div[2]/p[1]
# 스크래핑에 필요한 라이브러리를 불러와봅시다.
from selenium import webdriver
from selenium.webdriver.chrome.service import Service
from selenium.webdriver.common.by import By
from webdriver_manager.chrome import ChromeDriverManager
# 예시 사이트에 요청을 진행하고, 예시 사이트의 첫 번째 이벤트의 제목을 가져와봅시다.
driver = webdriver.Chrome(service = Service(ChromeDriverManager().install()))
driver.get("https://indistreet.com/live?sortOption=startDate%3AASC")
driver.find_element(By.XPATH, '//*[@id="__next"]/div/main/div[2]/div/div[4]/div[1]/div[1]/div/a/div[2]/p[1]')
- 명령어 실행 시 해당 요소를 찾지 못하는 오류가 발생
- 동적 웹페이지이기 때문에 요청 후 로딩 완료되기 까지 시간이 걸림
- 이 페이지를 성공적으로 스크래핑하기 위해서는 Wait을 사용해야함
---------------------------------------------------------------------------
NoSuchElementException Traceback (most recent call last)
Input In [9], in <cell line: 6>()
3 driver = webdriver.Chrome(service = Service(ChromeDriverManager().install()))
5 driver.get("https://indistreet.com/live?sortOption=startDate%3AASC")
----> 6 driver.find_element(By.XPATH, '//*[@id="__next"]/div/main/div[2]/div/div[4]/div[1]/div[1]/div/a/div[2]/p[1]'
...
4. Wait 사용하기
- Implicit Wait
# 10초동안 Implicit Wait을 진행하도록 해서 스크래핑이 잘 이루어지도록 수정해봅시다.
from selenium.webdriver.support.ui import WebDriverWait
with webdriver.Chrome(service = Service(ChromeDriverManager().install())) as driver:
driver.get("https://indistreet.com/live?sortOption=startDate%3AASC")
driver.implicitly_wait(10)
print(driver.find_element(By.XPATH, '//*[@id="__next"]/div/main/div[2]/div/div[4]/div[1]/div[1]/div/a/div[2]/p[1]').text)
- Explicit Wait
- until() : 인자의 조건이 만족될 때 까지
- until_not() : 인자의 조건이 만족되지 않을 때 까지
예를 들어, id가 target인 요소가 존재할 때까지 기다린 후 다음 명령을 진행한다.
element = WebDriverWait(driver, 10).until(EC.presence_of_element_located((By.ID, "target")))
이때, EC는 expected_conditions로, selenium에서 정의된 조건이다. (~가 존재하면, ...)
아래 사이트에서 더 자세한 정보 확인이 가능하다.
https://www.selenium.dev/selenium/docs/api/py/webdriver_support/selenium.webdriver.support.expected_conditions.html
selenium.webdriver.support.expected_conditions — Selenium 4.8 documentation
An expectation for checking that an element, known to be present on the DOM of a page, is visible. Visibility means that the element is not only displayed but also has a height and width that is greater than 0. element is the WebElement returns the (same)
www.selenium.dev
# Explicit Wait를 활용해서 스크래핑이 잘 이루어지도록 코드를 작성해봅시다.
from selenium.webdriver.support import expected_conditions as EC
with webdriver.Chrome(service = Service(ChromeDriverManager().install())) as driver:
driver.get("https://indistreet.com/live?sortOption=startDate%3AASC")
element = WebDriverWait(driver,10).until(EC.presence_of_element_located((By.XPATH, '//*[@id="__next"]/div/main/div[2]/div/div[4]/div[1]/div[1]/div/a/div[2]/p[1]')))
print(element.text)
5. 여러 공연 제목 가져오기
- 여러 공연의 제목들을 가져오기 위해 XPath를 관찰해보기
이 페이지의 공연 제목들에 해당하는 XPath는 다음과 같다.
//*[@id="__next"]/div/main/div[2]/div/div[4]/div[1]/div[1]/div/a/div[2]/p[1]
//*[@id="__next"]/div/main/div[2]/div/div[4]/div[1]/div[2]/div/a/div[2]/p[1]
//*[@id="__next"]/div/main/div[2]/div/div[4]/div[1]/div[3]/div/a/div[2]/p[1]
...
이를 일반화해서 가장 먼저 등장하는 10개의 이름을 추출하는 코드를 작성해보기
# 여러 공연의 제목을 스크래핑하는 코드를 작성해봅시다.
from selenium.webdriver.support import expected_conditions as EC
with webdriver.Chrome(service = Service(ChromeDriverManager().install())) as driver:
driver.get("https://indistreet.com/live?sortOption=startDate%3AASC")
driver.implicitly_wait(10)
for i in range(1, 11):
element = driver.find_element(By.XPATH, '//*[@id="__next"]/div/main/div[2]/div/div[4]/div[1]/div[{}]/div/a/div[2]/p[1]'.format(i))
print(element.text)
'Programmers TIL' 카테고리의 다른 글
[DataWearhouse] Snowflake_TIL (4) | 2023.05.25 |
---|---|
[DataWearhouse] Redshift 고급 기능_TIL (1) | 2023.05.24 |
[Web] Django(Serializer)_TIL Day13 (2) | 2023.04.26 |
[Web] Django_TIL Day11-1 (1) | 2023.04.24 |
[Algorithm] 큐(Queues)_TIL Day3-1 (1) | 2023.04.12 |