
주요 학습내용
1. 웹 스크래핑/웹 크롤링
2. 데이터 시각화
최종 목표
- 총 51개 페이지에서 각 가게의 정보를 가져온다
- 가게이름/대표메뉴/대표메뉴 가격/가게 주소
from urllib.request import Request, urlopen
from bs4 import BeautifulSoup
import pandas as pd
url_base = "https://www.chicagomag.com/"
url_sub = "chicago-magazine/november-2012/best-sandwiches-chicago/"
url = url_base + url_sub
response = urlopen(url)
response.status
이렇게 불러오면 아래와 같은 오류 코드 발생
![]()
- 웹 서버가 사용자의 요청을 인식하지만 추가적인 액세스를 허용할 수 없는 경우에 표시 됨
- 일반적으로 서버 측에서 충분한 권한이나 인증 자격 증명이 없는 경우에 발생
- 오류 해결 방법: headers = {} 입력
# 정식으로는
# req = Request(url, headers={"user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/123.0.0.0 Safari/537.36"})
req = Request(url, headers={"user-agent": "Chrome"})
response = urlopen(req)
response.status
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
ua = UserAgent()
req = Request(url, headers={"user-agent": ua.chrome})
response = urlopen(req)
response.status
from urllib.parse import urljoin
url_base = "https://www.chicagomag.com/"
# 필요한 내용을 담을 빈 리스트 생성
# 리스트로 하나씩 컬럼을 만들고, DataFrame으로 합칠 예정
rank = []
main_menu = []
cafe_name = []
url_add =[]
list_soup = soup.find_all("div", "sammy") # soup.select(".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]) # 인덱스 0:메뉴
cafe_name.append(re.split(("\n|\r\n"), tmp_string)[1]) # 인덱스 1:카페이름
url_add.append(urljoin(url_base, item.find("a")["href"]))
# 모두 잘 가져와졌는지 check
len(rank), len(main_menu), len(cafe_name), len(url_add)
rank[:5], main_menu[:5], cafe_name[:5], url_add[:5]
import pandas as pd
data = {
"Rank": rank,
"Menu": main_menu,
"Cafe": cafe_name,
"URL": url_add
}
df = pd.DataFrame(data)
# 컬럼 순서 변경
df = pd.DataFrame(data, columns = ["Rank", "Cafe", "Menu", "URL"])
df
# requirement
import pandas as pd
from urllib.request import urlopen, Request
from fake_useragent import UserAgent
from bs4 import BeautifulSoup
# 문법상 IMPORT문 가장 최상단에 쓰고, from문 쓰는것이 좋음
# 인덱스 하나 지정하여, 추출하고자하는 데이터 위치 파악
df["URL"][0]
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")
# soup_tmp.select_one(".addy")
# regular expression(정규화)
price_tmp = soup_tmp.find("p", "addy").text
price_tmp
import re
re.split(".,", price_tmp)
# 재분리
price_tmp = re.split(".,", price_tmp)[0]
# 가격
tmp = re.search("\$\d+\.(\d+)?",price_tmp).group()
# 달러 + 숫자 + 그뒤로는 숫자가 올수도 있고 안올수도 있다
# 주소
price_tmp[len(tmp)+2:]
# 전체
from tqdm import tqdm
price = []
address = []
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:])
print(idx)
len(price), len(address)
price[:5], address[:5]
df["Price"] = price
df["Address"] = address
df = df.loc[:, ["Rank", "Cafe", "Menu", "Price", "Address"]]
df.set_index("Rank", inplace=True)
df.to_csv("../data/03. best_sandwiches_list_chicago2.csv",sep=",", encoding = "UTF-8")
pd.read_csv("../data/03. best_sandwiches_list_chicago2.csv", index_col=0)
# requirements
import folium
import pandas as pd
import numpy as np
import googlemaps
from tqdm import tqdm
gmaps_key = "개인별 키값 입력"
gmaps = googlemaps.Client(key=gmaps_key)
lat = []
lng = []
for idx, row in tqdm(df.iterrows()):
if not row["Address"] == "Multiple location":
target_name = row["Address"] + ", " + "Chicago"
# print(target_name)
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.tail()
mapping= folium.Map(
location=[41.8781136, -87.6297982],
zoom_start = 11
)
mapping
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