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()
분석 결과
셀프 주유소의 휘발유와 경유 가격이 그냥 주유소 가격보다 저렴한 것을 위의 막대 그래프를 통해 알 수 있다. 용산구 종로구 중구 강남구 지역의 휘발유와 경유 가격이 비싼 것으 알 수 있고 또한 셀프 유무에 따른 가격차이가 다른 구들보다 심한 것을 알 수 있다. 용산구의 경우 셀프 주유소가 없는 것을 추가로 확인할 수 있다.
'프로젝트로 배우는 데이터사이언스' 카테고리의 다른 글
Tableau 실습 예제 (1, 2) (0) | 2024.05.17 |
---|---|
데이터 분석 과제 - 이디야 커피는 스타벅스 커피 매장이 위치하는 곳에 위치할까? (0) | 2024.04.29 |