log.Sehee
[데이터 취업 스쿨 스터디 노트] 시카고 맛집 웹데이터 분석 및 시각화 / 웹데이터분석 3 - 5 본문
시카고 맛집 데이터 분석 - 메인페이지
구글에 'chicago magazine the 50 best sandwiches' 검색하여 상단 웹페이지 링크 사용
총 51개 페이지에서 각 가게의 정보를 가져오기
fake-useragent 설치
pip install fake-useragent
from urllib.request import Request, urlopen
from bs4 import BeautifulSoup
from fake_useragent import UserAgent
url_base = 'https://www.chicagomag.com/'
url_sub = 'chicago-magazine/november-2012/best-sandwiches-chicago/'
url = url_base + url_sub
# UserAgent() : UserAgent를 랜덤으로 생성해준다.
ua = UserAgent()
# 403 Forbidden 상태코드. 접근 권한이 없을 때 뜬다. / header를 추가해야한다.
req = Request(url, headers={'User-Agent': ua.chrome})
html = urlopen(req)
soup = BeautifulSoup(html, 'html.parser')
print(soup.prettify())
! headers에 넣어야 하는 User-Agent 위치 (개발자도구 > 네트워크 > 상단의 GET 정보 최하단에 있다.)
내가 필요한 정보 확인 후 태그와 class or id 특정하기
# find_all
soup.find_all('div', 'sammy'), len(soup.find_all('div', 'sammy'))
# select
# soup.select('.sammy'), len(soup.select('.sammy'))
0번 인덱스로 조회
tmp_one = soup.find_all('div', 'sammy')[0]
tmp_one
메뉴와 가게 이름이 있는 태그의 text 가져오기
import re
tmp_string = tmp_one.find(class_='sammyListing').get_text()
# 'BLT\nOld Oak Tap\nRead more '
# \n or \r\n 기준으로 split
re.split(('\n|\r\n'), tmp_string)
column으로 사용할 리스트를 만든다.
from urllib.parse import urljoin
# 필요한 내용을 담을 빈 리스트
# 리스트로 하나씩 컬럼을 만들고, DataFrame으로 합칠 예정
rank = []
main_meau = []
cafe_name = []
url_add = []
list_soup = soup.find_all('div', 'sammy')
for item in list_soup:
rank.append(item.find(class_='sammyRank').get_text())
tmp_string = item.find(class_='sammyListing').get_text()
main_meau.append(re.split(('\n|\r\n'), tmp_string)[0])
cafe_name.append(re.split(('\n|\r\n'), tmp_string)[1])
# urljoin : href 태그에서 바로 가져온 링크는 상대 주소
# urljoin을 사용하면 baseUrl + href 형식으로 절대 주소로 만들 수 있다.
url_add.append(urljoin(url_base, item.find('a')['href']))
갯수가 맞는지 확인
len(rank), len(main_meau), len(cafe_name), len(url_add)
DataFrame으로 만들기
import pandas as pd
data = {
'Rank': rank,
'Menu': main_meau,
'Cafe': cafe_name,
'URL': url_add
}
df = pd.DataFrame(data)
df.tail(2)
컬럼 순서 변경
# 컬럼 순서 변경
df = pd.DataFrame(data, columns=['Rank', 'Cafe', 'Menu', 'URL'])
df.tail(2)
저장
df.to_csv(
'../data/03. best_sandwiches_list_chicago.csv', sep=',', encoding='utf-8'
)
시카고 맛집 데이터 분석 - 하위페이지
# requirements
import pandas as pd
from urllib.request import urlopen, Request
from fake_useragent import UserAgent
from bs4 import BeautifulSoup
df = pd.read_csv('../data/03. best_sandwiches_list_chicago.csv', index_col = 0)
df.tail()
DataFrame에 저장된 URL 정보를 사용하여 하위페이지의 정보 가져오기
ua = UserAgent()
req = Request(df['URL'][0], headers = {'user-agent':ua.chrome})
html = urlopen(req).read()
soup_tmp = BeautifulSoup(html, 'html.parser')
soup_tmp.find('p', 'addy')
텍스트 다듬기
import re
price_tmp = re.split('.,', price_tmp)[0]
price_tmp
정규표현식 사용하여 가격, 주소 분리하기
# 정규표현식 사용
# \$ : $ 기호 찾기
# \d+ : 하나 이상의 숫자
# \. : 소수점
# (\d+) : 소수점 뒤 하나 이상의 숫자가 있을 수 있음
# ? : 선택적 옵션
# 특수문자는 앞에 백슬래시 \ 를 붙여 이스케이프 처리해야한다.
tmp = re.search('\$\d+\.(\d+)?', price_tmp).group() # $10.
price_tmp[len(tmp) + 2:] # '2109 W. Chicago Ave'
tqdm 설치
pip install tqdm
column으로 사용할 리스트 만들기
from tqdm import tqdm
price = []
address = []
# tqdm : 코드 진행 상태를 시각적으로 표현해준다
for idx, row in tqdm(df.iterrows()):
req = Request(row['URL'], headers = {'user-agent':ua.chrome})
html = urlopen(req).read()
soup_tmp = BeautifulSoup(html, 'html.parser')
gettings = soup_tmp.find('p', 'addy').get_text()
price_tmp = re.split('.,', gettings)[0]
tmp = re.search('\$\d+\.(\d+)?', price_tmp).group()
price.append(tmp)
address.append(price_tmp[len(tmp) + 2:])
DataFrame에 가격, 주소 정보 추가
df['Price'] = price
df['Address'] = address
column 순서 변경 및 인덱스 변경
df = df.loc[:, ['Rank', 'Cafe', 'Menu', 'Price', 'Address']]
df.set_index('Rank', inplace=True)
df.head()
저장
df.to_csv(
'../data/03. best_sandwiches_list_chicago2.csv', sep=',', encoding='utf-8'
)
시카고 맛집 데이터 지도 시각화
import folium, googlemaps, pandas as pd, numpy as np
from tqdm import tqdm
gmaps_key = 발급받은 API key
gmaps = googlemaps.Client(key=gmaps_key)
df = pd.read_csv('../data/03. best_sandwiches_list_chicago2.csv', index_col = 0)
df.tail()
위도, 경도 정보 가져오기
lat = []
lng = []
for idx, row in tqdm(df.iterrows()):
# 주소가 여러 개가 아닐 때 실행
if not row['Address'] == 'Multiple location':
target_name = row['Address'] + ', ' + 'Chicago'
gmaps_output = gmaps.geocode(target_name)
location_output = gmaps_output[0].get('geometry')
lat.append(location_output['location']['lat'])
lng.append(location_output['location']['lng'])
# 주소가 여러 개라면 null값 추가
else:
lat.append(np.nan)
lng.append(np.nan)
DataFrame에 위치정보 추가
df['lat'] = lat
df['lng'] = lng
df.tail()
folium으로 지도 표시
mapping = folium.Map(location=[41.8781136, -87.6297982], zoom_start=11)
for idx, row in df.iterrows():
if not row['Address'] == 'Multiple location':
folium.Marker(
location = [row['lat'], row['lng']],
popup=row['Cafe'],
tooltip=row['Menu'],
icon = folium.Icon(
icon = 'coffee',
prefix='fa'
)
).add_to(mapping)
mapping
내일의 학습 목표
유가분석 1 - 3
Comments