Search

Second PJ - Chicago Best Sandwiches Crawling

1. 필요한 라이브러리, 모듈 임포트

# 필요한 라이브러리, 모듈 import import urllib.request import Request, urlopen from bs4 import BeautifulSoup from fake_useragent import UserAgent
Python
복사
 403 error
특정 페이지에서 일반적으로 urlopen(url) 을 하게 되면 위의 403 error 를 발생시키는 경우가 있다.
이 해결 방법으로 아래와 같은 Request(), useragent 작업을 해줘야 한다.

2. 문제 없이 페이지 크롤링해오기 - Request(), 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.ie}) html = urlopen(req) # 상태를 확인해보면 200 으로 정상적으로 요청하고 받은 것으로 확인할 수 있다.-> html.status soup = BeautifulSoup(html, 'html.parser') print(soup.prettify()) # 제대로 불러와진 html 확인
Python
복사

3. 원하는 부분 가져오기

from urllib.parse import urljoin # 하위 페이지에 url_base가 제대로 붙여져 있으면 그대로 가져오고, 없다면 붙여서 url_add 에 넣어주기 위해 필요한 모듈 import re # 정규표현식 모듈 가져오기 url_base = 'https://www.chicagomag.com/' # 필요한 내용을 담을 빈 리스트 # 리스트로 하나의 칼럼을 만들고, 추후 데이터프레임으로 합칠 에정 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').text) # 순위 tmp_string = item.find(class_='sammyListing').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'])) # 링크
Python
복사
 re.split((”\n | \r\n”))
‘\n’ 이나 ‘\r\n’ 을 기준으로 문자들을 모두 분리해준다.
 urljoin(url_base, item.find(’a’)[’href’])
url_base 가 item.find(’a’)[’href’] 에 포함되어 있으면 그대로 가져오고, 없다면 url_base 를 붙여주는 기능

4. 원하는 부분 추출한 데이터 → 데이터프레임 형태로 만들어주기

# 만들어진 리스트를 데이터프레임으로 만들어주기 import pandas as pd data = { 'Rank': rank, 'Main Menu' : main_menu, 'Cafe Name' : cafe_name, 'URL' : url_add } df = pd.DataFrame(data) # 만든 데이터프레임 csv 파일로 저장하기 df.to_csv('../data/03. best_sandwiches_list_chicago.csv', sep=',', encoding='utf-8')
Python
복사

5. 하위 페이지 데이터 가져오기 - price, address

# 위의 저장한 df 다시 가져오기 df = pd.read_csv('../data/03. best_sandwiches_list_chicago.csv', index_col=0)
Python
복사
# 하위 페이지 소스 가져오기 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) soup_tmp = BeautifulSoup(html, 'html.parser') # 크롤링해오기 gettings = soup_tmp.find('p','addy').text price_address = re.split('.,', gettings)[0] tmp = re.search("\$\d+\.(\d+)?", price_address).group() # 정규표현식으로 원하는 데이터만 추출하기 price.append(tmp) address.append(price_address[len(tmp) + 2:]) print(idx)
Python
복사
 tqdm
반복문을 돌리는 경우, 진행 상황이나 시간이 얼마나 걸리는지 등의 정보를 확인할 수 있는 모듈이다.
 re.search(”정규표현식”, 적용하고자하는문자형태).group()
“” 안에 넣어준 정규표현식을 충족하는 문자만 찾아준다. group() 을 넣어줘야 원하는 값을 출력할 수 있다.
ex) \$\d+\.(\d+)? 가 의미하는 것
\$ : 달러가 포함되어야 하고,
\d+ : 숫자가 포함되어야 하는데, 그 크기는 상관이 없고
\. : ‘ . ’ 을 포함해야 한다.
( )? : ( ) 안에 있는 내용은 포함되어도 되고, 포함되지 않아도 된다.

6. 데이터프레임으로 합쳐주고 다시 저장해주기

# 위의 가격 정보와 주소 정보를 리스트에 담았으니 # 기존 데이터프레임에 변수로 더해주자. df['Price'] = price df['Address'] = address # 필요없는 url 필드는 빼고 저장 df = df.iloc[:,[0,1,2,4,5]] # Rank 필드를 index 로 설정 df.set_index('Rank', inplace=True) # csv 파일로 다시 저장 df.to_csv('../data/03. best_sandiwiches_list_chicago2.csv', sep=',', encoding='utf-8')
Python
복사

7. 지도에 샌드위치 맛집 50군데 위치 표시하기

# 필요한 라이브러리, 모듈 임포트 import folium import numpy as np import googlemaps
Python
복사
# 시카고 맛집 데이터 다시 불러오기 df = pd.read_csv('../data/03. best_sandiwiches_list_chicago2.csv', index_col=0)
Python
복사
주소 필드 활용해서 위도, 경도 데이터를 가져오기
gmaps_key = 'AIzaSyD8GhzmjZ2g4p4ZOWv8zMBEG7IoruaGIoc' gmaps = googlemaps.Client(gmaps_key)
Python
복사
lat = [] # 위도 정보 담을 리스트 lng = [] # 경도 정보 담을 리스트 for idx, row in tqdm(df.iterrows()): # Address 주소가 여러개일 경우, 'Multiple location' 으로 되어 있다. -> 빼주고 진행 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']) # 경도 정보 else: lat.append(np.nan) lng.append(np.nan)
Python
복사
# 기존 데이터프레임에 위도, 경도 필드로 더해주자 df['lat'] = lat df['lng'] = lng
Python
복사
# 지도에 마커 표시하기 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 Name'], tooltip=row['Main Menu'], icon = folium.Icon( icon='coffee', prefix='fa' ) ).add_to(mapping)
Python
복사