EDA 학습 과제 2 - 주유소 : 데이터 취업 스쿨 스터디 노트 12/15

slocat·2023년 12월 15일
0

start-data

목록 보기
41/75

1. 서울시 구별 주유소 데이터 수집하고 정리하기

  • 부가 정보 데이터는 Y 또는 N 으로 저장
  • 컬럼 : 주유소명, 주소, 브랜드, 휘발유 가격, 경유 가격, 셀프 여부, 세차장 여부, 충전소 여부, 경정비 여부, 편의점 여부, 24시간 운영 여부, 구, 위도, 경도

1-1. 주유소 기본 정보 가져오기

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

클릭할 준비를 한다.

# 시/도
sido_list_raw = driver.find_element(By.ID, "SIDO_NM0")
sido_list = sido_list_raw.find_elements(By.TAG_NAME, "option")

# 서울 선택
seoul_select = sido_list[1].get_attribute("value")
sido_list_raw.send_keys(seoul_select)

# 구 리스트 만들기
gu_list_raw = driver.find_element(By.ID, "SIGUNGU_NM0")
gu_list = gu_list_raw.find_elements(By.TAG_NAME, "option")

gu_names = [option.get_attribute("value") for option in gu_list]
gu_names = gu_names[1:]

먼저 주유소명, 주소, 브랜드, 휘발유 가격, 경유 가격, 세차장 여부, 충전소 여부, 경정비 여부, 편의점 여부, 24시간 운영 여부 데이터를 모았다.

세차장이 있는 곳과 없는 곳의 HTML코드를 비교해보니, 없을 때만 off라는 글자가 있었다.(이미지 파일명이던가...) 그걸 이용해서 세차장 여부 데이터를 얻었다. 충전소, 경정비 등도 마찬가지이다.

name_list = []
address_list = []
brand_list = []
gas_price_list = []
diesel_price_list = []
car_wash_list = []
charging_list = []
garage_list = []
csv_list = []
all_day_list = []

for gu in tqdm_notebook(gu_names):
    driver.find_element(By.ID, "SIGUNGU_NM0").send_keys(gu)
    time.sleep(3)
    
    # 주유소별
    station_list_raw = driver.find_element(By.ID, "body1")
    station_list = station_list_raw.find_elements(By.TAG_NAME, "tr")
    
    for station in station_list:
        
        # 주유소 클릭
        station.find_element(By.TAG_NAME, "a").click()
        req = driver.page_source
        soup = BeautifulSoup(req, "html.parser")

        # 주유소명
        name = soup.select_one("#os_nm").text
        name_list.append(name)
        
        # 주소
        address = soup.select_one("#rd_addr").text
        address_list.append(address)
        
        # 브랜드
        brand = soup.select_one("#poll_div_nm").text
        brand_list.append(brand)
        
        # 휘발유 가격
        gas_price = soup.select_one("#b027_p").text
        gas_price_list.append(gas_price)
        
        # 경유 가격
        diesel_price = soup.select_one("#d047_p").text
        diesel_price_list.append(diesel_price)
        
        # 세차장 여부
        if "off" in soup.select_one("#cwsh_yn").get("src"):
            car_wash = "N"
        else:
            car_wash = "Y"
        car_wash_list.append(car_wash)
        
        # 충전소 여부
        if "off" in soup.select_one("#lpg_yn").get("src"):
            charging = "N"
        else:
            charging = "Y"
        charging_list.append(charging)
        
        # 경정비 여부
        if "off" in soup.select_one("#maint_yn").get("src"):
            garage = "N"
        else:
            garage = "Y"
        garage_list.append(garage)
        
        # 편의점 여부
        if "off" in soup.select_one("#cvs_yn").get("src"):
            csv = "N"
        else:
            csv = "Y"
        csv_list.append(csv)
        
        # 24시간 운영 여부
        if "off" in soup.select_one("#sel24_yn").get("src"):
            all_day = "N"
        else:
            all_day = "Y"
        all_day_list.append(all_day)

셀프 여부는 데이터를 코드를 따로 작성했다.
위 코드에서 주유소를 클릭하기 전에 driver를 이용해서 데이터를 얻어보려고 이런저런 시도를 해봤는데 잘 안되었다. BeautifulSoup을 이용해서 셀프 여부 데이터를 얻고 주유소를 클릭하는 방법도 있겠지만 약간 과부하가 와서... 다음에 시도해보기로 하고 간단한 방법을 이용했다. 주말에 다시 해볼 생각이다.

# 셀프 여부
is_self_list = []

for gu in tqdm_notebook(gu_names):
    driver.find_element(By.ID, "SIGUNGU_NM0").send_keys(gu)
    time.sleep(3)
    
    req = driver.page_source
    soup = BeautifulSoup(req, "html.parser")
    
    station_list_raw = soup.select_one("#body1")
    station_list = station_list_raw.select('.rlist')
    
    for station in station_list:
        if "셀프" in station.text:
            is_self = "Y"
        else:
            is_self= "N"
            
        is_self_list.append(is_self)

필요한 정보를 모두 얻어왔으니 driver를 꺼준다.

driver.quit()

1-2. 구, 위도, 경도 데이터 가져오기

# 구 데이터
address_gu_list = []
for address in address_list:
    gu = address_list[0].split(" ")
    address_gu_list.append(address.split(" ")[1])
import googlemaps

gmaps_key = "인증키"
gmaps = googlemaps.Client(key=gmaps_key)

# 위도, 경도 데이터 가져오기
lat_list = []
lng_list = []

for address in address_list:
    tmp = gmaps.geocode(address, language="ko")[0]
    
    lat = tmp.get("geometry")["location"]["lat"]
    lat_list.append(lat)
    lng = tmp.get("geometry")["location"]["lng"]
    lng_list.append(lng)

1-3. 데이터프레임으로 정리하기

stations = pd.DataFrame({
    "name": name_list,
    "address": address_list,
    "brand": brand_list,
    "gasoline_price": gas_price_list,
    "diesel_price": diesel_price_list,
    "self": is_self_list,
    "car_wash": car_wash_list,
    "charging": charging_list,
    "garage": garage_list,
    "csv": csv_list,
    "all_day": all_day_list,
    "gu": address_gu_list,
    "lat": lat_list,
    "lng": lng_list
}, )

휘발유, 경유 가격의 타입이 object로 되어 있다.
콤마를 제거해주고 실수 타입으로 변경했다.

# 휘발유, 경유 가격 type 변환
stations["gasoline_price"] = stations["gasoline_price"].str.replace(",", "").astype(float)
stations["diesel_price"] = stations["diesel_price"].str.replace(",", "").astype(float)

2. 휘발유와 경유 가격이 셀프 주유소에서 더 저렴한가?

2-1. 수치로 비교

# 전체 주유소 가격 비교
df = stations.pivot_table(index=["self"],
                          values=["gasoline_price", "diesel_price"],
                          aggfunc="mean")

df = df.transpose()
df["gap"] = df["N"] - df["Y"]
df

# 셀프 주유소 - 브랜드별 가격 비교
df_self_brand = stations[stations["self"] == "Y"].pivot_table(index=["brand"],
                          values=["gasoline_price", "diesel_price", "name"],
                          aggfunc={"gasoline_price": "mean", "diesel_price": "mean", "name": "count"},
                          margins=True,
                          margins_name="mean / mean / count")

df_self_brand
# 일반 주유소 - 브랜드별 가격 비교
df_non_self_brand = stations[stations["self"] == "N"].pivot_table(index=["brand"],
                          values=["gasoline_price", "diesel_price", "name"],
                          aggfunc={"gasoline_price": "mean", "diesel_price": "mean", "name": "count"},
                          margins=True,
                          margins_name="mean / mean / count")

df_non_self_brand

2-2. 시각화

import matplotlib.pyplot as plt
from matplotlib import rc
import seaborn as sns

plt.rcParams['axes.unicode_minus'] = False
rc("font", family="Malgun Gothic")
%matplotlib inline
# 휘발유 가격
plt.figure(figsize=(10, 6))
sns.boxplot(x="self", y="gasoline_price", data=stations, palette="Set2")
plt.grid(True)
plt.show()

# 휘발유 가격 - 브랜드별
plt.figure(figsize=(10, 6))
sns.boxplot(x="brand", y="gasoline_price", hue="self", data=stations, palette="Set2")
plt.grid(True)
plt.show()
# 경유 가격
plt.figure(figsize=(10, 6))
sns.boxplot(x="self", y="diesel_price", data=stations, palette="Set3")
plt.grid(True)
plt.show()

# 경유 가격 - 브랜드별
plt.figure(figsize=(10, 6))
sns.boxplot(x="brand", y="diesel_price", hue="self", data=stations, palette="Set3")
plt.grid(True)
plt.show()

🚗🚗🚗
이번 과제를 하면서 언제 BeautifulSoup을 쓰는 게 더 좋은지 느낄 수 있었다.
아직 BeautifulSoup과 Selenium 사이를 오고 가는 게 조금 헷갈려서 기본적인 부분을 꼼꼼하게 복습해야겠다.

0개의 댓글