[제로베이스] EDA 과제 2. 유가분석(과제 해설)

허재훈·2023년 4월 22일
0

EDA

목록 보기
14/14
post-thumbnail

1. 셀프 주유소가 정말 저렴하나요?

  • 'https://www.opinet.co.kr/searRgSelect.do'
  • 사이트 구조 확인
  • 목표 데이터
    • 주유소 이름
    • 주소
    • 브랜드(상호명)
    • 휘발유 가격
    • 경유 가격
    • 셀프 여부
    • 세차장 여부
    • 충전소 여부
    • 경정비 여부
    • 편의점 여부
    • 24시간 운영 여부
    • 위도
    • 경도

2. selenium 을 활용한 크롤링

  • 기존 강의에서는 엑셀 파일을 다운 받은 걸로 진행
  • EDA 과제 2 에서는 엑셀 파일이 아닌, 크롤링 코드로 데이터 수집

2-1 페이지 접근

from selenium.webdriver import ActionChains
from selenium.webdriver.common.by import By
from selenium import webdriver

url = 'https://www.opinet.co.kr/searRgSelect.do'
driver = webdriver.Chrome('./driver/chromedriver.exe')
driver.get(url)

2-2 서울 선택(고정)

# 시/도 칸? 선택
sido_select = driver.find_element(By.CSS_SELECTOR, value="#SIDO_NM0")
# '서울' 입력
sido_select.send_keys('서울')

2-3 구별 선택

# 기존 유가 분석 강의에서 가져옴

# 서울의 구 목록 가져오기
# 지역: 구
# 지역관련 html 에 id 가 모두 있다 id = 'SIGUNGU_NM0'
# 우리나라 시/도 목록을 가져오려면, 
# 목록을 포함하고 있는 부모 태그를 가져와서 해당 목록을 가져온다

# id 로 해당 목록을 가져온다
gu_list_raw = driver.find_element(By.ID, value="SIGUNGU_NM0") # 부모태그

# html 에서 option 태그를 기준으로 가져온다
# 여러개 가져오므로 find_elements 이다.
gu_list = gu_list_raw.find_elements(By.TAG_NAME, value="option") # 자식태그

# gu_names = []

# for option in gu_list:
#     gu_names.append(option.get_attribute("value"))

# 한줄로 작성
# gu_names = [option.get_attribute("value") for option in gu_list]
# gu_names = gu_names[1:] # 첫번째가 빈값이어서 두번째 값부터 넣음

# 공백 제거까지 한번에
gu_names = [option.get_attribute("value") for option in gu_list if option.get_attribute('value')]


gu_names[:5], len(gu_names)

>>
(['강남구', '강동구', '강북구', '강서구', '관악구'], 25)

# 원하는 구로 바뀜
# 아래를 두번 실행하면 두번째에서는 에러남
# 근데 위 코드를 실행 후 다시 이 코드를 실행하면 실행됨
# 아래에서 다른 방법을 찾음
gu_list_raw.send_keys(gu_names[0])

# 개발자도구에서 강남구 부분 copy selector
driver.find_element(By.CSS_SELECTOR, value="#SIGUNGU_NM0 > option:nth-child(2)").text

>> '강남구'

# 이거는 1부터 시작한다
# 0은 없음
# 2부터 강남구 시작
driver.find_element(By.CSS_SELECTOR, value="#SIGUNGU_NM0 > option:nth-child(1)").text

>> '시/군/구'

driver.find_element(By.CSS_SELECTOR, value="#SIGUNGU_NM0 > option:nth-child(26)").text

>> '중랑구'

  • 구별 선택 방법 1
# 구별 선택 방법 1
# 구별 클릭이 됨
# 중랑구 선택됨
driver.find_element(By.CSS_SELECTOR, value="#SIGUNGU_NM0 > option:nth-child(26)").click()

  • 구별 선택 방법 2
# 구별 선택 방법 2
# 이것도 되네
# 강남구 선택됨
driver.find_element(By.CSS_SELECTOR, value='#SIGUNGU_NM0').send_keys('강남구')

  • 반복문 테스트
# 반복문 테스트
# 서울 고정
# 구별 순환

import time

for i, v in enumerate(gu_names):
    # {i+2} : i 가 0부터 시작인데 위에서 강남구는 2부터 시작이므로 +2 를 해준다
    # 중괄호는 왜지?
    # 아하
    # 그냥 '#SIGUNGU_NM0 > option:nth-child(i+2)' 넣으면 '' 안에 있는 거라 i+2 가 문자열이라서 인식을 못함
    # 그래서 위  '' 안의 색이 모두 똑같음
    # 그래서 앞에 f 를 붙여서 문자열 포매팅을 한다. 그래서 중괄호를 넣음 와우...
    # 포매팅을 하면 {i+2} 만 색이 달라짐
    gu_selector = f'#SIGUNGU_NM0 > option:nth-child({i+2})'
    driver.find_element(By.CSS_SELECTOR, value=gu_selector).click()
   

# 중랑구에는 주유소가 13개 있다.
# 목적에 맞는 데이터를 가져오는지 확인
# 아래 id="totCnt" 는 특정구가 선택된 상태에서 아래를 실행하면
# 해당구에 있는 주유소의 갯수를 가져옴

# 홈페이지에서도 같은 자리에서 숫자만 바뀌니까 갯수를 가져올 거란 걸 예상할 수 있음

# id="totCnt"

driver.find_element(By.CSS_SELECTOR, value="#totCnt").text

# 구별로 주유소의 갯수가 다른데
# 주유소별의 정보는
# tbody 태그(id=body1) 밑에 tr 태그로 모두 있다.

# 현재 중랑구, 중랑구는 주유소 13개
driver.find_elements(By.CSS_SELECTOR, value='#body1 > tr')


# 구별로 주유소의 갯수가 다른데
# 주유소별의 정보는
# tbody 태그(id=body1) 밑에 tr 태그로 모두 있다.

# 현재 중랑구, 중랑구는 주유소 13개
len(driver.find_elements(By.CSS_SELECTOR, value='#body1 > tr'))

>> 13

# 갯수가 일치한다
# 홈페이지에 나오는 주유소 갯수와 
# 주유소 정보를 가져와서 확인한 갯수가 같은지 확인.
totCnt = driver.find_element(By.CSS_SELECTOR, value="#totCnt").text
totCnt, len(driver.find_elements(By.CSS_SELECTOR, value='#body1 > tr'))

>> ('13', 13)

# 위 코드에 이어서

# 반복문 테스트
# 서울 고정
# 구별 순환
# 강의대로 하면 실행되지 않아서 조금 수정함

import time

for i, v in enumerate(gu_names):
    # {i+2} : i 가 0부터 시작인데 위에서 강남구는 2부터 시작이므로 +2 를 해준다
    # 중괄호는 왜지?
    # 아하
    # 그냥 '#SIGUNGU_NM0 > option:nth-child(i+2)' 넣으면 '' 안에 있는 거라 i+2 가 문자열이라서 인식을 못함
    # 그래서 위  '' 안의 색이 모두 똑같음
    # 그래서 앞에 f 를 붙여서 문자열 포매팅을 한다. 그래서 중괄호를 넣음 와우...
    # 포매팅을 하면 {i+2} 만 색이 달라짐
    gu_selector = f'#SIGUNGU_NM0 > option:nth-child({i+2})'
    driver.find_element(By.CSS_SELECTOR, value=gu_selector).click()

    # 목적에 맞는 데이터를 가져오는지 확인
    totCnt = driver.find_element(By.CSS_SELECTOR, value="#totCnt").text
    gu_totalCnt = driver.find_elements(By.CSS_SELECTOR, value='#body1 > tr')
    print(i, v, totCnt, len(gu_totalCnt))
    time.sleep(0.5)
    
>>
0 강남구 34 34
1 강동구 13 13
2 강북구 12 12
3 강서구 33 33
4 관악구 14 14
5 광진구 13 13
6 구로구 20 20
7 금천구 11 11
8 노원구 14 14
9 도봉구 16 16
10 동대문구 18 18
11 동작구 9 9
12 마포구 11 11
13 서대문구 14 14
14 서초구 30 30
15 성동구 16 16
16 성북구 23 23
17 송파구 29 29
18 양천구 24 24
19 영등포구 27 27
20 용산구 12 12
21 은평구 16 16
22 종로구 9 9
23 중구 10 10
24 중랑구 13 13

2-4 서울 구별 주유소 데이터 수집

# 데이터 수집 첫 시도
# 하나의 구에서 데이터 수집 테스트

from selenium.webdriver import ActionChains
from selenium.webdriver.common.by import By


body1 = driver.find_element(By.CSS_SELECTOR, value='#body1')

# 휘발유 가격 가져오기
gas = body1.find_elements(By.CSS_SELECTOR, value= 'td:nth-child(2)')
# copy selector 가 #body1 > tr:nth-child(1) > td:nth-child(2) 인데, 마지막만 넣어줌
# #body1 은 위 body1 에서 지정을 해줬으므로 뺌

# 경유 가격 가져오기
disel = body1.find_elements(By.CSS_SELECTOR, value= 'td:nth-child(3)')
# copy selector 가#body1 > tr:nth-child(1) > td:nth-child(3) 인데, 마지막만 넣어줌
# #body1 은 위 body1 에서 지정을 해줬으므로 뺌

# 브랜드명 가져오기
# rlist 클래스 밑에 img 로 들어감
brand = body1.find_elements(By.CSS_SELECTOR, value= '.rlist img')

# 부가정보(세차장, 경정비, 편의점, 24시간) 가져오기
# copy selector : #body1 > tr:nth-child(1) > td.rlist > span.ic.ico_self > span
is_self = body1.find_elements(By.CSS_SELECTOR, value= 'td.rlist span.ic.ico_self')

# 주유소명 가져오기
# copy selector : #body1 > tr:nth-child(1) > td.rlist > a
name = body1.find_elements(By.CSS_SELECTOR, value= '.rlist a')


# brand[0].get_attribute('alt') # rlist 클래스 밑에 img 로 들어가서 alt 값을 가져옴
# 주유소명이 잘려서 나옴
gas[0].text, disel[0].text, brand[0].get_attribute('alt'), is_self[0].text, name[0].text

>>
('1645', '1517', '현대오일뱅크', '셀프', '(주)자연에너지 ...')
# 숫자를 바꾸면 주유소마다의 정보를 가져온다
gas[3].text, disel[3].text, brand[3].get_attribute('alt'), is_self[3].text, name[3].text

>>
('1665', '1517', 'SK에너지', '셀프', '면목SELF주유소')

# 데이터 수집 2번째 시도
# 주유소명을 클릭하면 지도에 창이 열리면서 주유소명이 안잘린 데이터가 나온다
# 부가정보도 색깔로 가능한 부가정보를 나타내고 있다. (셀프는 주유소명 옆에 있다)

# 주유소명 클릭해보기 a href 부분을 클릭해야됨
# find_element 임 주의
# 'a href' 넣으니까 에러남
# 'a href' 부분이 13개 있는데 첫번째가 선택되어서 팝업됨
# body1.find_element(By.CSS_SELECTOR, value= 'a').click() # 이렇게 하니까 다른 구에서는 실행이 안됨

# driver.find_element(By.CSS_SELECTOR, value='#body1 a').click()
# tr:nth-child(1) 이 첫번째 주유소
# tr:nth-child(2) 가 두번째 주유소
driver.find_element(By.CSS_SELECTOR, value='#body1 > tr:nth-child(1) > td.rlist > a').click()

# 주유소명 가져오기
# #os_nm
# 분명 잘 했는데 안가져와진다
driver.find_element(By.CSS_SELECTOR, value='#os_nm').text

>>
...

# 그 위에 class="header" 부분을 같이 입력해주니 된다.
# 다 시도해봐야 됨
driver.find_element(By.CSS_SELECTOR, value='.header #os_nm').text

>>
'(주)자연에너지 대창주유소'


https://stackoverflow.com/questions/13047056/how-to-read-text-from-hidden-element-with-selenium-webdriver

Might be useful as well:

In some cases, 
one may find it useful to get the hidden text, 
which can be >retrieved from element's 
textContent, innerText or innerHTML attribute, 
by >calling element.attribute('attributeName').

element.getAttribute("textContent") worked for me.
# 그 다음 주유소명을 가져와보자 > 오천만주유소
# 오천만주유소명을 클릭해서 지도에 띄운 다음
# 그냥 하면 안됨 > 화면에 팝업창 전체가 안나오면 안나옴
# 팝업창을 화면에 보이게 만든 후 실행하니 잘 나옴...

# 구글링 : selenium get text hidden element
driver.find_element(By.CSS_SELECTOR, value='.header #os_nm').text

>>
'오천만주유소'

# 방법 2
driver.find_element(By.CSS_SELECTOR, value='.header #os_nm').get_attribute('innerText')

>>
'오천만주유소'

# 방법 3
driver.find_element(By.CSS_SELECTOR, value='.header #os_nm').get_attribute('innerHTML')

>>
'오천만주유소'

2-4 반복문 테스트

  • 우선 3개구에서 3개씩만 가져와보자
# 반복문 데트스
# 세부페이지(팝업창)에서 주유소명 가져오기
# 우선 3개만 해보자

import time

# 3개의 구를 돈다
for i in range(0, 3): # 구 선택
    # {i+2} : i 가 0부터 시작인데 위에서 강남구는 2부터 시작이므로 +2 를 해준다
    # 중괄호는 왜지?
    # 아하
    # 그냥 '#SIGUNGU_NM0 > option:nth-child(i+2)' 넣으면 '' 안에 있는 거라 i+2 가 문자열이라서 인식을 못함
    # 그래서 위  '' 안의 색이 모두 똑같음
    # 그래서 앞에 f 를 붙여서 문자열 포매팅을 한다. 그래서 중괄호를 넣음 와우...
    # 포매팅을 하면 {i+2} 만 색이 달라짐
    gu_selector = f'#SIGUNGU_NM0 > option:nth-child({i+2})'
    driver.find_element(By.CSS_SELECTOR, value=gu_selector).click()

    # # 목적에 맞는 데이터를 가져오는지 확인
    # totCnt = driver.find_element(By.CSS_SELECTOR, value="#totCnt").text
    # gu_totalCnt = driver.find_elements(By.CSS_SELECTOR, value='#body1 > tr')
    # print(i, v, totCnt, len(gu_totalCnt))
    # time.sleep(0.5)

    # 위까지는 위 코드에서 가져옴
    # 구별마다 주유소를 클릭해서 정보를 가져오기
    # 3개의 구마다 3개의 주유소를 클릭해서 팝업창을 띄운다
    for idx in range(0, 3): # 주유소 선택
        detail_selector = f'#body1 > tr:nth-child({idx+1}) > td.rlist > a'
        driver.find_element(By.CSS_SELECTOR, value=detail_selector).click()
        title = driver.find_element(By.CSS_SELECTOR, value='.header #os_nm').get_attribute('innerText')
        print(title)
        
>>
()보성 세곡주유소
삼성동주유소
현대오일뱅크 도곡셀프주유소
재건에너지 재정제2주유소 고속셀프지점
구천면주유소
대성석유()길동주유소
씨앤에스유통㈜ 미아셀프주유소
덕릉로주유소
북서울고속주유소

# 테스트코드
# 구별로 순회하면서, 세부페이지 주유소 이름 수집

for i, v in enumerate(gu_names[:3]): # 구 선택
    
    gu_selector = f'#SIGUNGU_NM0 > option:nth-child({i+2})'
    driver.find_element(By.CSS_SELECTOR, value=gu_selector).click()
    station_items = driver.find_elements(By.CSS_SELECTOR, value='#body1 > tr')
    print()
    print(f'========={v}에는 {len(station_items)}개 주유소가 있습니다==========')

    # # 목적에 맞는 데이터를 가져오는지 확인
    # totCnt = driver.find_element(By.CSS_SELECTOR, value="#totCnt").text
    # gu_totalCnt = driver.find_elements(By.CSS_SELECTOR, value='#body1 > tr')
    # print(i, v, totCnt, len(gu_totalCnt))
    # time.sleep(0.5)

    # 위까지는 위 코드에서 가져옴
    # 구별마다 주유소를 클릭해서 정보를 가져오기
    # 3개의 구마다 3개의 주유소를 클릭해서 팝업창을 띄운다
    for idx in range(len(station_items))[:3]: # 주유소 선택
        detail_selector = f'#body1 > tr:nth-child({idx+1}) > td.rlist > a'
        driver.find_element(By.CSS_SELECTOR, value=detail_selector).click()
        title = driver.find_element(By.CSS_SELECTOR, value='.header #os_nm').get_attribute('innerText')
        print(f'{v} 주유소 이름:', title)
    time.sleep(0.5)

>>
=========강남구에는 34개 주유소가 있습니다==========
강남구 주유소 이름: ()보성 세곡주유소
강남구 주유소 이름: 삼성동주유소
강남구 주유소 이름: 현대오일뱅크 도곡셀프주유소

=========강동구에는 13개 주유소가 있습니다==========
강동구 주유소 이름: 재건에너지 재정제2주유소 고속셀프지점
강동구 주유소 이름: 구천면주유소
강동구 주유소 이름: 대성석유()길동주유소

=========강북구에는 12개 주유소가 있습니다==========
강북구 주유소 이름: 씨앤에스유통㈜ 미아셀프주유소
강북구 주유소 이름: 덕릉로주유소
강북구 주유소 이름: ()석산에너지

2-5 메인데이터 수집

# 메인 데이터 수집

name = title = driver.find_element(By.CSS_SELECTOR, value='.header #os_nm').get_attribute('innerText')
gasoline = driver.find_element(By.CSS_SELECTOR, value='#b027_p').get_attribute('innerText')
disel = driver.find_element(By.CSS_SELECTOR, value='#d047_p').get_attribute('innerText')
address = driver.find_element(By.CSS_SELECTOR, value='#rd_addr').get_attribute('innerText')
brand = driver.find_element(By.CSS_SELECTOR, value='#poll_div_nm').get_attribute('innerText')

name, gasoline, disel, address, brand

>>
('씨앤에스유통㈜ 미아셀프주유소', '1,623', '1,513', '서울 강북구 도봉로 200 (미아동)', 'S-OIL')

# 부가정보 데이터 수집
# 세차장은 나오는데, 세차장을 하는건지 안하는건지는 알 수 없다

cwsh_yn = driver.find_element(By.CSS_SELECTOR, value='.service #cwsh_yn').get_attribute('alt')

cwsh_yn

# html 을 보면 /images/user/gis/oil_station_service1_02_01_off.gif 와 같이
# 없으면 off 가 들어가있고, 있으면 off 가 없음
# src 를 가져온다
# / 를 기준으로 되어있다
cwsh_yn = driver.find_element(By.CSS_SELECTOR, value='.service #cwsh_yn').get_attribute('src')
lpg_yn = driver.find_element(By.CSS_SELECTOR, value='.service #lpg_yn').get_attribute('src')

cwsh_yn, lpg_yn

>>
('https://www.opinet.co.kr/images/user/gis/oil_station_service1_01.gif',
 'https://www.opinet.co.kr/images/user/gis/oil_station_service1_02_01_off.gif')

# / 를 기준으로 나눈다.

lpg_yn.split('/')

>>
['https:',
 '',
 'www.opinet.co.kr',
 'images',
 'user',
 'gis',
 'oil_station_service1_02_01_off.gif']

# / 를 기준으로 나눈다.
# 마지막 것만 필요하므로 마지막 것만 가져온다
lpg_yn.split('/')[-1]

>>
'oil_station_service1_02_01_off.gif'


# off 가 있는걸 가져와보자

# lpg_yn.split('/')[-1] 에 '_off'가 있으면 'N' 없으면 'Y'
'N' if '_off' in lpg_yn.split('/')[-1] else 'Y'

>> 'N'


# lpg_yn.split('/')[-1] 에 '_off'가 있으면 'N' 없으면 'Y'
'N' if '_off' in cwsh_yn.split('/')[-1] else 'Y'

>> 'Y'

2-6 셀프여부(try ~ except~ )


# 셀프주유소인 곳은 셀프 아이콘 html 의 alt 에 셀스주유소라고 되어있고,

driver.find_element(By.CSS_SELECTOR, value='#self_icon').get_attribute('alt')

>> '셀프주유소'


# 셀프주유소가 아닌 곳은 오류가 난다.

driver.find_element(By.CSS_SELECTOR, value='#self_icon').get_attribute('alt')



try: # 아래가 실행이 되면 Y
    driver.find_element(By.CSS_SELECTOR, value='#self_icon').get_attribute('alt')
    is_self = 'Y'
except: # 실행 안되면 N
    is_self = 'N'

is_self

>> 'N'

2-7 전체 데이터 수집

# 페이지 접근

from selenium.webdriver import ActionChains
from selenium.webdriver.common.by import By
from selenium import webdriver


url = 'https://www.opinet.co.kr/searRgSelect.do'
driver = webdriver.Chrome('./driver/chromedriver.exe')
driver.get(url)
driver.get(url)

# 서울시 고정

# 시/도 칸? 선택
sido_select = driver.find_element(By.CSS_SELECTOR, value="#SIDO_NM0")
# '서울' 입력
sido_select.send_keys('서울')

# 구별 선택

# 기존 유가 분석 강의에서 가져옴

# 서울의 구 목록 가져오기
# 지역: 구
# 지역관련 html 에 id 가 모두 있다 id = 'SIGUNGU_NM0'
# 우리나라 시/도 목록을 가져오려면, 
# 목록을 포함하고 있는 부모 태그를 가져와서 해당 목록을 가져온다

# id 로 해당 목록을 가져온다
gu_list_raw = driver.find_element(By.ID, value="SIGUNGU_NM0") # 부모태그

# html 에서 option 태그를 기준으로 가져온다
# 여러개 가져오므로 find_elements 이다.
gu_list = gu_list_raw.find_elements(By.TAG_NAME, value="option") # 자식태그

# gu_names = []

# for option in gu_list:
#     gu_names.append(option.get_attribute("value"))

# 한줄로 작성
# gu_names = [option.get_attribute("value") for option in gu_list]
# gu_names = gu_names[1:] # 첫번째가 빈값이어서 두번째 값부터 넣음

# 공백 제거까지 한번에
gu_names = [option.get_attribute("value") for option in gu_list if option.get_attribute('value')]

import pandas as pd
import time
import googlemaps

gmaps_key = '본인키입력'
gmaps = googlemaps.Client(key=gmaps_key)

datas = []

for i in range(len(gu_names)): # 구 선택
    
    gu_selector = f'#SIGUNGU_NM0 > option:nth-child({i+2})'
    driver.find_element(By.CSS_SELECTOR, value=gu_selector).click()
    station_items = driver.find_elements(By.CSS_SELECTOR, value='#body1 > tr')

    for idx in range(len(station_items)): # 주유소 선택
        detail_selector = f'#body1 > tr:nth-child({idx+1}) > td.rlist > a'
        driver.find_element(By.CSS_SELECTOR, value=detail_selector).click()
        title = driver.find_element(By.CSS_SELECTOR, value='.header #os_nm').get_attribute('innerText')

        name = title = driver.find_element(By.CSS_SELECTOR, value='.header #os_nm').get_attribute('innerText')
        gasoline = driver.find_element(By.CSS_SELECTOR, value='#b027_p').get_attribute('innerText')
        disel = driver.find_element(By.CSS_SELECTOR, value='#d047_p').get_attribute('innerText')
        address = driver.find_element(By.CSS_SELECTOR, value='#rd_addr').get_attribute('innerText')
        brand = driver.find_element(By.CSS_SELECTOR, value='#poll_div_nm').get_attribute('innerText')
        cwsh_yn = 'N' if '_off' in driver.find_element(By.CSS_SELECTOR, value='.service #cwsh_yn').get_attribute('src').split('/')[-1] else 'Y'
        lpg_yn = 'N' if '_off' in driver.find_element(By.CSS_SELECTOR, value='.service #lpg_yn').get_attribute('src').split('/')[-1] else 'Y'
        maint_yn = 'N' if '_off' in driver.find_element(By.CSS_SELECTOR, value='.service #maint_yn').get_attribute('src').split('/')[-1] else 'Y'
        cvs_yn = 'N' if '_off' in driver.find_element(By.CSS_SELECTOR, value='.service #cvs_yn').get_attribute('src').split('/')[-1] else 'Y'
        sel24_yn = 'N' if '_off' in driver.find_element(By.CSS_SELECTOR, value='.service #sel24_yn').get_attribute('src').split('/')[-1] else 'Y'

        try: # 아래가 실행이 되면 Y
            driver.find_element(By.CSS_SELECTOR, value='#self_icon').get_attribute('alt')
            is_self = 'Y'
        except: # 실행 안되면 N
            is_self = 'N'


        # gu
        
        gu = address.split()[1]

        # lat, lng
        tmp = gmaps.geocode(address, language='ko')
        lat = tmp[0].get('geometry')['location']['lat']
        lng = tmp[0].get('geometry')['location']['lng']


        datas.append({
            'name' : name,
            'address' : address,
            'brand' : brand,
            'is_self' : is_self,
            'gasoline' : gasoline,
            'disel' : disel,
            'car_wash' : cwsh_yn,
            'charging_station' : lpg_yn,
            'car_maintenance' : maint_yn,
            'convenience_store' : cvs_yn,
            '24_hour' : sel24_yn,
            'gu' : gu,
            'lat' : lat,
            'lng' : lng
        })

        time.sleep(0.2)
    time.sleep(0.5)

driver.quit

df = pd.DataFrame(datas)
df.tail()


# 모두 다 잘 들어왔다
df.info()

>>
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 441 entries, 0 to 440
Data columns (total 14 columns):
 #   Column             Non-Null Count  Dtype  
---  ------             --------------  -----  
 0   name               441 non-null    object 
 1   address            441 non-null    object 
 2   brand              441 non-null    object 
 3   is_self            441 non-null    object 
 4   gasoline           441 non-null    object 
 5   disel              441 non-null    object 
 6   car_wash           441 non-null    object 
 7   charging_station   441 non-null    object 
 8   car_maintenance    441 non-null    object 
 9   convenience_store  441 non-null    object 
 10  24_hour            441 non-null    object 
 11  gu                 441 non-null    object 
 12  lat                441 non-null    float64
 13  lng                441 non-null    float64
dtypes: float64(2), object(12)
memory usage: 48.4+ KB

import datetime

now = datetime.datetime.now()
now

>> datetime.datetime(2023, 4, 22, 16, 25, 52, 771547)

nowDate = now.strftime('%Y%m%d')
nowDate

>> '20230422'

# csv 파일 저장

df.to_csv(f'./oilstaion_oneday_{nowDate}.csv', encoding='utf-8')

# csv 파일 읽기
# thousands=',' : 휘발유, 경유 가격에 천단위 콤마 없애기 > 그래야 휘발유, 경유 자료형이 int 로 나옴
station = pd.read_csv('./oilstaion_oneday_20230422.csv', encoding='utf-8', thousands=',', index_col=0)
station


station.info()

>>
<class 'pandas.core.frame.DataFrame'>
Int64Index: 441 entries, 0 to 440
Data columns (total 14 columns):
 #   Column             Non-Null Count  Dtype  
---  ------             --------------  -----  
 0   name               441 non-null    object 
 1   address            441 non-null    object 
 2   brand              441 non-null    object 
 3   is_self            441 non-null    object 
 4   gasoline           441 non-null    int64  
 5   disel              441 non-null    int64  
 6   car_wash           441 non-null    object 
 7   charging_station   441 non-null    object 
 8   car_maintenance    441 non-null    object 
 9   convenience_store  441 non-null    object 
 10  24_hour            441 non-null    object 
 11  gu                 441 non-null    object 
 12  lat                441 non-null    float64
 13  lng                441 non-null    float64
dtypes: float64(2), int64(2), object(10)
memory usage: 51.7+ KB

3. 데이터 시각화

# 한글대응

import matplotlib.pyplot as plt
import seaborn as sns
import platform
from matplotlib import font_manager, rc

%matplotlib inline

path = 'C:/Windows/Fonts/malgun.ttf'

if platform.system() == 'Darwin':
    rc('font', family = 'Arial Unicode MS')
elif platform.system() == 'Windows':
    font_name = font_manager.FontProperties(fname = path).get_name()
    rc('font', family = font_name)
else:
    print('Unknown system. sorry.')

boxplot(feat. seaborn)

# 휘발유 boxplot(feat. seaborn)

plt.figure(figsize=(12, 8))
sns.boxplot(x='is_self', y='gasoline', data=station, palette='Set1')
plt.grid(True)
plt.show()


# 휘발유 브랜드별 비교
# boxplot(feat. seaborn)

plt.figure(figsize=(12, 8))
sns.boxplot(x='brand', y='gasoline', hue='is_self', data=station, palette='Set1')
plt.grid(True)
plt.show()


# 휘발유 구별 비교
# boxplot(feat. seaborn)

plt.figure(figsize=(18, 8))
sns.boxplot(x='gu', y='gasoline', data=station, palette='Set1')
plt.grid(True)
plt.show()


# 휘발유 구별 비교
# boxplot(feat. seaborn)

plt.figure(figsize=(18, 8))
sns.boxplot(x='gu', y='gasoline', data=station, palette='Set1')
plt.grid(True)
plt.show()


4. 지도 시각화

import json
import folium

가장 비싼 주유소 10개

# 가장 비싼 주유소 10개

station[['gu', 'name', 'is_self', 'gasoline']].sort_values(by='gasoline', ascending=False).head(10)


# 가장 비싼 주유소 10개

station[['gu', 'name', 'is_self', 'gasoline']].sort_values(by='gasoline', ascending=False).head(10).reset_index(drop=True)


가장 저렴한 주유소 10개

# 가장 저렴한 주유소 10개

station[['gu', 'name', 'is_self', 'gasoline']].sort_values(by='gasoline', ascending=True).head(10).reset_index(drop=True)


지도 시각화용 데이터프레임 만들기

# 지도 시각화용 데이터프레임 만들기

import numpy as np

gu_data = pd.pivot_table(data=station, index='gu', values='gasoline', aggfunc=np.sum)
gu_data.head()


서울 지도 가져오기

# 서울 지도 가져오기

geo_path = './data/02. skorea_municipalities_geo_simple.json'
geo_str = json.load(open(geo_path, encoding='utf-8'))

m = folium.Map(location=[37.5502, 126.982], zoom_start=12)

# 지도에 서울시 구별로 경계선 넣기

m.choropleth(
    geo_data = geo_str,
    data = gu_data,
    columns = [gu_data.index, 'gasoline'],
    key_on = 'feature.id',
    fiil_color = 'PuRd'
)
m

위 글은 제로베이스 데이터 취업 스쿨의 강의자료를 참고하여 작성되었습니다.

profile
허재

1개의 댓글

comment-user-thumbnail
2023년 9월 13일

안녕하세요 혹시 EDA테스트2 화장품 성분분석한 코드도 있으신가요?

답글 달기

관련 채용 정보