2-1. 페이지 접근
from selenium import webdriver
url = 'https://www.opinet.co.kr/searRgSelect.do'
driver = webdriver.Chrome("../driver/chromedriver.exe")
driver.get(url)
2-2. 서울 선택(고정)
from selenium.webdriver.common.by import By
sido_list_raw = driver.find_element(By.CSS_SELECTOR, "#SIDO_NM0")
sido_list = sido_list_raw.find_elements(By.CSS_SELECTOR, "option")
sido_names = [option.get_attribute('value') for option in sido_list]
sido_names = sido_names[1:]
sido_list_raw.send_keys(sido_names[0]) # 서울 선택
OR
seoul = driver.find_element(By.CSS_SELECTOR, "#SIDO_NM0 > option:nth-child(2)")
seoul.click()
2-3. 구별 선택
gu_list_raw = driver.find_element(By.CSS_SELECTOR, "#SIGUNGU_NM0")
gu_list = gu_list_raw.find_elements(By.CSS_SELECTOR, "option")
gu_names = [option.get_attribute('value') for option in gu_list if option.get_attribute('value')] # 공백 제거
OR
# 2부터 강남구 시작
driver.find_element(By.CSS_SELECTOR, "#SIGUNGU_NM0 > option:nth-child(2)").text
# 반복문 테스트
# 서울 고정
# 구별 순환
# "#SIGUNGU_NM0 > option:nth-child(2)" -> 강남구 (시작)
# "#SIGUNGU_NM0 > option:nth-child(26)" -> 중랑구 (끝)
import time
for i, v in enumerate(gu_names): # enumerate는 index, value를 가져옴
gu_selector = f'#SIGUNGU_NM0 > option:nth-child({i+2})'
driver.find_element(By.CSS_SELECTOR, gu_selector).click()
# 목적에 맞는 데이터를 가져오는지 확인
totCnt = driver.find_element(By.CSS_SELECTOR, "#totCnt").text # 표시된 주유소 개수
gu_totalCnt = len(driver.find_elements(By.CSS_SELECTOR, "#body1 > tr")) # 직접 주유소 개수 구하기 -> 두 데이터를 비교해서 정확히 가져오는지 확인
print(i, v, totCnt, gu_totalCnt)
time.sleep(0.5)
2-4. 서울시 구별 주유소 데이터 수집
# 데이터 수집 첫 번째 시도
# 하나의 구에서 데이터 수집 테스트
body1 = driver.find_element(By.CSS_SELECTOR, "#body1")
gas = body1.find_elements(By.CSS_SELECTOR, "td:nth-child(2)") # 휘발유값
diesel = body1.find_elements(By.CSS_SELECTOR, "#td:nth-child(3)) # 경유값
brand = body1.find_elements(By.CSS_SELECTOR, ".rlist img")
is_self = body1.find_elements(By.CSS_SELECTOR, "td.rlist span.ico")
name = body1.find_elements(By.CSS_SELECTOR, ".rlist > a")
gas[0].text, diesel[0].text, brand[0].get_attribute('alt'), is_self[0].text, name[0].text
# 이름이 길면 잘려서 나옴
# a 태그 데이터 가져오기
a_tag = body1.find_elements(By.CSS_SELECTOR, ".rlist a")
a_tag[0].get_attribute('href')
# 한글이 깨져나옴
-> 이 방법은 실패
# 데이터 수집 두 번째 시도
# 세부 페이지 클릭
driver.find_element(By.CSS_SELECTOR, "#body1 a").click()
driver.find_element(By.CSS_SELECTOR, ".header #os_nm").text # 클래스 header 밑에 id값 지정
-> 화면상에서 글자가 가려져서 안 보이게 되면, ''공백을 가져옴.
-> 구글링해보기
driver.find_element(By.CSS_SELECTOR, ".header #os_nm").get_attribute("innerText")
-> 화면상 정보가 나타나지 않아도 데이터를 가져올 수 있음
# text와 'innerText, innerHTML, textContent'
# text는 화면에 안 보이면 데이터를 불러오지 못하지만, innerText 등은 화면에 보이지 않더라도 데이터를 가져올 수 있음
station_title_text = driver.find_element(By.CSS_SELECTOR, ".header #os_nm").text
station_title_innerText = driver.find_element(By.CSS_SELECTOR, ".header #os_nm").get_attribute("innerText")
station_title_text, station_title_innerText
# 반복문 테스트
# 세부 페이지에서 주유소 이름 가져오기
import time
for i, v in enumerate(gu_names): # 구 선택
gu_selector = f'#SIGUNGU_NM0 > option:nth-child({i+2})'
driver.find_element(By.CSS_SELECTOR, gu_selector).click()
time.sleep(1)
print('--------------------')
for idx in range(0, 3): # 주유소 선택
detail_selector = f'#body1 > tr:nth-child({idx+1}) > td.rlist > a'
driver.find_element(By.CSS_SELECTOR, detail_selector).click()
title = driver.find_element(By.CSS_SELECTOR, ".header #os_nm").get_attribute("innerText")
print(title)
# 테스트 코드
# 구별로 순회하면서, 세부 페이지 주유소 이름 수집
for i, v in enumerate(gu_names[:3]):
gu_selector = f'#SIGUNGU_NM0 > option:nth-child({i+2})'
driver.find_element(By.CSS_SELECTOR, gu_selector).click()
station_items = driver.find_elements(By.CSS_SELECTOR, "#body1 > tr") # 주유소 목록
print()
print(f'============{v}에는 {len(station_items)}개의 주유소 존재===========')
for idx in range(len(station_items))[:3]:
detail_selector = f'#body1 > tr:nth-child({idx+1}) > td.rlist > a'
driver.find_element(By.CSS_SELECTOR, detail_selector).click()
title = driver.find_element(By.CSS_SELECTOR, ".header #os_nm").get_attribute("innerText")
print(f'{v} 주유소 이름 : ', title)
time.sleep(0.5)
# 메인 데이터 수집
name = driver.find_element(By.CSS_SELECTOR, ".header #os_nm").get_attribute("innerText")
gasoline = driver.find_element(By.CSS_SELECTOR, "#b027_p").get_attribute("innerText")
diesel = driver.find_element(By.CSS_SELECTOR, "#d047_p").get_attribute("innerText")
address = driver.find_element(By.CSS_SELECTOR, "#rd_addr").get_attribute("innerText")
brand = driver.find_element(By.CSS_SELECTOR, "#poll_div_nm").get_attribute("innerText")
name, gasoline, diesel, address, brand
# 부가정보 데이터 수집
cwsh_yn = driver.find_element(By.CSS_SELECTOR, ".service #cwsh_yn")
cwsh_yn.get_attribute('src').split('/')[-1] # '/'로 나누고, 마지막꺼를 가져옴
# 세차장 유무
'N' if '_off' in cwsh_yn.get_attribute('src').split('/')[-1] else 'Y'
# 충전소 유무
lpg_yn = driver.find_element(By.CSS_SELECTOR, ".service #lpg_yn")
'N' if '_off' in lpg_yn.get_attribute('src').split('/')[-1] else 'Y'
# 셀프 여부
try:
driver.find_element(By.CSS_SELECTOR, "#self_icon").get_attribute("alt")
is_self = 'Y'
except:
is_self = 'N'
is_self
2-5. 전체 데이터 수집(구, 위도, 경도 포함)
# 1. 페이지 접근
url = 'https://www.opinet.co.kr/searRgSelect.do'
driver = webdriver.Chrome("../driver/chromedriver.exe")
driver.get(url)
driver.get(url)
# 2. 서울 선택
seoul = driver.find_element(By.CSS_SELECTOR, "#SIDO_NM0 > option:nth-child(2)")
seoul.click()
# 3. 구별 선택
gu_list_raw = driver.find_element(By.CSS_SELECTOR, "#SIGUNGU_NM0")
gu_list = gu_list_raw.find_elements(By.CSS_SELECTOR, "option")
gu_names = [option.get_attribute('value') for option in gu_list if option.get_attribute('value')]
import pandas as pd
import time
import googlemaps
gmaps_key = "AIzaSyAc-8jqf4pKjDW91-dggnio0Sda7IdTZqA"
gmaps = googlemaps.Client(key=gmaps_key)
datas = []
for i in range(len(gu_names)):
gu_selector = f'#SIGUNGU_NM0 > option:nth-child({i+2})'
driver.find_element(By.CSS_SELECTOR, gu_selector).click()
station_items = driver.find_elements(By.CSS_SELECTOR, "#body1 > tr")
for idx in range(len(station_items)):
detail_selector = f'#body1 > tr:nth-child({idx+1}) > td.rlist > a'
driver.find_element(By.CSS_SELECTOR, detail_selector).click()
name = driver.find_element(By.CSS_SELECTOR, ".header #os_nm").get_attribute("innerText")
gasoline = driver.find_element(By.CSS_SELECTOR, "#b027_p").get_attribute("innerText")
diesel = driver.find_element(By.CSS_SELECTOR, "#d047_p").get_attribute("innerText")
address = driver.find_element(By.CSS_SELECTOR, "#rd_addr").get_attribute("innerText")
brand = driver.find_element(By.CSS_SELECTOR, "#poll_div_nm").get_attribute("innerText")
cwsh_yn = 'N' if '_off' in driver.find_element(By.CSS_SELECTOR, ".service #cwsh_yn").get_attribute('src').split('/')[-1] else 'Y'
lpg_yn = 'N' if '_off' in driver.find_element(By.CSS_SELECTOR, ".service #lpg_yn").get_attribute('src').split('/')[-1] else 'Y'
maint_yn = 'N' if '_off' in driver.find_element(By.CSS_SELECTOR, ".service #maint_yn").get_attribute('src').split('/')[-1] else 'Y'
cvs_yn = 'N' if '_off' in driver.find_element(By.CSS_SELECTOR, ".service #cvs_yn").get_attribute('src').split('/')[-1] else 'Y'
sel24_yn = 'N' if '_off' in driver.find_element(By.CSS_SELECTOR, ".service #sel24_yn").get_attribute('src').split('/')[-1] else 'Y'
try:
driver.find_element(By.CSS_SELECTOR, "#self_icon").get_attribute("alt")
is_self = 'Y'
except:
is_self = 'N'
# address
address = driver.find_element(By.CSS_SELECTOR, "#rd_addr").get_attribute("innerText")
# gu
gu = address.split()[1]
# lat, lng
tmp = gmaps.geocode(address, language='ko')
lat = tmp[0].get('geometry')['location']['lat']
lng = tmp[0].get('geometry')['location']['lng']
datas.append({
'name' : name,
'address' : address,
'brand' : brand,
'is_self' : is_self,
'gasoline' : gasoline,
'diesel' : diesel,
'car_wash' : cwsh_yn,
'charging_station' : lpg_yn,
'car_maintenance' : maint_yn,
'convenience_store': cvs_yn,
'24_hour' : sel24_yn,
'gu' : gu,
'lat' : lat,
'lng' : lng
})
time.sleep(0.2)
time.sleep(0.5)
driver.quit()
df = pd.DataFrame(datas)
df.tail()
df.info()
# csv 파일 저장
import datetime
now = datetime.datetime.now() # 현재날짜시각
nowDate = now.strftime('%Y%m%d') # 형식 정해주기
df.to_csv(f'./oilstation_oneday_{nowDate}.csv', encoding='utf-8')
# csv 파일 읽기
stations = pd.read_csv('./oilstation_oneday_20220307.csv', encoding='utf-8', thousands=',', index_col=0)
stations
-> thousands=',' : 세자리수마다 있는 ,를 없애고 숫자형으로 가져옴
import matplotlib.pyplot as plt
%matplotlib inline
from matplotlib import rc
rc("font", family="Malgun Gothic")
# 휘발유 boxplot (feat. seaborn의 boxplot)
plt.figure(figsize=(12, 8))
sns.boxplot(x='is_self', y='gasoline', data=stations, palette='Set1')
plt.grid(True)
plt.show()
# 휘발유 브랜드별 비교 (feat. seaborn의 boxplot)
plt.figure(figsize=(12, 8))
sns.boxplot(x='brand', y='gasoline', hue='is_self', data=stations, palette='Set1')
plt.grid(True)
plt.show()
# 휘발유 구별 비교 (feat. seaborn의 boxplot)
plt.figure(figsize=(18, 8))
sns.boxplot(x='gu', y='gasoline', data=stations, palette='Set1')
plt.grid(True)
plt.show()
# 경유 boxplot (feat. seaborn의 boxplot)
plt.figure(figsize=(12, 8))
sns.boxplot(x='is_self', y='diesel', data=stations, palette='Set1')
plt.grid(True)
plt.show()
# 경유 브랜드별 비교 (feat. seaborn의 boxplot)
plt.figure(figsize=(12, 8))
sns.boxplot(x='brand', y='diesel', hue='is_self', data=stations, palette='Set1')
plt.grid(True)
plt.show()
# 경유 구별 비교 (feat. seaborn의 boxplot)
plt.figure(figsize=(18, 8))
sns.boxplot(x='gu', y='diesel', data=stations, palette='Set1')
plt.grid(True)
plt.show()
import json
import folium
# 가장 비싼 주유소 10개
stations[['gu', 'name', 'is_self', 'gasoline']].sort_values(by='gasoline', ascending=False).head(10).reset_index(drop=True)
# 가장 값싼 주유소 10개
stations[['gu', 'name', 'is_self', 'gasoline']].sort_values(by='gasoline', ascending=True).head(10).reset_index(drop=True)
# 지도 시각화용 데이터프레임
import numpy as np
gu_data = pd.pivot_table(data=stations, index='gu', values='gasoline', aggfunc=np.mean)
gu_data.head()
geo_path = '../data/02. skorea_municipalities_geo_simple.json'
geo_str = json.load(open(geo_path, encoding='utf-8'))
m = folium.Map(location=[37.5502, 126.982], zoom_start=10.5)
m.choropleth(
geo_data=geo_str,
data=gu_data,
columns=[gu_data.index, 'gasoline'],
key_one='feature.id',
fill_color='PuRd'
)
m
<제로베이스 데이터 취업 스쿨>