3 샌드위치 맛집 좌표 구글맵에 찍기
3-1 인터넷의 top50 샌드위치 DF로 만들기
url_base = 'http://www.chicagomag.com'
url_sub = '/Chicago-Magazine/November-2012/Best-Sandwiches-Chicago/'
from bs4 import BeautifulSoup
from urllib.request import Request, urlopen
url = Request(url_base + url_sub,headers={'User-Agent': 'Mozilla/5.0'})
html = urlopen(url)
soup = BeautifulSoup(html, "html.parser")
- Request로 Request 객체 만들고(이때 user 설정해서 우회) -> urlopen으로 HTTP respnse객체로 -> BeautifulSoup 객체로 파싱
a = soup.select('.sammyListing')
for i in a:
print(i.text)
foodList = []
placeList = []
numList = [i for i in range(1, 51)]
urlList = []
for i in a:
text = i.text.split('\n')
foodList.append(text[0])
placeList.append(text[1])
if i.attrs['href'].startswith('http'):
urlList.append(i.attrs['href'])
else:
url = 'https://www.chicagomag.com' + i.attrs['href']
urlList.append(url)
import pandas as pd
df = pd.DataFrame(data={
'Rank': numList,
'Menu': foodList,
'Cafe': placeList,
'URL': urlList})

3-2 다수의 개별 페이지 접근해서 원하는 정보 들고오기
from bs4 import BeautifulSoup
from urllib.request import Request, urlopen
import pandas as pd
df = pd.read_csv('../data/best_sandwiches_chicago11.csv', encoding='utf-8', index_col=0)
print(df.index)
df['URL'][0]
- 모듈 호출 부분에서 urllib의 request는 requests와 다른 모듈.
전자는 파이썬 표준이고, 후자는 외부 모듈이다.
전자는 상대적으로 낮은 수준의 HTTP 요청 작업 수행, 후자는 사용자 친화적인 API 제공해서 HTTP 요청 보내는 과정을 더 단순화하고 다양한 기능 지원.
url = Request(df['URL'][0], headers={'User-Agent':'Mozilla/5.0'})
html = urlopen(url)
soup_tmp = BeautifulSoup(html, 'html.parser')
- 여기서
Request는 url을 받아서 Request 객체를 만드는 것.
header={'User-Agent':'Mozilla/5.0'} 부분은 헤더에 User-Agent 추가하는 것으로, 자신을 일반 웹브라우저 사용자로 가장해서 접근 제한 우회하는 방법. 이걸 빼면 웹사이트에서 요청 막힌다.
https://m.blog.naver.com/kiddwannabe/221185808375
urlopen은 URL 또는 Request 객체 받아서, 해당 리소스 열고 읽어서 => HTTP 응답을 나타내는 객체 (HTTP respnse객체)로
BeautifulSoup로 HTTP respnse 객체 받아서 BeautifulSoup 객체로 파싱. requests모듈을 썼으면 Response 객체. => 이게 html 문자열이다.
soup_tmp.select_one('.addy')
price_tmp = soup_tmp.select_one('.addy').text
temp = price_tmp.split()
price = price_tmp.split()[0][:-1]
address = ' '.join(temp[1:5])[:-2]
phone_number = temp[5][:-1]
- 정보 1개만 추출

price = []
address = []
for n in df.index[:3]:
url = Request(df['URL'][n], headers = {'User-Agent':'Mozilla/5.0'})
html = urlopen(url)
soup_tmp = BeautifulSoup(html, 'lxml')
gettings = soup_tmp.select_one('.addy').text
price.append(gettings.split()[0][:-1])
address.append(' '.join(gettings.split()[1:-2][:-1]))
- 'lxml'은 그냥 내장된 html.parser보다 더 빠른 파서
- 3개 for문으로 돌려보기 => 이상 없음 => 이제 50개 돌려보기

from tqdm import tqdm_notebook
price = []
address = []
for n in tqdm_notebook(df.index):
url = Request(df['URL'][n], headers = {'User-Agent':'Mozilla/5.0'})
html = urlopen(url)
soup_tmp = BeautifulSoup(html, 'lxml')
gettings = soup_tmp.select_one('.addy').text
price.append(gettings.split()[0][:-1])
address.append(' '.join(gettings.split()[1:-2]))
print(price)
print(len(price))
print()
print(address)
print(len(address))
- 50개 추출, 결과값 확인

df['Price'] = price
df['Address'] = address
df = df.loc[:, ['Rank', 'Cafe', 'Menu', 'Price', 'Address']]
df.set_index('Rank', inplace=True)
df.to_csv('../data/best_sandwiches_chicago22.csv', sep=',', encoding='UTF-8')

3-3 googlemaps에서 위도경도 뽑아와서 전처리
import folium
import pandas as pd
import googlemaps
import numpy as np
df['Address']
- 이상값 확인 => 'Multiple'이 주소에 있음

gmaps_key = "구글키"
gmaps = googlemaps.Client(key=gmaps_key)
gmaps_output = gmaps.geocode('2109 W. Chicago')
location_output = gmaps_output[0].get('geometry')
print(location_output['location']['lat'])
print(location_output['location']['lng'])

lat = []
lng = []
for n in tqdm_notebook(df.index):
if df['Address'][n] != 'Multiple' :
target_name = df['Address'][n] + '. ' + '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'])
else:
lat.append(np.nan)
lng.append(np.nan)
df['lat'] = lat; df['lng'] = lng
df.head()
- Multiple에 대해 예외처리를 해서, for문으로 모든 위도 경도 리스트로 만들기
- 그리고 결과를 DF에 집어넣기

3-4 folium으로 시각화
mapping = folium.Map(location=[df['lat'].mean(),
df['lng'].mean()],
zoom_start=11)
for n in df.index:
if df['Address'][n] != 'Multiple':
folium.Marker([df['lat'][n], df['lng'][n]],
popup = df['Cafe'][n]).add_to(mapping)
- 먼저 mapping할 때 평균을 쓰는 이유는, 그래야 대략적인 지도 위치가 잡히기 때문.
무작위로 하면 세계 지도가 잡히거나 전혀 중심이 안잡힐 수 있다. => 마커를 찍어도 안된다.