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()
# 구 데이터
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)
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)
# 전체 주유소 가격 비교
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
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 사이를 오고 가는 게 조금 헷갈려서 기본적인 부분을 꼼꼼하게 복습해야겠다.