🌟 목표
셀프주유소와 일반주유소의 가격을 비교해보고,
셀프주유소가 저렴한지 확인해보자
📌 미션
사이트 데이터를 불러와 서울시 구별 데이터 정보를 pandas data frame으로 정리하자
- 필요컬럼 | 주유소명, 주소, 브랜드, 휘발유 가격, 경유 가격, 셀프 여부, 세차장 여부, 충전소 여부, 경정비 여부, 편의점 여부, 24시간 운영 여부, 구, 위도, 경도
- 사이트링크 | https://www.opinet.co.kr/user/main/mainView.do
from selenium import webdriver
from selenium.webdriver.common.by import By
url = "https://www.opinet.co.kr/user/main/mainView.do"
driver = webdriver.Chrome("C:/Users/solbi/OneDrive/Documents/ds_study/driver/chromedriver.exe")
driver.get(url)
from selenium.webdriver import ActionChains
move_tag = driver.find_element(By.CSS_SELECTOR,"#header > div > ul > li:nth-child(1) > a")
ActionChains(driver).move_to_element(move_tag).perform()
동적 페이지이기 때문에 해당 버튼에 마우스를 올려야 숨은 코드가 보였다.
그래서 ActionChains을 통해 해결 !
driver.find_element(By.CSS_SELECTOR,"#header > div > ul > li:nth-child(1) > ul > li:nth-child(1) > a").click()
# 세차장클릭
driver.find_element(By.CSS_SELECTOR,"#CWSH_YN").click()
# 경정비클릭
driver.find_element(By.CSS_SELECTOR,"#MAINT_YN").click()
# 편의점클릭
driver.find_element(By.CSS_SELECTOR,"#CVS_YN").click()
# 24시간클릭
driver.find_element(By.CSS_SELECTOR,"#SEL24_YN").click()
# 시/도 접근
sido_raw = driver.find_element(By.CSS_SELECTOR,"#SIDO_NM0")
sido = sido_raw.find_elements(By.TAG_NAME,"option")
sido[0].text # 시/도
sido = sido[1:]
sido[0].text # 서울
#서울입력
sido_raw.send_keys(sido[0].text)
gu_raw = driver.find_element(By.CSS_SELECTOR,"#SIGUNGU_NM0")
gu = gu_raw.find_elements(By.TAG_NAME,"option")
gu[0].text # 시/군/구
gu = gu[1:]
gu[0].text # 강남구
gu_list = []
from tqdm import tqdm_notebook
for option in tqdm_notebook(gu) :
gu_list.append(option.get_attribute("value"))
gu_list
data = []
from bs4 import BeautifulSoup
import time
# 구 이름 넣기
for gu in tqdm_notebook(gu_list) :
gu_raw = driver.find_element(By.CSS_SELECTOR,"#SIGUNGU_NM0")
gu_raw.send_keys(gu)
html = driver.page_source
soup = BeautifulSoup(html,"html.parser")
cnt = int(soup.find(id = "totCnt").text)
for n in range(1,cnt+1) :
driver.find_element(By.CSS_SELECTOR,f'#body1 > tr:nth-child({n}) > td.rlist > a').click()
html = driver.page_source
soup = BeautifulSoup(html,"html.parser")
# 1. 주유소 명
name = soup.find(id = "os_nm").text
# 2. 주유소 주소
address = soup.find(id = "rd_addr").text
# 3. 브랜드
brand = soup.find(id = "poll_div_nm").text
# 4. 휘발유가격
gasoline = soup.find(id = "b027_p").text
# 5. 경유가격
diesel = soup.find(id = "d047_p").text
# 6. 셀프여부
if soup.find('img', {'alt': '셀프주유소', 'class': 'bul'}):
self = "Y"
else:
self = "N"
# 7. 세차장여부
if "off" in soup.find(id = "cwsh_yn").get("src") :
wash = "N"
else:
wash = "Y"
# 8. 충전소여부
if "off" in soup.find(id = "lpg_yn").get("src") :
charging = "N"
else:
charging = "Y"
# 9. 경정비여부
if "off" in soup.find(id = "maint_yn").get("src"):
center = "N"
else:
center = "Y"
# 10. 편의점여부
if "off" in soup.find(id = "cvs_yn").get("src") :
store = "N"
else:
store = "Y"
# 11. 24시여부
if "off" in soup.find(id = "sel24_yn").get("src") :
night = "N"
else:
night = "Y"
# 12. 구
gu = gu
time.sleep(0.2)
data.append({
'name' : name,
'address' : address,
'brand' : brand,
'gasoline' : gasoline,
'diesel' : diesel,
'self' : self,
'wash' : wash,
'charging' : charging,
'center' : center,
'store' : store,
'night' : night,
'gu' : gu
})
- 페이지에서 각 구별 주유소 수가 상단에 뜨기 때문에
해당 데이터로 for문을 돌렸다.
다행히 각 데이터마다 고유의 id를 가지고 있어서 데이터를 크롤링 하는게 어렵지는 않았으나,
세차장, 충전소, 경정비, 편의점의 경우 데이터 텍스트가 존재하는것이 아닌,
이미지의 색상으로 여부를 구별해야했고,
src 이미지 링크 내 없다면 off로 되어있는것을 확인
in 키워드를 사용해서 여부를 파악할 수 있었다.
셀프주유소여부의 경우
해당할 경우에만 상단에 이미지가 있는데,
alt로 셀프주유소 코드가 존재해서 if문으로 확인하였다.
(사실 저렇게 if문을 사용해도 되나 했지만, 얻어걸림 😅)
import pandas as pd
oil_df = pd.DataFrame(data)
import googlemaps
gmaps_key = "개인구글키"
gmaps = googlemaps.Client(key = gmaps_key)
lat_list = []
lng_list = []
for adr in tqdm_notebook(oil_df["address"]) :
tmp = gmaps.geocode(adr, language= "ko")
lat = tmp[0].get("geometry")["location"]["lat"]
lng = tmp[0].get("geometry")["location"]["lng"]
lat_list.append(lat)
lng_list.append(lng)
oil_df["lat"] = lat_list
oil_df["lng"] = lng_list
object(+ 천단위 ,)이기 떄문에 ,를 지워주고 int로 변경해야한다. | 참고링크
import numpy as np
oil_df["gasoline"] = oil_df["gasoline"].str.replace(",","")
oil_df["gasoline"] = oil_df["gasoline"].astype("int64")
oil_df["diesel"] = oil_df["diesel"].str.replace(",","")
oil_df["diesel"] = oil_df["diesel"].astype("int64")
from matplotlib import font_manager as fm
from matplotlib import pyplot as plt
#한글폰트 깨짐 해결
get_ipython().run_line_magic("matplotlib", "inline")
plt.rc('font', family = "Malgun Gothic")
#마이너스부호 깨짐 해결
import matplotlib as mpl
mpl.rcParams['axes.unicode_minus'] = False
import numpy as np
self_pivot = oil_df.pivot_table(index=["self"],values=["gasoline","diesel"],aggfunc=np.mean)
self_pivot
import seaborn as sns
self_pivot.boxplot(
figsize=(12,8), column=["gasoline","diesel"], by = "self"
)
- 경유의 경우 셀프주유소에서 평균 1492원 셀프가 아닌 주유소에서 1689원이고,
- 휘발유의 경우 셀프주유소에서 평균 1566원 셀프가 아닌 주유소에서 1765원이므로
- 서울 전체 평균을 따져본다면 셀프주유소가 아닌 주유소보다 더 저렴한 것을 알 수 있다.
- (해당 수치를 boxplot으로 시각화 하였을 때 차이를 한눈에 볼 수 있음)
plt.figure(figsize=(12,8))
sns.boxplot(
x= "brand", y = "gasoline", hue = "self", data=oil_df, palette = "Set3"
)
plt.show()
plt.figure(figsize=(12,8))
sns.boxplot(
x= "brand", y = "diesel", hue = "self", data=oil_df, palette = "Set3"
)
plt.show()
- 브랜드별 휘발유, 경유 가격을 시각화 하였을 때
- 모든 브랜드에서 셀프주유소의 가격분포가 더 낮음을 확인 할 수 있다.
- (추가로 알뜰주유소가 가격이 제일 저렴하다.)
plt.figure(figsize=(12,8))
sns.boxplot(
x= "gu", y = "gasoline", hue = "self", data=oil_df, palette = "Set3"
)
plt.show()
plt.figure(figsize=(12,8))
sns.boxplot(
x= "gu", y = "diesel", hue = "self", data=oil_df, palette = "Set3"
)
plt.show()
- 구별 각각의 기름가격을 셀프주유소와 아닌 주유소로 시각화하였을 때, 대체적으로 휘발유, 경유 모두 셀프주유소가 더 저렴한것을 확인 할 수 있었다.
( 추가로 강남구, 중구, 성동구 등에서 가장 큰 차이를 보임)- 다만, 양천구, 금천구, 송파구 등의 경우 차가 크지 않고 은평구의 경우 셀프 주유소보다 확연하게 저렴한 주유소도 존재하는 것으로 보아
절대적으로 셀프 주유소가 저렴하다고는 볼 수없고, 대체적으로 저렴하다라고 볼 수 있다.
📌 인사이트정리
A. 인사이트 |
- 서울 전체 주유소의 셀프주유소와 아닌 주유소의 평균 가격을 비교해보았을 때, 휘발유/경유 모두 셀프주유소의 가격이 더 저렴한것을 확인함
B. 인사이트 |- 브랜드별 셀프주유소와 아닌 주유소의 가격분포를 시각화해 보았을 때, 모든 브랜드가 셀프주유소의 가격이 더 저렴한것을 확인함
C. 인사이트 |- 구별 셀프주유소와 아닌 주유소의 가격분포를 시각화해 보았을때, 대체적으로 셀프 주유소가 더 저렴하며 그 차가 작은구와 큰 구가 존재하고,
- 몇몇구에서는 셀프주유소보다 저렴한 주유소가 존재함
📌 최종결론
셀프주유소는 아닌 일반 주유소보다 '대체적'으로 저렴한 편이다.
셀프보다 더 저렴한 일반 주유소도 존재 하지만 그 수가 적고,
데이터를 시각화 해보았을 때 대부분의 셀프주유소 가격이 저렴한 것을 볼 수 있다.
안녕하세요 솔비님! 코드 중에
driver.find_element(By.CSS_SELECTOR,f'#body1 > tr:nth-child({n}) > td.rlist > a').click()
요 부분 도저히 해결이 되지 않아서 그런데 참고 해서 써도 되나요?🥲