프로젝트로 배우는 데이터사이언스

데이터 분석 과제 - 셀프 주유소는 정말 저렴할까?

우드의개발개발 2024. 4. 29. 20:21

1. 서울시 구별 주유소 데이터 정보를 수집하여 데이터 프레임화

from bs4 import BeautifulSoup
from selenium import webdriver
from selenium.webdriver.common.by import By
import time 
from tqdm import tqdm

url="https://www.opinet.co.kr/searRgSelect.do"
driver=webdriver.Chrome()

driver.get(url)

#서울 선택
sido_select=driver.find_element(By.ID, "SIDO_NM0")
sido_select.send_keys('서울')

time.sleep(3)

# 서울시 구
gu=driver.find_element(By.ID,'SIGUNGU_NM0')
gu_li=gu.find_elements(By.TAG_NAME,'option')
li= [gu.get_attribute('value') for gu in gu_li]

def get_info(driver, gu):
    
    station_li = []
    address_li = []
    brand_li = []
    oil_price_li = []
    oil2_price_li = []
    self_bool_li = []
    car_wash_bool_li = []
    charge_bool_li = []
    maintenance_bool_li = []
    conveni_bool_li = []
    all_day_bool_li = []
    gu = []
    
    self = ''
    car_wash = ''
    charging=''
    maintenance=''

    
    req=driver.page_source
    soup=BeautifulSoup(req,'html.parser')        
    result=soup.select_one('.result_gis #os_price1 #body1')
    
    gu_stations=result.select('.rlist')
    
    #구 리스트
    gu_list=[gu for i in range(len(gu_stations)) ]
    
    
    for idx, detail in tqdm(enumerate(gu_stations)):
        
        # 셀프 여부 
        if '셀프' in detail.text.strip():
            self='Y'
        else:
            self='N'            
        
        self_bool_li.append(self)

        rlist=driver.find_element(By.CSS_SELECTOR,f'#body1 > tr:nth-child({idx+1}) > td.rlist > a')
        rlist.click()

        req=driver.page_source
        soup=BeautifulSoup(req,'html.parser')
        station_info=soup.select_one('.ollehmap-info #os_dtail_info')

        name = station_info.select_one('#os_nm').text #주유소 명
        brand=station_info.select_one('#poll_div_nm').text #브랜드
        address=station_info.select_one('#rd_addr').text #주소
        o1_price=station_info.select_one('#b027_p').text # 휘발유
        o2_price=station_info.select_one('#d047_p').text #경유가격
    

        station_li.append(name)
        brand_li.append(brand)
        address_li.append(address)
        oil_price_li.append(o1_price)
        oil2_price_li.append(o2_price)
        
        
        additional_info=station_info.select_one('.service')
        
        #세차장
        car_wash_img=additional_info.select_one('#cwsh_yn').get('src')
        if 'off' in car_wash_img:
            car_wash='N'
        else:
            car_wash='Y'

        # 충전소
        charging_img=additional_info.select_one('#lpg_yn').get('src')
        if 'off' in charging_img:
            charging='N'
        else:
            charging='Y'
        # 경정비
        maintenance_img=additional_info.select_one('#maint_yn').get('src')
        if 'off' in maintenance_img:
            maintenance='N'
        else:
            maintenance='Y'
        #편의점
        convenience_img=additional_info.select_one('#cvs_yn').get('src')
        if 'off' in convenience_img:
            convenience='N'
        else:
            convenience='Y'
        # 24시 영업
        sel24_img=additional_info.select_one('#sel24_yn').get('src')
        if 'off' in convenience_img:
            sel24='N'
        else:
            sel24='Y'

        # 각 리스트에 추가  
        car_wash_bool_li.append(car_wash)
        charge_bool_li.append(charging)
        maintenance_bool_li.append(maintenance)
        conveni_bool_li.append(convenience)
        all_day_bool_li.append(sel24)

    data={
        '주유소명' : station_li,
        '주소' : address_li,
        '브랜드' : brand_li,
        '휘발유 가격' : oil_price_li,
        '경유 가격' : oil2_price_li,
        '셀프 여부' : self_bool_li,
        '세차장 여부' : car_wash_bool_li,
        '충전소 여부' : charge_bool_li,
        '경정비 여부' : maintenance_bool_li,
        '편의점 여부' : conveni_bool_li,
        '24시간 운영 여부' : all_day_bool_li,
        '구' : gu_list
    }
    return data
    
    seoul_station = {}

# 서울시 내 구를 돌면서 구 내에 있는 주유소 매장을 수집하여 리스트에 담는다
for gu in li[1:]:
    select_gu=driver.find_element(By.ID,'SIGUNGU_NM0')
    select_gu.send_keys(gu)
    time.sleep(2)

    btn = driver.find_element(By.CSS_SELECTOR,'#searRgSelect')
    btn.click()
    time.sleep(4)
        
    seoul_station[gu]=get_info(driver, gu)
    time.sleep(4)
    
station_li = [] #주유소 명
address_li=[] #주소
brand_li=[] #브랜드
oil_price_li=[] # 휘발유가격
oil2_price_li=[] #경유가격
self_bool_li=[] #셀프
car_wash_bool_li=[] # 세차장
charge_bool_li=[] #충전소
maintenance_bool_li=[] #경정비
conveni_bool_li=[] #편의점
all_day_bool_li=[] #24시 영업
gu_li=[] # 구


for k in seoul_station:
    ad = [val for val in seoul_station[k]['주소']]
    station_li+=[val for val in seoul_station[k]['주유소명']]
    address_li+=ad
    brand_li+=[val for val in seoul_station[k]['브랜드']]
    oil_price_li+=[val for val in seoul_station[k]['휘발유 가격']]
    oil2_price_li+=[val for val in seoul_station[k]['경유 가격']]
    self_bool_li+=[val for val in seoul_station[k]['셀프 여부']]
    car_wash_bool_li+=[val for val in seoul_station[k]['세차장 여부']]
    charge_bool_li+=[val for val in seoul_station[k]['충전소 여부']]
    maintenance_bool_li+=[val for val in seoul_station[k]['경정비 여부']]
    conveni_bool_li+=[val for val in seoul_station[k]['편의점 여부']]
    all_day_bool_li+=[val for val in seoul_station[k]['24시간 운영 여부']]
    gu_li+=[val.split(' ')[1] for val in ad]


import pandas as pd
import numpy as np

df = pd.DataFrame(
    {
        'station': station_li,
        'address': address_li,
        'brand': brand_li,
        'oil-price': oil_price_li,
        'oil-price2': oil2_price_li,
        'self': self_bool_li,
        'wash': car_wash_bool_li,
        'charging': charge_bool_li,
        'maintenance': maintenance_bool_li,
        'conveni': conveni_bool_li,
        'operation': all_day_bool_li,
        'gu': gu_li        
    }
)


import googlemaps

gmaps_key="발급받은 키"
gmaps=googlemaps.Client(key=gmaps_key)

df['lat']=np.nan
df['lng']=np.nan

for idx, rows in df.iterrows():
    address=rows['address']
    tmp=gmaps.geocode(address, language='ko')
    lat=tmp[0]['geometry']['location']['lat']
    lng=tmp[0]['geometry']['location']['lng']
    ad=tmp[0]['formatted_address'].split()[2]
    df.loc[idx,'lat']=lat
    df.loc[idx,'lng']=lng
    

df.to_csv('./data/seoul_oil_station_data.csv',sep=',',encoding='utf-8')
df[['oil-price', 'oil-price2']]=df[['oil-price', 'oil-price2']].apply(lambda x:x.str.replace(',','')).astype(int)

df_ = df.copy()
df_.iloc[:,5:11]=df_.iloc[:,5:11].applymap(lambda x: 1 if x=='Y' else 0)

bool_col=['self','wash','charging','maintenance','conveni','operation']
df_service=df_.groupby('gu')[bool_col].agg('sum')
df_service.head()

# 구별 평균 휘발유, 경유 가격
df_oil_price=df_.groupby('gu')[['oil-price','oil-price2']].agg('mean')

total_station=df_.groupby('gu')[['oil-price2']].agg('count')
total_station.columns=['total oil stations']

df_service=pd.concat([total_station, df_service, df_oil_price], axis=1)
df_service.sort_values(by='oil-price',ascending=False)

col=df_service.columns
df_norm=df_service[col]/df_service[col].max()

df_self_price=df.groupby(['self'])[['oil-price', 'oil-price2']].agg('mean')
df_self_price

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

if platform.system()=="Darwin": #mac
    rc("font",family='Arial Unicodes MS')
    sns.set(font='Arial Unicodes MS', 
        rc={"axes.unicode_minus":False}),
    print('MAC Hangul OK')
    
df_oil1=df.pivot_table(values=['oil-price'], columns=['self'], index=['gu'], aggfunc='mean')
df_oil2=df.pivot_table(values=['oil-price2'], columns=['self'], index=['gu'], aggfunc='mean')

2. 수집한 정보를 바탕으로 휘발유와 경유 가격이 셀프 주유소에서 정말 저렴한지 분석

# 시각화
df_oil_1 = pd.DataFrame(df_oil1)

plt.rcParams["font.family"] = "Apple SD Gothic Neo"
df_oil_1.plot(kind='bar', figsize=(15, 8))
plt.title('구별 휘발유 및 경유 가격 정보')
plt.xlabel('구')
plt.ylabel('휘발유 가격')
plt.xticks(rotation=45, ha='right')
plt.legend(['셀프 아닌 주유소 휘발유 가격', '셀프주유소 휘발유 가격'])
plt.show()

 

# 시각화
df_oil_2 = pd.DataFrame(df_oil2)

plt.rcParams["font.family"] = "Apple SD Gothic Neo"
df_oil_2.plot(kind='bar', figsize=(15, 8))
plt.title('구별 휘발유 및 경유 가격 정보')
plt.xlabel('구')
plt.ylabel('휘발유 가격')
plt.xticks(rotation=45, ha='right')
plt.legend(['셀프 아닌 주유소 경유 가격', '셀프 주유소 경유 가격'])
plt.show()

분석 결과

 

셀프 주유소의 휘발유와 경유 가격이 그냥 주유소 가격보다 저렴한 것을 위의 막대 그래프를 통해 알 수 있다. 용산구 종로구 중구 강남구 지역의 휘발유와 경유 가격이 비싼 것으 알 수 있고 또한 셀프 유무에 따른 가격차이가 다른 구들보다 심한 것을 알 수 있다. 용산구의 경우 셀프 주유소가 없는 것을 추가로 확인할 수 있다.