본문 바로가기

데이터 청년 캠퍼스(경남대학교)/수업

2021-07-01 (2)

데이터 크롤링

 

!pip install selenium #selenium 설치

from selenium import webdriver
driver = webdriver.Chrome('C:\data\chromedriver') #크롬... 가상의 창에서 작업
driver.get('http://naver.com') #네이버 사이트에서 활용하기!

네이버 사이트에서 로그인하는 크롤링을 할 예정!

 

xpath='//*[@id="account"]'
driver.find_element_by_xpath(xpath).click()

네이버 메인화면에서 로그인을 클릭하는 작업을 하는 코드

xpath를 통해 작업 수행

 

elem_login = driver.find_element_by_id('id')
elem_login.clear()
elem_login.send_keys('*********') #값을 입력하는 명령어

elem_login = driver.find_element_by_id('pw')
elem_login.clear()
elem_login.send_keys('**********')

********* 자리에는 각각 아이디와 비밀번호를 입력하면 됨!

여기서는 아이디 값을 사용해서 작업을 수행함

 

# 태그 오른쪽 클릭->Copy->xpath 밑에 붙여넣기
# find_element_by_xpath(xpath) : xpath 위치 찾기
# click() : 로그인 버튼 클릭하는 함수
xpath='//*[@id="log.login"]'
driver.find_element_by_xpath(xpath).click()

아이디와 비밀번호를 입력하고 로그인을 클릭하는 작업을 함!

그런데 비밀번호랑 아이디가 맞는건데도 로그인에 실패함..

 


두 번째 크롤링은 오피넷?에서 서울시 기름의 가격을 크롤링

 

from selenium import webdriver
driver = webdriver.Chrome('C:\data\chromedriver')
driver.get("http://www.opinet.co.kr") #메인화면
driver.get("http://www.opinet.co.kr/searRgSelect.do") #자료를 뽑아낼 주소

 

서울 주유소 가격을 추출할 것임!

# 서울 클릭을 위한 xpath 확인
area = driver.find_element_by_xpath('//*[@id="SIDO_NM0"]')
area.send_keys('서울')

서울 클릭

# 구/데이터 입력을 위한 xpath 확인
gu_list_raw = driver.find_element_by_xpath('//*[@id="SIGUNGU_NM0"]')

# 구 리스트 확인 위해 find_elements_by_tag_name으로 option 태그 검색
gu_list = gu_list_raw.find_elements_by_tag_name('option')

#value 속성을 이용하여 구 리스트 획득
gu_names = [option.get_attribute('value') for option in gu_list]
gu_names.remove('')

서울시 모든 구의 자료를 다운받을건데 먼저 잘 작동하는지 테스트 해 보기

#gu_names에서 리스트 첫번째 값 입력하여 테스트 진행
element = driver.find_element_by_id('SIGUNGU_NM0')
element.send_keys(gu_names[0])
#조회버튼의 Xpath를 찾아서 클릭
xpath ='''//*[@id="searRgSelect"]/span'''
element_sel_gu = driver.find_element_by_xpath(xpath).click()
#엑셀 저장 버튼 클릭하여 엑셀 내용 저장 테스트
xpath = '''//*[@id="glopopd_excel"]/span'''
element_get_excel = driver.find_element_by_xpath(xpath).click()

정상작동하는 것을 확인했으면 반복문을 사용해서 모든 데이터 다운받기

 

import time
from tqdm import tqdm_notebook #진행되는 과정을 보여줌

# 반복문을 이용하여 모든 구 엑셀파일 다운로드 진행
for gu in tqdm_notebook(gu_names):
    element = driver.find_element_by_id('SIGUNGU_NM0')
    element.send_keys(gu)
    
    time.sleep(2)# 데이터 획득 위한 지연 시간
    
    xpath ='''//*[@id="searRgSelect"]/span'''
    element_sel_gu = driver.find_element_by_xpath(xpath).click()
    
    time.sleep(1)

    xpath = '''//*[@id="glopopd_excel"]/span'''
    element_get_excel = driver.find_element_by_xpath(xpath).click()
    
    time.sleep(1)

다운받은 후에는 파일의 위치를 옮겨주거나 파일 경로를 찾아야 함

 

# station_files 변수에 각 엑셀 파일의 경로와 이름을 리스트로 저장
stations_files = glob('지역*.xls')
stations_files

나는 현재 진행중인 주피터 노트북의 위치와 같은 위치에 저장함 그래서 경로 설정 없이 파일을 불러와서 저장

 

# concat 명령으로 합쳐본다.
tmp_raw = []

for file_name in stations_files:
    tmp = pd.read_excel(file_name, header=2) #header함수를 이용해서 인덱스2인 행을 제일 윗 행으로 만듦
    tmp_raw.append(tmp)

station_raw = pd.concat(tmp_raw)

header를 이용하여 필요없는 행을 날림

 

# 휘발유 데이터 저장.
stations = pd.DataFrame({'Oil_store': station_raw['상호'],
        '주소': station_raw['주소'],
        '가격': station_raw['휘발유'],
        '셀프': station_raw['셀프여부'],
        '상표': station_raw['상표']
        })
stations.head()

딕셔너리 형태 사용해서 데이터프레임을 만듦

 

# 구 이름만 추출
stations['구'] = [eachAddress.split()[1] for eachAddress in stations['주소']]
stations.head()

주소에서 구를 기준으로 구만 출력해서 새로운 행 만들기

 

# unique() 이용해서 데이터 검사 수행
stations['구'].unique() #구에 있는 값을 하나 하나 뽑아내는것?

어떤 구가 있는지 확인

 

stations['가격'].unique() #가격에 '-'가 있음

가격에 있는 값들을 확인 '-' 값은 지워줘야함

 

#가격에 '-' 값만 추출
stations[stations['가격']=='-'].count() #17개 있음

# '-' 문자가 포함된 데이터 제외
stations = stations[stations['가격'] != '-']
# 가격 float 형 변환.
stations['가격'] = [float(value) for value in stations['가격']] 
# reset_index 이용하여 index 재정의
stations.reset_index(inplace=True)
del stations['index']# 기존 인덱스 삭제

 

시각화

stations.boxplot(column='가격', by='셀프', figsize=(12,8))
plt.show()

그래프를 보면 셀프 주유소의 가격이 더 저렴하다는 것을 알 수 있음

 

plt.figure(figsize=(12,8))
sns.boxplot(x='상표', y='가격', hue='셀프', data=stations, palette='Set3')
plt.show()

sk에너지 주유소의 가격이 가장 비싸다는 것이 확인됨

 

plt.figure(figsize=(12,8))
sns.boxplot(x='상표', y='가격', data=stations, palette='Set3')
sns.swarmplot(x='상표', y='가격', data=stations, color='.6')
plt.show()

박스플롯과 함께 각 데이터들의 분포 확인

 

!pip install folium
!pip install googlemaps
#다운로드
import json
import folium
import googlemaps
# 이제 서울시에서 가장 주유 가격이 비싼 주유소
stations.sort_values(by='가격', ascending=False).head(10)

가격이 높은 상위 10개

 

import googlemaps
gmaps_key = 'AIzaSyDekfiVYSFscguylCGOYdtGTjwf0twUubE' # API설정할 때 얻은 key
gmaps = googlemaps.Client(key=gmaps_key)
# pivot_table을 이용해서 구별 가격 정보로 변경하고 가격 평균값 정리.
import numpy as np
gu_data = pd.pivot_table(stations, index=['구'], values=['가격'], aggfunc=np.mean)
gu_data.head()

구별로 가격의 평균을 구해서 저장

 

# 서울시 구별 정보에 대해 지도로 표현
geo_path = 'skorea_municipalities_geo_simple.json'
geo_str = json.load(open(geo_path, encoding='utf-8'))
map = folium.Map(location=[37.5502, 126.982], zoom_start=10.5, 
tiles='Stamen Toner')
map.choropleth(geo_data = geo_str,
data = gu_data,
columns=[gu_data.index, '가격'],
fill_color='PuRd', #PuRd, YlGnBu
key_on='feature.id')
map

색깔이 진할수록 비싼 지역

 

# 주유 가격 상위 10개 주소 oil_price_top10 저장.
oil_price_top10 = stations.sort_values(by='가격', ascending=False).head(10)
#oil_price_top10

# 하위 10개 oil_price_bottom10 저장
oil_price_bottom10 = stations.sort_values(by='가격', 
ascending=True).head(10)
#oil_price_bottom10
from tqdm import tqdm_notebook

lat = []
lng = []

for n in tqdm_notebook(oil_price_top10.index):
    try:
        tmp_add = str(oil_price_top10['주소'][n]).split('(')[0]
        tmp_map = gmaps.geocode(tmp_add)

        tmp_loc = tmp_map[0].get('geometry')
        lat.append(tmp_loc['location']['lat'])
        lng.append(tmp_loc['location']['lng'])

    except:
        lat.append(np.nan)
        lng.append(np.nan)
        print('Here is nan !')
        
oil_price_top10['lat']=lat
oil_price_top10['lng']=lng
#oil_price_top10


lat = []
lng = []

for n in tqdm_notebook(oil_price_bottom10.index):
    try:
        tmp_add = str(oil_price_bottom10['주소'][n]).split('(')[0] #괄호 제거
        tmp_map = gmaps.geocode(tmp_add)

        tmp_loc = tmp_map[0].get('geometry')
        lat.append(tmp_loc['location']['lat'])
        lng.append(tmp_loc['location']['lng'])

    except:
        lat.append(np.nan)
        lng.append(np.nan)
        print('Here is nan !')

oil_price_bottom10['lat']=lat
oil_price_bottom10['lng']=lng
#oil_price_bottom10

lat와 lug을 새로운 열 추가

 

map = folium.Map(location=[37.5202, 126.975], zoom_start=10.5)

for n in oil_price_top10.index:
    if pd.notnull(oil_price_top10['lat'][n]):
        folium.CircleMarker([oil_price_top10['lat'][n], 
                             oil_price_top10['lng'][n]],
                            radius=15, color='#CD3181',
                            fill_color='#CD3181').add_to(map)

for n in oil_price_bottom10.index:
    if pd.notnull(oil_price_bottom10['lat'][n]):
        folium.CircleMarker([oil_price_bottom10['lat'][n],
                                oil_price_bottom10['lng'][n]],
                                radius=15, color='#3186cc',
                                fill_color='#3186cc').add_to(map)

map

지도에 원으로 나타내기

'데이터 청년 캠퍼스(경남대학교) > 수업' 카테고리의 다른 글

2021-07-09  (0) 2021.07.09
2021 - 07 - 02  (0) 2021.07.02
2021-07-01 (1)  (0) 2021.07.01
2021-06-29  (0) 2021.07.01
2021-06-28  (0) 2021.07.01