- 데이터 확보하기
- 주유소 정보 정리하기
- 주유 가격 정보 시각화
Q. 셀프 주유소의 가격, 정말 저렴한가???
Opinet에서 지역별 주유소의 가격 정보를 확인할 수 있다.
https://www.opinet.co.kr/searRgSelect.do
이 사이트에서 서울시 구마다의 주유소 가격, 브랜드, 셀프 주유 여부 등의 데이터를 가져와
다양한 시각화 작업을 하는 프로젝트이다.
지역을 선택하면 그 지역에 있는 모든 주유소의 정보들을 담은 엑셀 파일을 다운받을 수 있다.
"지역 선택->엑셀 파일 다운로드 버튼 클릭" 과정을 자동화할 것이다.
from selenium import webdriver
from selenium.webdriver.common.by import By
url = 'https://www.opinet.co.kr/searRgSelect.do'
driver = webdriver.Chrome()
driver.get(url)
태그를 분석해보면
#SIDO_NM0 (지역-시) 태그 안에, option이라는 태그로 값들(서울, 부산, 대구..)이 있는 것 같다.
sido_list_raw = driver.find_element(By.CSS_SELECTOR, "#SIDO_NM0")
-> 18
18개의 지역 정보를 가져왔다.
get_attribute로 옵션 태그 안에 value 속성값을 가져온다.
sido_list[1].get_attribute("value")
-> '서울특별시'
서울특별시 안의 구는, #SIGUNGU_NM0 에서 구를 선택하고 option으로 25개의 구를 선택할 수 있다.
for문을 사용해서 25개의 구 정보를 수집할 수 있다.
gu_list_raw = driver.find_element(By.CSS_SELECTOR, "#SIGUNGU_NM0")
gu_list = driver.find_elements(By.CSS_SELECTOR, "#SIGUNGU_NM0 > option")
gu_names = [option.get_attribute("value") for option in gu_list]
gu_names = gu_names[1:]
gu_names
gu_names라는 리스트에 25개의 구들이 잘 들어왔고,
이제 25개의 구를 리스트에서 반복문으로 받아와 각각 검색->엑셀 다운받기 버튼 클릭하는 과정이다.
tqdm_notebook으로 진행이 잘 되고 있는지 눈으로 확인할 수 있다.
import time
from tqdm import tqdm_notebook
for gu in tqdm_notebook(gu_names):
element = driver.find_element(By.CSS_SELECTOR, "#SIGUNGU_NM0")
element.send_keys(gu)
time.sleep(3)
element_get_excel = driver.find_element(By.CSS_SELECTOR, "#glopopd_excel").click()
time.sleep(3)
이런 식으로 25개 파일을 다 받아왔다.
파일 목록 한 번에 가져오기 - glob에서 파일 경로를 지정!
import pandas as pd
from glob import glob
glob("../data/지역_*.xls")
파일명 저장
stations_files = glob("../data/지역_*.xls")
컬럼명이 이상했기에 header=2로 가져왔음...
이제 모든 구의 주유소 정보를 이어 붙일 수 있다.
빈 리스트를 만들어준 후 for문을 이용해서 경로를 다 가져와 하나씩 다 읽어들이고, 빈 리스트에 더해준다.
tmp_raw = []
for file_name in stations_files:
tmp = pd.read_excel(file_name, header=2)
tmp_raw.append(tmp)
형식이 동일한 데이터프레임을 연달아 붙이기만 하면 될 때는 concat함수를 사용한다! (추가, 추가, 추가..하는 방식)
stations_raw = pd.concat(tmp_raw)
stations_raw
가져오고 싶은 컬럼만 딕셔너리 형태로 추려 데이터프레임으로 만들었다.
stations = pd.DataFrame({
"상호": stations_raw["상호"],
"주소": stations_raw["주소"],
"가격": stations_raw["휘발유"],
"셀프": stations_raw["셀프여부"],
"상표": stations_raw["상표"]
})
stations.tail()
구 별로 검색하기 위해서는,
주소를 보고 어느 구에 해당되는지를 분류해주는 컬럼이 필요하다.
주소는 '서울특별시 강동구 천호대로 1246' 이런 형식으로 생겼다.
-> for문으로 주소를 띄어쓰기 기준으로 split해주고, 그 값들의 두번째 값(index 1)만 추려오면 된다.
for eachAddress in stations["주소"]:
eachAddress.split()[1]
"구" 라는 컬럼을 만들어 for문으로 얻은 값들을 넣어주는 코드:
stations["구"] = [eachAddress.split()[1] for eachAddress in stations["주소"]]
stations
그리고
분석을 위해 가격 데이터타입을 object에서 float로 변환해야 한다.
-> ValueError -> 가격 정보가 빈 곳이 있었고 bar(-)형태로 채워져 있어서였음
-> 가격 정보가 있는 주유소 데이터만 사용하자!
stations = stations[stations["가격"] != "-"]
나머지 가격 정보들의 데이터타입을 바꿔주었다.
stations["가격"] = stations["가격"].astype("float")
인덱스 재정렬, 명목상인 index컬럼 없애기...
stations.reset_index(inplace=True)
del stations["index"]
이렇게 필요한 정보를 담은 데이터프레임을 완성했다.
import matplotlib.pyplot as plt
import seaborn as sns
from matplotlib import font_manager, rc
plt.rcParams["axes.unicode_minus"] = False
font_name = font_manager.FontProperties(fname="c:/Windows/Fonts/malgun.ttf").get_name()
rc('font', family=font_name)
%matplotlib inline
시각화를 위한 모듈과 한글 대응 코드 등등을 불러오고,
다양한 방면으로 시각화를 해보자.
셀프 여부(y/n)에 따른 가격 비교:
plt.figure(figsize=(12, 8))
sns.boxplot(x="셀프", y="가격", data=stations, palette="Set3")
sns.set_style("darkgrid")
plt.show()
-> ㅇㅇ 셀프 주유소가 싼편이다
상표별 가격 boxplot - 셀프 구분을 hue로:
import matplotlib.pyplot as plt
plt.rcParams['font.family'] ='Malgun Gothic'
plt.rcParams['axes.unicode_minus'] =False
plt.figure(figsize=(12, 8))
sns.boxplot(x="상표", y="가격", hue="셀프", data=stations, palette="Set3")
plt.show()
지역별 정보를 가져왔으니 표로 살펴보자!
import json
import folium
import warnings
warnings.simplefilter(action="ignore", category=FutureWarning)
가장 비싼 주유소 10개:
stations.sort_values(by="가격", ascending=False).head(10)
진짜 비싸네...ㄷㄷ
가장 싼 주유소 10개:
stations.sort_values(by="가격", ascending=True).head(10)
구마다의 평균 가격을 보고 싶어 -> 피벗테이블!!
import numpy as np
gu_data = pd.pivot_table(data=stations, index="구", values="가격", aggfunc=np.mean)
gu_data.head()
지도 시각화도 할 수 있다.
저번시간에 다운받은 우리나라 좌표값 데이터를 가져와서, 서울시 지역별 평균 유가 시각화를 하자
geo_path = "../data/02. skorea_municipalities_geo_simple.json"
geo_str = json.load(open(geo_path, encoding="utf-8"))
my_map = folium.Map(
location=[37.5502, 126.982],
zoom_start=11
)
folium.Choropleth(
geo_data=geo_str,
data=gu_data,
columns=[gu_data.index, "가격"],
key_on="feature.id",
fill_color="PuRd",
fill_opacity=0.7,
line_opacity=0.2
).add_to(my_map)
my_map
용산구, 중구, 종로구, 강남구가 비싸고,
서울 바깥쪽으로 갈수록 가격이 낮아지는 경향인 것 같다.