관리 메뉴

log.Sehee

[데이터 취업 스쿨 스터디 노트] 시카고 맛집 웹데이터 분석 및 시각화 / 웹데이터분석 3 - 5 본문

Zerobase DS School

[데이터 취업 스쿨 스터디 노트] 시카고 맛집 웹데이터 분석 및 시각화 / 웹데이터분석 3 - 5

Sehe_e 2024. 8. 6. 18:35

 


 

시카고 맛집 데이터 분석 - 메인페이지

 

구글에 'chicago magazine the 50 best sandwiches' 검색하여 상단 웹페이지 링크 사용

총 51개 페이지에서 각 가게의 정보를 가져오기

 

fake-useragent 설치

pip install fake-useragent

 

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

# UserAgent() : UserAgent를 랜덤으로 생성해준다.
ua = UserAgent()

# 403 Forbidden 상태코드. 접근 권한이 없을 때 뜬다. / header를 추가해야한다.
req = Request(url, headers={'User-Agent': ua.chrome})
html = urlopen(req)
soup = BeautifulSoup(html, 'html.parser')
print(soup.prettify())

 

! headers에 넣어야 하는 User-Agent 위치 (개발자도구 > 네트워크 > 상단의 GET 정보 최하단에 있다.)

 

내가 필요한 정보 확인 후 태그와 class or id 특정하기

# find_all
soup.find_all('div', 'sammy'), len(soup.find_all('div', 'sammy'))

# select
# soup.select('.sammy'), len(soup.select('.sammy'))

생략

 

0번 인덱스로 조회

tmp_one = soup.find_all('div', 'sammy')[0]
tmp_one

 

메뉴와 가게 이름이 있는 태그의 text 가져오기

import re


tmp_string = tmp_one.find(class_='sammyListing').get_text()
# 'BLT\nOld Oak Tap\nRead more '

# \n or \r\n 기준으로 split
re.split(('\n|\r\n'), tmp_string)

 

column으로 사용할 리스트를 만든다.

from urllib.parse import urljoin

# 필요한 내용을 담을 빈 리스트
# 리스트로 하나씩 컬럼을 만들고, DataFrame으로 합칠 예정

rank = []
main_meau = []
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_meau.append(re.split(('\n|\r\n'), tmp_string)[0])
    cafe_name.append(re.split(('\n|\r\n'), tmp_string)[1])
    
    # urljoin : href 태그에서 바로 가져온 링크는 상대 주소
    # urljoin을 사용하면 baseUrl + href 형식으로 절대 주소로 만들 수 있다.
    url_add.append(urljoin(url_base, item.find('a')['href']))

 

갯수가 맞는지 확인

len(rank), len(main_meau), len(cafe_name), len(url_add)

 

DataFrame으로 만들기

import pandas as pd

data = {
    'Rank': rank,
    'Menu': main_meau,
    'Cafe': cafe_name,
    'URL': url_add
}

df = pd.DataFrame(data)
df.tail(2)

 

컬럼 순서 변경

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

 

저장

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

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

 

DataFrame에 저장된 URL 정보를 사용하여 하위페이지의 정보 가져오기

ua = UserAgent()
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')

 

텍스트 다듬기

import re
price_tmp = re.split('.,', price_tmp)[0]
price_tmp

 

정규표현식 사용하여 가격, 주소 분리하기

# 정규표현식 사용
# \$ : $ 기호 찾기
# \d+ : 하나 이상의 숫자
# \. : 소수점
# (\d+) : 소수점 뒤 하나 이상의 숫자가 있을 수 있음
# ? : 선택적 옵션
# 특수문자는 앞에 백슬래시 \ 를 붙여 이스케이프 처리해야한다.

tmp = re.search('\$\d+\.(\d+)?', price_tmp).group()    # $10.
price_tmp[len(tmp) + 2:]    # '2109 W. Chicago Ave'

 

tqdm 설치

pip install tqdm

 

column으로 사용할 리스트 만들기

from tqdm import tqdm

price = []
address = []

# tqdm : 코드 진행 상태를 시각적으로 표현해준다
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:])

 

DataFrame에 가격, 주소 정보 추가

df['Price'] = price
df['Address'] = address

 

column 순서 변경 및 인덱스 변경

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

 

저장

df.to_csv(
    '../data/03. best_sandwiches_list_chicago2.csv', sep=',', encoding='utf-8'
)

 

 


 

시카고 맛집 데이터 지도 시각화

 

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

gmaps_key = 발급받은 API key
gmaps = googlemaps.Client(key=gmaps_key)

df = pd.read_csv('../data/03. best_sandwiches_list_chicago2.csv', index_col = 0)
df.tail()

 

위도, 경도 정보 가져오기

lat = []
lng = []

for idx, row in tqdm(df.iterrows()):
	# 주소가 여러 개가 아닐 때 실행
    if not row['Address'] == 'Multiple location':
        target_name = row['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'])
    # 주소가 여러 개라면 null값 추가
    else:
        lat.append(np.nan)
        lng.append(np.nan)

 

DataFrame에 위치정보 추가

df['lat'] = lat
df['lng'] = lng

df.tail()

 

folium으로 지도 표시

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

 

 


내일의 학습 목표

유가분석 1 - 3

 

 

 

Comments