티스토리 뷰

시카고 샌드위치 맛집 분석 - 복사본 (2)

제 3장 시카고 샌드위치 맛집 분석

구성 및 블로그 진행 과정

3-1 웹데이터를 가져오는 Beautiful Soup 익히기
3-2 크롬 개발자 도구를 이용해서 원하는 태그 찾기
3-3 실전: 시카고 샌드위치 맛집 소개 사이트에 접근하기
3-4 접근한 웹 페이지에서 원하는 데이터 추출하고 정리하기
-------------------------------------------------------
3-5 다수의 웹 페이지에 자동으로 접근해서 원하는 정보 가져오기
3-6 Jupyter Notebook에서 상태 진행바를 쉽게 만들어주는 tqdm 모듈
3-7 상태 진행바까지 적용하고 다시 샌드위치 페이지 50개에 접근하기
3-8 50개 웹 페이지에 대한 정보 가져오기
3-9 맛집 위치를 지도에 표기하기
-------------------------------------------------------
3-10 네이버 영화 평점 기준 영화의 평점 변화 확인하기
3-11 영화별 날짜 변화에 따른 평점 변화 확인하기

출처: 파이썬으로 데이터 주무르기 by 민형기


3-5 다수의 웹 페이지에 자동으로 접근해서 원하는 정보 가져오기

3-3절 까지 시카고 매거진에서 시카고의 베스트 샌드위치 가게 50개에 대한 정보를 가져오는 페이지를 만들었다. html 페이지로는 하나여서 페이지 간 이동은 필요가 없었다. 그저 한 페이지의 내용을 잘 이해하고 가져오면 되는데, 앞에서 이야기한 대로 세부 메뉴를 설명하는 곳을 클릭하면 각각의 또 다른 매거진 기사로 연결된다. 이 기사의 아래쪽을 보면 해당 상품의 가격과 가게 주소, 전화번호를 확인할 수 있다.

In [82]:
Image.open('crawling3.png')
Out[82]:
In [76]:
# 모듈 import
from bs4 import BeautifulSoup
from urllib.request import urlopen

import pandas as pd
In [77]:
# 3-3절에서 저장했던 파일을 불러오자.
df = pd.read_csv('pydata/03. best_sandwiches_list_chicago.csv', index_col=0)
df.head()
Out[77]:
Rank Cafe Menu URL
0 1 Old Oak Tap BLT https://www.chicagomag.com/Chicago-Magazine/No...
1 2 Au Cheval Fried Bologna https://www.chicagomag.com/Chicago-Magazine/No...
2 3 Xoco Woodland Mushroom https://www.chicagomag.com/Chicago-Magazine/No...
3 4 Al’s Deli Roast Beef https://www.chicagomag.com/Chicago-Magazine/No...
4 5 Publican Quality Meats PB&L https://www.chicagomag.com/Chicago-Magazine/No...

위 표에서 URL 컬럼에 있는 내용을 50개 읽어서 각 페이지에서 가게 주소, 대표 샌드위치 가격, 가게 전화번호를 얻어보자. 그러면 첫 번째 URL 정보를 확인하고 연습 삼아 진행한 다음 50개에 대해 반복문을 적용하겠다.

In [78]:
# 첫 번째 URL
df['URL'][0]
Out[78]:
'https://www.chicagomag.com/Chicago-Magazine/November-2012/Best-Sandwiches-in-Chicago-Old-Oak-Tap-BLT/'
In [80]:
# 첫 번째 주소를 Beautiful Soup로 읽는다. 내용이 많아~
html = urlopen(df['URL'][0])
soup_tmp = BeautifulSoup(html, 'html.parser')
#soup_tmp
In [81]:
# 위 그림에서 확인했던 태그를 이용해서 원하는 부분을 찾자
print(soup_tmp.find('p','addy'))
<p class="addy">
<em>$10. 2109 W. Chicago Ave., 773-772-0406, <a href="http://www.theoldoaktap.com/">theoldoaktap.com</a></em></p>
In [83]:
# 텍스트로 가져오자
price_tmp = soup_tmp.find('p', 'addy').get_text()
price_tmp
Out[83]:
'\n$10. 2109 W. Chicago Ave., 773-772-0406, theoldoaktap.com'
In [84]:
# 빈칸으로 나누자
price_tmp.split()
Out[84]:
['$10.', '2109', 'W.', 'Chicago', 'Ave.,', '773-772-0406,', 'theoldoaktap.com']

우리는 위 결과를 보면 제일 첫 번째 자리에는 가격이, 맨 뒤에는 웹주소, 그 앞에는 전화번호라는 것을 확인 할 수 있다.

In [85]:
# 가격정보
price_tmp.split()[0]
Out[85]:
'$10.'
In [86]:
# 뒤에 붙어있는 점이 보기 싫기 때문에 다음과 같이 표현하자
price_tmp.split()[0][:-1]
Out[86]:
'$10'
In [87]:
# 두 번째부터 마지막에서 세 번째까지가 주소이다. 
' '.join(price_tmp.split()[1:-2])
Out[87]:
'2109 W. Chicago Ave.,'
In [88]:
# 페이지가 50개라 많지는 않지만 페이지가 열리는 시간이 좀 있어서 반복문을 이용하여 3개([:3])만 돌려보자.
price = []
address = []

for n in df.index[:3]:
    html = urlopen(df['URL'][n])
    soup_tmp = BeautifulSoup(html, 'lxml')
    
    gettings = soup_tmp.find('p', 'addy').get_text()
    
    price.append(gettings.split()[0][:-1])
    address.append(' '.join(gettings.split()[1:-2]))
In [89]:
# 가격은 잘 나왔니~
price
Out[89]:
['$10', '$9', '$9.50']
In [90]:
# 주소는 잘 나왔니
address
Out[90]:
['2109 W. Chicago Ave.,', '800 W. Randolph St.,', '445 N. Clark St.,']

시간이 너무 오래걸릴 경우 동작이 되는건지 멈춘건지 확인이 되지 않아 답답할때가 있다. 그래서 흔히 반복문 안에 print(n)을 넣어서 어디쯤 진행되고 있는지 확인하곤 한다.

3-6 Jupyter Notebook에서 상태 진행바를 쉽게 만들어주는 tqdm 모듈

tqdm의 github 페이지:
https://github.com/tqdm/tqdm

conda install -c conda-forge tqdm 으로 터미널에서 설치

3-7 상태 진행바까지 적용하고 다시 샌드위치 페이지 50개에 접근하기

In [91]:
from tqdm import tqdm_notebook

price = []
address = []

for n in tqdm_notebook(df.index):
    html = urlopen(df['URL'][n])
    soup_tmp = BeautifulSoup(html, 'lxml')
    
    gettings = soup_tmp.find('p', 'addy').get_text()
    
    price.append(gettings.split()[0][:-1])
    address.append(' '.join(gettings.split()[1:-2]))

3-8 50개 웹 페이지에 대한 정보 가져오기

In [95]:
# 가격은 잘 들어갔니
price[:10]
Out[95]:
['$10', '$9', '$9.50', '$9.40', '$10', '$7.25', '$16', '$10', '$9', '$17']
In [96]:
# 주소는 잘 들어갔니
address[:10]
Out[96]:
['2109 W. Chicago Ave.,',
 '800 W. Randolph St.,',
 '445 N. Clark St.,',
 '914 Noyes St., Evanston,',
 '825 W. Fulton Mkt.,',
 '100 E. Walton',
 '1639 S. Wabash Ave.,',
 '2211 W. North Ave.,',
 '3619 W. North Ave.,',
 '3267 S. Halsted St.,']
In [94]:
len(price), len(address), len(df)
Out[94]:
(50, 50, 50)
In [97]:
# 랭크는 index로 만든다.
df['Price'] = price
df['Address'] = address

df = df.loc[:, ['Rank', 'Cafe', 'Menu', 'Price', 'Address']]
df.set_index('Rank', inplace=True)
df.head()
Out[97]:
Cafe Menu Price Address
Rank
1 Old Oak Tap BLT $10 2109 W. Chicago Ave.,
2 Au Cheval Fried Bologna $9 800 W. Randolph St.,
3 Xoco Woodland Mushroom $9.50 445 N. Clark St.,
4 Al’s Deli Roast Beef $9.40 914 Noyes St., Evanston,
5 Publican Quality Meats PB&L $10 825 W. Fulton Mkt.,
In [98]:
df.to_csv('pydata/03. best_sandwiches_list_chicago2.csv', sep=',',
         encoding='UTF-8')

3-9 맛집 위치를 지도에 표기하기

3장의 메인 주제는 3-7에서 끝났지만 추가로 지도에 각 맛집을 추가하는 내용을 이야기해보자.

In [99]:
# 모듈 import
import folium
import pandas as pd
import googlemaps
import numpy as np
In [100]:
df = pd.read_csv('pydata/03. best_sandwiches_list_chicago2.csv', index_col=0)
df.head()
Out[100]:
Cafe Menu Price Address
Rank
1 Old Oak Tap BLT $10 2109 W. Chicago Ave.,
2 Au Cheval Fried Bologna $9 800 W. Randolph St.,
3 Xoco Woodland Mushroom $9.50 445 N. Clark St.,
4 Al’s Deli Roast Beef $9.40 914 Noyes St., Evanston,
5 Publican Quality Meats PB&L $10 825 W. Fulton Mkt.,
In [102]:
# googlemaps를 키를 이용해서 읽어오자.
# googlemap 키를 입력
gmaps_key = '*****************************'
gmaps = googlemaps.Client(key=gmaps_key)
In [105]:
# 50개 맛집의 위도, 경도 정보를 받아오자.
# Multiple이 나타나지 않는 경우만 주소를 검색
lat = []
lng = []

for n in tqdm_notebook(df.index):
    if df['Address'][n] != 'Multiple':
        target_name = df['Address'][n]+', '+'Cicago'
        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)

In [112]:
df['lat'] = lat
df['lng'] = lng
df.head()
Out[112]:
Cafe Menu Price Address lat lng
Rank
1 Old Oak Tap BLT $10 2109 W. Chicago Ave., 41.895605 -87.679961
2 Au Cheval Fried Bologna $9 800 W. Randolph St., 41.884658 -87.647667
3 Xoco Woodland Mushroom $9.50 445 N. Clark St., 41.890618 -87.630933
4 Al’s Deli Roast Beef $9.40 914 Noyes St., Evanston, 42.058322 -87.683748
5 Publican Quality Meats PB&L $10 825 W. Fulton Mkt., 41.886600 -87.648451
In [113]:
# 50개의 맛집의 위도, 경도의 평균값을 중앙에 둔다.
mapping = folium.Map(location=[df['lat'].mean(), df['lng'].mean()],
                    zoom_start=11)
folium.Marker([df['lat'].mean(), df['lng'].mean()],
             popup='center').add_to(mapping)
mapping
Out[113]:
In [114]:
# 50개의 맛집의 위도, 경도를 지도에 표기
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
Out[114]:

Beautiful Soup라는 라이브러리를 이용해서 인터넷의 정보를 가져오는 작업을 수행했다.
단순히 한 페이지만 읽는 것이 아니라 메인 페이지에 연결된 다른 페이지들도 모두 대상으로 한다.

공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2024/05   »
1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 31
글 보관함