◼import
import pandas as pd
import numpy as np
import re
import folium
import googlemaps
from bs4 import BeautifulSoup
from urllib.request import urlopen, Request
from urllib.parse import urljoin
from tqdm import tqdm
◼개요
- 시카고 최고의 샌드위치 50 기사 : 링크
- 식당명, 메뉴명, 가격,주소, 위치 추출
- 지도에 각 식당 시각화
◼메인 페이지 분석
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
req = Request(url, headers={'User-Agent' : "Chrome"})
html = urlopen(req).read()
soup = BeautifulSoup(html, "html.parser")
print(soup.prettify())

- 구글 크롬 개발자 도구를 활용해 순위 부분의 태그 및 속성 확인
- 태그
div
, 클래스 sammmy
확인

- find_all 명령 사용 (또는 selcet 명령 사용)
print(len(soup.find_all("div", class_="sammy")))
print(soup.find_all("div", class_="sammy"))

tmp_one = soup.find_all("div", class_="sammy")[0]
print(tmp_one.find(class_="sammyRank").get_text())
print(tmp_one.find(class_="sammyListing").get_text())

- re 모듈의 split으로 메뉴, 가게명 분리
tmp_string = tmp_one.find(class_="sammyListing").get_text()
print(re.split('\n|\r\n', tmp_string))
print(re.split('\n|\r\n', tmp_string)[0])
print(re.split('\n|\r\n', tmp_string)[1])

- 링크 주소 확보 : ("a").get("href")
print(tmp_one.find('a').get("href"))

rank = []
main_menu = []
cafe_name = []
url_add = []
list_soup = soup.find_all("div", class_="sammy")
for item in list_soup:
rank.append(item.find(class_="sammyRank").get_text())
tmp_string = item.find(class_="sammyListing").get_text()
main_menu.append(re.split('\n|\r\n', tmp_string)[0])
cafe_name.append(re.split('\n|\r\n', tmp_string)[1])
url_add.append(urljoin(url_base, item.find('a').get('href')))
data = {"Rank" : rank, "Menu" : main_menu, "Cafe" : cafe_name, "URL" : url_add}
df = pd.DataFrame(data, columns=["Rank", "Cafe", "Menu", "URL"])
df = pd.DataFrame(data)
df.head(2)

df.to_csv(
"../data/03/03. best_sandwiches_list_chicago.csv", sep=",", encoding="UTF-8"
)
◼하위 페이비 분석
df = pd.read_csv('../data/03/03. best_sandwiches_list_chicago.csv', index_col = 0)
df.head(2)

- 구글 크롬 개발자 도구를 활용해 순위 부분의 태그 및 속성 확인

req = Request(df.get("URL")[0], headers={'User-Agent' : 'Chrome'})
html = urlopen(req)
soup_tmp = BeautifulSoup(html, "html.parser")
print(soup_tmp.prettify())

soup_tmp.find('p', class_='addy').get_text()

정규식(Regular Expression)
- .x : 임의의 한 문자(x가 마지막으로 끝난다)
- x+ : x가 1번이상 반복한다.
- x? : x가 존재하거나 존재하지 않는다.
- x* : x가 0번이상 반복한다.
- x|y : x 또는 y를 찾는다.(or 연산자와 동일하다.)
price_tmp = soup_tmp.find("p", "addy").get_text()
price_tmp = re.split('.,', price_tmp)[0]
price_tmp

- 텍스트 구성 : $숫자.(숫자) 주소
- 가격이 끝나는 지점의 위치를 이용해 주소 시작 지점을 찾을 수 있다.
tmp = re.search("\$\d+\.(\d+)?", price_tmp).group()
price_tmp[len(tmp) + 2:]
print(tmp)
print(price_tmp[len(tmp) + 2:])

from tqdm import tqdm
price = []
address = []
for idx, row in tqdm(df.iterrows()):
req = Request(row.get("URL"), headers={'User-Agent' : 'Mozilla/5.0'})
html = urlopen(req)
soup_tmp = BeautifulSoup(html, "lxml")
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 : ])
len(price), len(address)

df["Price"] = price
df["Address"] = address
df = df.loc[:, ["Rank", "Cafe", "Menu", "Price", "Address"]]
df.set_index("Rank", inplace=True)
df.head()

df.to_csv(
"../data/03/03. best_sandwiches_list_chicago2.csv", sep=',', encoding="UTF-8"
)
◼지도 시각화
df = pd.read_csv("../data/03. best_sandwiches_list_chicago2.csv", index_col=0)
df.head(2)

gmaps_key = '개인키'
gmaps = googlemaps.Client(key=gmaps_key)
lat = []
lng = []
for idx, row in tqdm(df.iterrows()):
if not row.get("Address") == "Multiple location":
target_name = row.get("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"])
else:
lat.append(np.nan)
lng.append(np.nan)

df["lat"] = lat
df["lng"] = lng
df.head(2)

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(
[row.get('lat'), row.get('lng')],
popup=row.get("Cafe"),
tooltip=row.get('Menu'),
icon=folium.Icon(
icon='coffee',
prefix="fa",
icon_color = 'black',
color = 'orange'
)
).add_to(mapping)
mapping
