프로젝트 3 - 시카고 맛집 데이터 분석

Jungmin·2022년 10월 19일
1

데이터 분석

목록 보기
11/24

시카고 맛집 데이터 분석 - 개요

최종 목표
총 51개 페이지에서 각 가게의 정보를 가져온다.

  • 가게 이름
  • 대표메뉴
  • 대표메뉴의 가격
  • 가게 주소

메인페이지

- 페이지 요청
-url_base = 'https://www.chicagomag.com'
-url_sub = '/Chicago-Magazine/November-2012/Best-Sandwiches-Chicago/'

  • 관리를 위해 base와 sub로 분리
  • html = urlopen(url) : Error 403 서버에서 접근 차단(자동 봇 차단)
  • 크롬 개발자 도구 -> Network 상세 내용 확인
  • User-Agent 생성--> ua = UserAgent() --> ua.ie
    --> req = Request(url, headers={'User-Agent' : ua.ie})
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
ua = UserAgent()

# req = Request(url, headers={"User-Agent":"Chrome"})
# response = urlopen(req)
# response

#!pip install fake-useragent
req = Request(url, headers={"User-Agent":"ua.ie"})
html = urlopen(req)
soup = BeautifulSoup(html, "html.parser")
print(soup.prettify())

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

soup.find_all("div", "sammy"), len(soup.find_all("div", "sammy"))
# soup.select(".sammy"), len(soup.select(".sammy"))
tmp_one = soup.find_all('div', "sammy")[0]
tmp_one

tmp_one.find(class_='sammyRank').get_text()
# tmp_one.select_one(".sammyRank").text 와 동일

--> '1'

tmp_one.find("div",{"class":"sammyListing"}).text
# tmp_one.find("div",{"class":"sammyListing"}).get_text() 와 동일
# tmp_one.select_one(".sammyListing").text 와 동일

--> 'BLT\nOld Oak Tap\nRead more '

tmp_one.select_one("a").get("href")
# tmp_one.find("a")["href"] 와 동일

--> '/Chicago-Magazine/November-2012/Best-Sandwiches-in-Chicago-Old-Oak-Tap-BLT/'

re 모듈의 split으로 메뉴, 가게명 분리

import re

tmp_string = tmp_one.find(class_="sammyListing").get_text()
re.split(("\n|\r\n"), tmp_string)

--> ['BLT', 'Old Oak Tap', 'Read more ']

print(re.split(('\n|\r\n'), tmp_string)[0])

--> BLT

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")

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")["href"]))
import pandas as pd

data = {
    "Rank":rank,
    "Menu":main_menu,
    "Cafe": cafe_name,
    "URL": url_add
}
df = pd.DataFrame(data)
df.tail()

#컬럼 순서 변경
df = pd.DataFrame(data, columns=["Rank", "Cafe", "Menu", "URL"])
df.tail()

#저장
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 bs4 import BeautifulSoup   
from fake_useragent import UserAgent

df = pd.read_csv("../data/03.best_sandwiches_list_chicago.csv", index_col=0)
df.tail()

# 순위 1위 메뉴의 주소 
df["URL"][0]

--> 'https://www.chicagomag.com/Chicago-Magazine/November-2012/Best-Sandwiches-in-Chicago-Old-Oak-Tap-BLT/'

req = Request(df["URL"][0], headers={"user-agent":ua.ie})
html = urlopen(req).read()
soup_tmp = BeautifulSoup(html, "html.parser")
soup_tmp.find("p","addy") # 아니면 soup_find.select_one(".addy")


가격과 주소-->한 줄로 이루어진 것을 확인

# regular expression
price_tmp = soup_tmp.find("p","addy").text
price_tmp

--> '\n$10. 2109 W. Chicago Ave., 773-772-0406, theoldoaktap.com'

regular expression

import re
re.split(".,", price_tmp)

--> ['\n$10. 2109 W. Chicago Ave', ' 773-772-040', ' theoldoaktap.com']

price_tmp = re.split(".,", price_tmp)[0]
price_tmp

--> '\n$10. 2109 W. Chicago Ave'

tmp = re.search("\$\d+\.(\d+)?", price_tmp).group()
price_tmp[len(tmp) +2:]

--> '2109 W. Chicago Ave'

from tqdm import tqdm

price = []
address = []
for idx, row in tqdm(df.iterrows()):
    req = Request(row["URL"], headers={"user-agent":ua.ie})
    html = urlopen(req).read()
    soup_tmp = BeautifulSoup(html, "html.parser")
    
    getthings = soup_tmp.find("p","addy").get_text()
    price_tmp = re.split(".,", getthings)[0]
    tmp = re.search("\$\d+\.(\d+)?", price_tmp).group()
    price.append(tmp)
    address.append(price_tmp[len(tmp)+2:])

--> 50it [01:04, 1.29s/it] 데이터 작동 확인

df.tail(2)

df["Price"] = price
df["Address"] = address
df = df.loc[:,["Rank", "Cafe","Menu", "Price", "Address"]]  #전체 행에 대해서 링크 제외하고 컬럼 설정
df.set_index("Rank", inplace=True)  #인덱스 값을 Rank로 설정해주기 
df.head()

# 저장
df.to_csv(
    "../data/03. best_sandwiches_list_Chicago2.csv", sep=",", encoding="utf-8"
)

지도 시각화

# requirements

import folium
import pandas as pd
import numpy as np
import googlemaps
from tqdm import tqdm

df = pd.read_csv("../data/03. best_sandwiches_list_Chicago2.csv", index_col=0)
df.tail(10)

gmaps_key = "AIzaSyCB3zeKUulnVUj_yDjKqaqoqVsF0MGvx_o"
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]
        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(2)

# 마커 추가해주기 
from msilib.schema import Icon


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

profile
데이터분석 스터디노트🧐✍️

0개의 댓글