데이터분석/미니프로젝트 03. 유가 분석

미니프로젝트 03-01-02. selenium으로 셀프주유소 데이터 확인

책다니엘 2024. 4. 14. 04:49

1. 이번 미니프로젝트에서는 셀프주유소가 정말 저렴한가?라는 주제로 selenium과 bs를 이용해 데이터를 크롤링하고 활용한다. 먼저 유가 데이터를 확인할 수 있는 사이트는 아래와 같다.

https://www.opinet.co.kr/user/main/mainView.do

 

싼 주유소 찾기 오피넷

 

www.opinet.co.kr

 

2. 사이트의 구조를 확인한다. 우리의 목표는 브랜드, 가격, 셀프 주유 여부, 위치이다.

https://www.opinet.co.kr/searRgSelect.do

 

싼 주유소 찾기 오피넷

 

www.opinet.co.kr

해당 페이지의 구조를 보면, '지역'에서 광역시도와 시구 정보를 입력한다. -> 지도가 업데이트된다 -> 주유소 정보가 로딩된다 식으로 된다는 것을 알 수 있다. 

아래 부분을 보면, 셀프 여부도 알려주고, 휘발유/경유 가격도 표시해주지만, 상표와 주소 정보를 다루기가 좀 까다로워보인다. 오른쪽 하단의 '엑셀저장' 기능을 이용하여 다운받은 파일 안에는 필요한 정보가 모두 존재한다.

 

그렇다면 서울 지역의 주유소에 대해 분석하려면 서울 -> 각 구를 번갈아 선택 -> 엑셀파일을 다운로드 -> 다운로드받은 엑셀파일을 분석하는 순서로 진행하면 좋을 것이다.

 

또한 주소를 변경해도, url이 변경되지 않는다는 특징이 보인다. beautifulsoup을 응용한 html 접근으로도 원하는 결과를 얻기 어려워 보인다. 따라서 selenium을 통해 페이지 자체에 접근해야 한다.

 

3. 먼저 selenium을 통해서 주유소 검색 페이지에 접근해보자.

from selenium import webdriver

driver = webdriver.Chrome()
driver.get('https://www.opinet.co.kr/')

# Mac의 경우 크롬드라이버 권한을 줘야 한다

 

4. 지역별 주유소 현황 페이지에 들어간 다음, 지역에서 '서울'을 클릭하는 것부터 도전해보자.

먼저 크롬 개발자도구로 지역의 가장 큰 option항목을 클릭해 보았다.
그런데 원하는 부분이 표시되지 않는다. 더 하부 항목으로 내려가보자.

driver.get('https://www.opinet.co.kr/searRgSelect.do')
some_tag = driver.find_element(By.CSS_SELECTOR, '#SIDO_NM0 > option:nth-child(2)')
some_tag.click()

제대로 '서울'을 받아온다. 그 다음에는 '시군구'의 리스트를 받아와서 각각 클릭하도록 반복문을 돌릴 수 있게 해야 한다.

gu_list_raw = driver.find_element(By.CSS_SELECTOR, '#SIGUNGU_NM0')
gu_list = gu_list_raw.find_elements(By.CSS_SELECTOR, 'option')
gu_names = [option.get_attribute('value') for option in gu_list]
gu_names

gu_names를 받아 왔다.

5. 이상의 정보를 바탕으로 우리는 다음과 같이 '시/군/구'를 클릭하는 코드를 짤 수 있다.

# gu_list_raw(시군구 항목) 초기화
gu_list_raw = driver.find_element(By.CSS_SELECTOR, '#SIGUNGU_NM0')
gu_list_raw.send_keys(gu_name)

 

6. 그렇다면 간단한 반복문으로 시/군/구를 모두 클릭하게 하는 코드도 짤 수 있을 것이다.

for gu_name in gu_names:
    gu_list_raw = driver.find_element(By.CSS_SELECTOR, '#SIGUNGU_NM0')
    gu_list_raw.send_keys(gu_name)

위 코드를 실행시키면 실제로 페이지에서 시군구를 순회해가며 클릭한다.

 

7. 그 다음에는 '엑셀 저장'을 클릭해야 한다. 태그를 하나 찾아 클릭해보자.

exel_download = driver.find_element(By.CSS_SELECTOR, '#templ_list0 > div:nth-child(7) > div > a')
exel_download.click()

엑셀파일을 잘 다운로드하는 것을 알 수 있다.

8. 그렇다면 반복문으로 서울의 모든 시/군/구를 선택하여 엑셀파일을 저장하는 코드를 짤 수 있을 것이다. 간단히 tqdm까지 활용하여 더 보기 좋게 짜보자. 또한, 단순반복문으로는 '시군구 리스트 클릭' 동작과 '엑셀 다운로드' 사이에 공백이 없으니 웹페이지 로딩 속도가 코드 실행 속도를 따라오지 못한다. 그러므로 time모듈을 이용해서 명령 사이에 잠깐 공백을 주자.

import time
from tqdm import tqdm_notebook

for gu_name in tqdm_notebook(gu_names):
    # 시군구 리스트 클릭
    gu_list_raw = driver.find_element(By.CSS_SELECTOR, '#SIGUNGU_NM0')
    gu_list_raw.send_keys(gu_name)
    time.sleep(2)

    # 엑셀 다운로드    
    exel_download = driver.find_element(By.CSS_SELECTOR, '#templ_list0 > div:nth-child(7) > div > a')
    exel_download.click()
    time.sleep(1)

엑셀파일을 잘 다운로드받았다. 이제 이 파일들을 실행하여 DataFrame화해야한다.

9. 마지막에는 꼭 driver.close()로 프로세스를 종료해줘야 한다!

10. 지금까지의 코드를 함수로 만들어보자. 결과는 다음과 같다.

from selenium import webdriver
import time
from tqdm import tqdm_notebook

def main_get():
    driver = webdriver.Chrome()
    driver.get('https://www.opinet.co.kr/')
    driver.get('https://www.opinet.co.kr/searRgSelect.do')
    si_list = driver.find_element(By.CSS_SELECTOR, '#SIDO_NM0 > option:nth-child(2)')
    si_list.click()
    gu_list_raw = driver.find_element(By.CSS_SELECTOR, '#SIGUNGU_NM0')
    gu_list = gu_list_raw.find_elements(By.CSS_SELECTOR, 'option')
    gu_names = [option.get_attribute('value') for option in gu_list]
    
    for gu_name in tqdm_notebook(gu_names):
        # 시군구 리스트 클릭
        gu_list_raw = driver.find_element(By.CSS_SELECTOR, '#SIGUNGU_NM0')
        gu_list_raw.send_keys(gu_name)
        time.sleep(2)

        # 엑셀 다운로드    
        exel_download = driver.find_element(By.CSS_SELECTOR, '#templ_list0 > div:nth-child(7) > div > a')
        exel_download.click()
        time.sleep(1)
    driver.close()