[Web] 웹 데이터 크롤하고 분석하기(Selenium)_TIL Day9-1

셀레니움 (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