- 이전까지는 어떤 걸 클릭시 사이트 주소가 바뀌었지만,
- https://www.opinet.co.kr/searRgSelect.do 에서는
- 지역을 설정하고 조회해도 위 사이트 주소가 변동되지 않음.
- 그리고 검색어를 넣는게 아닌, 목록 중에 골라서 검색해야됨
목표 데이터
- 브랜드
- 가격
- 셀프 주유 여부
- 위치
from selenium import webdriver
# 페이지 접근
driver = webdriver.Chrome("../driver/chromedriver.exe")
driver.get("https://www.opinet.co.kr/searRgSelect.do")
# 메인페이지가 열리고, 팝업창도 하나 뜸
--------------------
# 한번 더 실행하니 원하는 페이지로 이동함
# 1. 한번에 해당 URL로 한번에 접근이 안됨
# 2. 메인 페이지로 접속이 되고, 팝업창이 하나 뜸
driver.get("https://www.opinet.co.kr/searRgSelect.do")
--------------------
main = driver.window_handles
len(main)
# 창 2개 열려있음
>> 2
-----------------------
print(main)
# 창 2개 확인
>>
['AEF1944C39F4CAAF3D942755DE6F1CF5', '3F9DD24164580A9110EBE819ED7CCEE1']
-------------------------
import time
def main_get():
# 강의대로 하니까 안되어서 구글링해서 처리함
# 창이 여러개 열리면 0이 메인창이고, 1이 팝업창인 듯
# 팝업창으로 전환
driver.switch_to.window(driver.window_handles[1])
# 팝업창 닫기
driver.close()
time.sleep(3) # 셀레니움이 느려서 3초 멈춰준다
# 메인화면 창으로 전환
driver.switch_to.window(driver.window_handles[0])
# 접근 URL 다시 요청
driver.get("https://www.opinet.co.kr/searRgSelect.do")
main_get()
-------------------------------
# 지역: 시/도
# 지역관련 html 에 id 가 모두 있다 id = 'SIDO_NM0'
# 우리나라 시/도 목록을 가져오려면,
# 목록을 포함하고 있는 부모 태그를 가져와서 해당 목록을 가져온다
# id 로 해당 목록을 가져온다
from selenium.webdriver.common.by import By
sido_list_raw = driver.find_element(By.ID, value="SIDO_NM0") # 부모태그
sido_list_raw.text
>>
' 시/도\n \n \n 서울\n \n...
-----------------------------
# html 에서 option 태그를 기준으로 가져온다
# 여러개 가져오므로 find_elements 이다.
sido_list = sido_list_raw.find_elements(By.TAG_NAME, value="option") # 자식태그
len(sido_list)
>> 18
------------------------------
sido_list[1].text
>> '서울'
------------------------------
sido_list[:5].text
# 리스트값 하나하나는 .text 가 되는데, 리스트 몇개는 .text가 안됨
>> 에러
----------------------------------
# 풀네임 가져오기 : value 값 가져오기
sido_list[1].get_attribute("value")
>> '서울특별시'
---------------------------------
sido_names = []
for option in sido_list:
sido_names.append(option.get_attribute("value"))
# 한줄로 작성
# sido_names = [option.get_attribute("value") for option in sido_list]
sido_names
>>
['',
'서울특별시',
'부산광역시',
'대구광역시',
'인천광역시',
'광주광역시',
'대전광역시',
'울산광역시',
'세종특별자치시',
'경기도',
'강원도',
'충청북도',
'충청남도',
'전라북도',
'전라남도',
'경상북도',
'경상남도',
'제주특별자치도']
-----------------------------------
# 첫번째가 공백이어서 없애기
sido_names = sido_names[1:]
sido_names
>>
['서울특별시',
'부산광역시',
'대구광역시',
'인천광역시',
'광주광역시',
'대전광역시',
'울산광역시',
'세종특별자치시',
'경기도',
'강원도',
'충청북도',
'충청남도',
'전라북도',
'전라남도',
'경상북도',
'경상남도',
'제주특별자치도']
----------------------------
# 시/도 를 원하는 지역으로 바꾸기
# 서울로 함
sido_list_raw.send_keys(sido_names[0])
-------------------------------
# 서울의 구 목록 가져오기
# 지역: 구
# 지역관련 html 에 id 가 모두 있다 id = 'SIGUNGU_NM0'
# 우리나라 시/도 목록을 가져오려면,
# 목록을 포함하고 있는 부모 태그를 가져와서 해당 목록을 가져온다
# id 로 해당 목록을 가져온다
gu_list_raw = driver.find_element(By.ID, value="SIGUNGU_NM0") # 부모태그
# html 에서 option 태그를 기준으로 가져온다
# 여러개 가져오므로 find_elements 이다.
gu_list = gu_list_raw.find_elements(By.TAG_NAME, value="option") # 자식태그
gu_names = []
for option in gu_list:
gu_names.append(option.get_attribute("value"))
# 한줄로 작성
# gu_names = [option.get_attribute("value") for option in gu_list]
gu_names = gu_names[1:]
gu_names[:5], len(gu_names)
>> (['강남구', '강동구', '강북구', '강서구', '관악구'], 25)
# 구까지 선택하기
gu_list_raw.send_keys(gu_names[15])
-------------------------
# 엑셀 저장 (사이트 좌측 아래에 엑셀 저장 버튼이 있음)
# driver.find_elements 가져오려는 태그가 여러개인 경우
# driver.find_element 가져오려는 태그가 하나인 경우
# 해당 페이지에서 개발자도구에서 클릭하려는 페이지의 html 값에 우클릭 > copy > copy selector
# 복사한 값을 아래 value 값에 넣어줌
excel_btn = driver.find_element(By.CSS_SELECTOR, value="#glopopd_excel")
excel_btn.click() # 해당 페이지가 클릭됨
# 2. Xpath 로 엑셀저장
xpath_btn = driver.find_element(By.XPATH, value='//*[@id="glopopd_excel"]')
xpath_btn.click()
# 3. id 로 엑셀저장
id_btn = driver.find_element(By.ID, value='glopopd_excel')
id_btn.click()
# 서울 모든 구 별로 엑셀 다운받기
import time
from tqdm import tqdm_notebook
for gu in tqdm_notebook(gu_names):
element = driver.find_element(By.ID, value="SIGUNGU_NM0") # 부모태그
element.send_keys(gu)
time.sleep(3)
element_get_excel = driver.find_element(By.XPATH, value='//*[@id="glopopd_excel"]')
element_get_excel.click()
time.sleep(3)
- 파일 목록 한번에 가져오기 : glob()
- '지역_'으로 시작하고 끝이 xls 로 끝나는 모든 파일을 가져온다.
- 가져와서 파일의 목록을 저장함
- glob("../data/지역_*.xls")
import pandas as pd
from glob import glob
# 파일 목록 한번에 가져오기 glob
# '지역_'으로 시작하고 끝이 xls 로 끝나는 모든 파일을 가져온다.
# 가져와서 파일의 목록을 저장함
glob("../data/지역_*.xls")
>>
['../data\\지역_위치별(주유소) (1).xls',
'../data\\지역_위치별(주유소) (10).xls',
'../data\\지역_위치별(주유소) (11).xls',
'../data\\지역_위치별(주유소) (12).xls',
'../data\\지역_위치별(주유소) (13).xls',
'../data\\지역_위치별(주유소) (14).xls',
'../data\\지역_위치별(주유소) (15).xls',
'../data\\지역_위치별(주유소) (16).xls',
'../data\\지역_위치별(주유소) (17).xls',
'../data\\지역_위치별(주유소) (18).xls',
'../data\\지역_위치별(주유소) (19).xls',
'../data\\지역_위치별(주유소) (2).xls',
'../data\\지역_위치별(주유소) (20).xls',
'../data\\지역_위치별(주유소) (21).xls',
'../data\\지역_위치별(주유소) (22).xls',
'../data\\지역_위치별(주유소) (23).xls',
'../data\\지역_위치별(주유소) (24).xls',
'../data\\지역_위치별(주유소) (3).xls',
'../data\\지역_위치별(주유소) (4).xls',
'../data\\지역_위치별(주유소) (5).xls',
'../data\\지역_위치별(주유소) (6).xls',
'../data\\지역_위치별(주유소) (7).xls',
'../data\\지역_위치별(주유소) (8).xls',
'../data\\지역_위치별(주유소) (9).xls',
'../data\\지역_위치별(주유소).xls']
# 파일명 저장 # glob
stations_files = glob("../data/지역_*.xls")
stations_files[:5]
>>
['../data\\지역_위치별(주유소) (1).xls',
'../data\\지역_위치별(주유소) (10).xls',
'../data\\지역_위치별(주유소) (11).xls',
'../data\\지역_위치별(주유소) (12).xls',
'../data\\지역_위치별(주유소) (13).xls']
----------------------------------------
# 하나만 읽어보기
tmp = pd.read_excel(stations_files[0])
tmp.tail(2)
# 이름이 이상하다
# 엑셀을 열어보면 2번째 셀까지는 데이터가 없음
tmp = pd.read_excel(stations_files[0], header=2)
tmp.tail(2)
# tmp_raw 에 모두 담기
tmp_raw = []
for file_name in stations_files:
tmp = pd.read_excel(file_name, header=2)
tmp_raw.append(tmp)
tmp_raw
# 데이터 프레임으로 만들기
# 형식이 동일하고 연달아 붙이기만 하면 될 때는 concat
station_raw = pd.concat(tmp_raw)
station_raw
# 442 rows × 10 columns 인데,
# 인덱스번호 마지막이 33임
station_raw.info()
>>
<class 'pandas.core.frame.DataFrame'>
Int64Index: 442 entries, 0 to 33
Data columns (total 10 columns):
# Column Non-Null Count Dtype
--- ------ -------------- -----
0 지역 442 non-null object
1 상호 442 non-null object
2 주소 442 non-null object
3 상표 442 non-null object
4 전화번호 442 non-null object
5 셀프여부 442 non-null object
6 고급휘발유 442 non-null object
7 휘발유 442 non-null int64
8 경유 442 non-null int64
9 실내등유 442 non-null object
dtypes: int64(2), object(8)
memory usage: 38.0+ KB
----------------------------------
station_raw.columns
>>
Index(['지역', '상호', '주소', '상표', '전화번호', '셀프여부', '고급휘발유', '휘발유', '경유', '실내등유'], dtype='object')
# 컬럼 이름 바꾸고, 일부만 가져오기
station = pd.DataFrame({"상호": station_raw["상호"],
"주소": station_raw["주소"],
"가격": station_raw["휘발유"],
"셀프": station_raw["셀프여부"],
"상표": station_raw["상표"]
})
station.tail()
# 구이름 컬럼 추가하기
for each in station["주소"]:
print(each.split())
# 구이름 컬럼 추가하기
for each in station["주소"]:
print(each.split()[1])
# 구이름 컬럼 추가하기
station["구"] = [each.split()[1] for each in station["주소"]]
station
station["구"].unique(), len(station["구"].unique())
>>
(array(['강동구', '동대문구', '동작구', '마포구', '서대문구', '서초구', '성동구', '성북구', '송파구',
'양천구', '영등포구', '강북구', '용산구', '은평구', '종로구', '중구', '중랑구', '강서구',
'관악구', '광진구', '구로구', '금천구', '노원구', '도봉구', '강남구'], dtype=object),
25)
------------------------
station["가격"]
# 가격 데이터형 변환 object => float
station["가격"] = station["가격"].astype('float')
station["가격"]
# 가격 정보가 없는 주유소 : 없네??
station[station["가격"]== "-"]
-----------------------------
station
# 주유 가격정보 시각화
# matplolib 한글 대응 작업
import matplotlib.pyplot as plt
import seaborn as sns
import platform
from matplotlib import font_manager, rc
# get_ipython().run_line_magic("matplotlib", "inline")
# # %matplotlib inline
# path = "C:/Windows/Fonts/malgun.ttf"
# if platform.system() == "Darwin":
# rc("font", family="Arial Unicode MS")
# elif platform.system == "Windows":
# font_name = font_manager.FontProperties(fname=path).get_name()
# rc("font", family=font_name)
# else:
# print("Unknown system. sorry ~ ")
# 위 실행하면 에러뜸
# 그래서 아래 실행
import matplotlib.pyplot as plt
# import matplotlib as mpl
from matplotlib import rc
plt.rcParams['axes.unicode_minus'] = False # 마이너스 부호로 인해 한글깨짐현상 방지
rc("font", family='Malgun Gothic')
%matplotlib inline
# 동일 : get_ipython().run_inline_magic("matplotlib", 'inline')
# boxplot(feat. pandas)
station.boxplot(column="가격", by="셀프", figsize=(6, 4));
# boxplot(feat. seaborn)
plt.figure(figsize=(6, 4))
sns.boxplot(x="셀프", y="가격", data=station, palette="Set3")
plt.grid(True)
plt.show()
# boxplot(feat. seaborn)
plt.figure(figsize=(8, 6))
sns.boxplot(x="상표", y="가격", hue="셀프", data=station, palette="Set3")
plt.grid(True)
plt.show()
# 지도 시각화
import json
import folium
import warnings
warnings.simplefilter(action="ignore", category=FutureWarning)
# 가장 비싼 주유소 10곳
station.sort_values(by="가격", ascending=False).head(10)
# 가장 저렴한 주유소 10곳
station.sort_values(by="가격", ascending=True).head(10)
# 구별 평균가격
import numpy as np
gu_data = pd.pivot_table(data=station, index="구", values="가격", 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"))
my_map = folium.Map(location=[37.5502, 126.982], zoom_start=10.5, tiles="Stamen Toner")
my_map
geo_path = "../data/02. skorea_municipalities_geo_simple.json"
geo_str = json.load(open(geo_path, encoding="utf-8"))
my_map = folium.Map(location=[37.5502, 126.982], zoom_start=10.5, tiles="Stamen Toner")
my_map.choropleth(geo_data=geo_str,
data = gu_data,
columns=[gu_data.index, "가격"],
key_on="feature.id",
fill_color="PuRd")
위 글은 제로베이스 데이터 취업 스쿨의 강의자료를 참고하여 작성되었습니다.