[0126] Web Data 수집/정리

이아연·2024년 1월 27일
0

03. Web Data - BeautifulSoup

1. BeautifulSoup for web data : 설치 및 코드 불러오기
2. 예제 1 - 네이버 금융
3. 예제 2 - 위키백과 문서 정보 가져오기
4. 예제 3.1 - 시카고 맛집 메인 페이지 분석
5. 예제 3.2 - 시카고 맛집 하위 페이지 분석
6. 예제 3.3 - 시카고 맛집 데이터 지도 시각화

1. BeautifulSoup for web data : 설치 및 코드 불러오기

BeautifulSoup Basic

  • install
    - conda install -c ananconda beautifulsoup4
    • pip install beatufiulsoup4

import

from urllib.request import urlopen
from bs4 import BeautifulSoup

페이지 읽기
page = open(path,'r').read()
soup = BeautifulSoup(page, 'html.parser') # html문법 규칙에 따라 문장 분석
print(soup.prettify())


출처 : Beautiful Soup Documentation

url = "https://finance.naver.com/marketindex/"
page = urlopen(url)
soup = BeautifulSoup(page, "html.parser")
print(soup.prettify)


response.status : 응답 상태를 숫자로 나타냄

url = "https://finance.naver.com/marketindex/"
response = urlopen(url)
response.status
#1xx (조건부 응답)
# 2xx (성공)
# 3xx (리다이렉션 완료)
# 4xx (요청 오류)
# 5xx (서버 오류)

2. 예제 1 - 네이버 금융

import requests
url = 'https://finance.naver.com/marketindex/'
response = requests.get(url)
response
# requests.get(), requests.post() 두 방식이 있음

soup = BeautifulSoup(response.text,'html.parser')
print(soup.prettify())

soup.find_all('li','on') <li class='on'>
soup.select('.class'|'#id') class는 .사용 id는 #사용

exchangeList = soup.select('#exchangeList > li') # class는 .사용 id는 #사용
len(exchangeList), exchangeList

제목, 환율, 변화, 상승/하락 출력

title = exchangeList[0].select_one('.h_lst').text
exchange = exchangeList[0].select_one('.value').text
change = exchangeList[0].select_one('.change').text
updown = exchangeList[0].select_one('div.head_info.point_up > .blind').text # 띄어쓰기 두 개의 속성 값으로 간주
# title 
# exchangeList
# change
# updown
title, exchange, change, updown

결과
('미국 USD', '1,337.50', '1.50', '상승')

미국, 일본, 유럽연합, 중국 4개 데이터 수집
1. 반복문 사용하여 각 아이템별 제목, 환율, 변화, 상승/하락 딕셔너리 형태로 저장.
2. exchange_datas 리스트에 추가
3. 데이터프레임 만들기

import pandas as pd
exchange_datas = []
baseUrl = 'http://finance.naver.com'

for item in exchangeList:
   data = {
       'title': item.select_one('.h_lst').text,
       'exchange': item.select_one('.value').text,
       'change': item.select_one('.change').text,
       'updown': item.select_one('.head_info > .blind').text, # 상승/ 하락 섞여있음. head_info만 입력
       'link' : baseUrl + item.select_one('a').get('href')

   }
   exchange_datas.append(data)
   print(data)
df =pd.DataFrame(exchange_datas) # 리스트 안의 딕셔너리 형태
df.to_excel('../source_code/naverfinance.xlsx')

3. 예제 2 - 위키백과 문서 정보 가져오기

 import urllib
from urllib.request import urlopen, Request
html = 'https://ko.wikipedia.org/wiki/{search_words}' # formatting

req = Request(html.format(search_words=urllib.parse.quote('여명의_눈동자'))) #글자를 URL로 인코딩
response = urlopen(req)
soup = BeautifulSoup(response, 'html.parser')
print(soup.prettify) 

반복문 사용하여 각 클래스 텍스트, 행 출력

n = 0
for each in soup.find_all('ul'):
  print('=>' + str(n) + '=====================')
  print(each.get_text())
  n += 1

35번째 ul 주요인물 텍스트
필요없는 코드 지우기

soup.find_all('ul')[35].text.strip().replace('\xa0','').replace('\n','')

결과
'채시라: 윤여옥 역 (아역: 김민정)박상원: 장하림(하리모토 나츠오) 역 (아역: 김태진)최재성: 최대치(사카이) 역 (아역: 장덕수)'

4. 예제 3.1 - 시카고 맛집 메인 페이지 분석

  • headers = {'User-Agent':ua.ie}
    or headers = {'User-Agent':'Chrome"}
from urllib.request import Request, urlopen
from fake_useragent import UserAgent
from bs4 import BeautifulSoup

url_base = 'https://www.chicagomag.com/'
url_sub = 'chicago-magazine/november-2012/best-sandwiches-chicago/'
url = url_base + url_sub
ua = UserAgent()

# {'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/121.0.0.0 Safari/537.36'}
req = Request(url, headers={'User-Agent': ua.ie})
response = urlopen(req)
response.status

html = urlopen(req)
soup = BeautifulSoup(html, "html.parser")
print(soup.prettify)

text 추출하기

import re

tmp_string = tmp_one.find(class_='sammyListing').get_text()
re.split(('\n|\r'), tmp_string) #결괏값은 리스트에 담겨 있다.
print(re.split(('\n|\r'), tmp_string)[0]) #메뉴 이름
print(re.split(('\n|\r'), tmp_string)[1])#카페 이름

결과
BLT
Old Oak Tap

순위, 메인메뉴, 카페이름, Url 리스트
반복문 사용하여 순위, 메인메뉴, 카페이름, Url 리스트에 추가
#필요한 내용을 담을 빈 리스트
#리스트로 하나씩 컬럼을 만들고, DataFrame으로 합칠 예정
urljoin(url_base,url_sub) : url합치기

from urllib.parse import urljoin

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').get_text()
    main_menu.append(re.split(('\n|\r'), tmp_string)[0])
    cafe_name.append(re.split(('\n|\r'), tmp_string)[1])
    url_add.append(urljoin(url_base,item.find('a')['href']))

DataFrame 합치기

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

5. 예제 3.2 - 시카고 맛집 하위 페이지 분석

순위 안의 리스트 하위 페이지 분석

import pandas as pd # import 먼저, 그 후 from절
from urllib.request import urlopen, Request
from fake_useragent import UserAgent
from bs4 import BeautifulSoup

데이터프레임URL컬럼 분석

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').text

가격, 주소, 번호 정보

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').text

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

price_tmp = soup_tmp.find('p','addy').text
price_tmp

.,를 기준으로 구분하기

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

결과
['\n$6.85. 3351 N. Broadwa', ' 773-868-400', ' phoebesbakery.com']

리스트의 0번째 값(가격, 주소 가져오기)

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

정규표현식
\d+ : 한 개 이상의 숫자
(\d+)? : 숫자 있을 수도 있고, 없을 수도 있음
.group()으로 묶기

주소(가격길이 +2부터 시작)

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

주소 : ' 3351 N. Broadwa'

반복문 사용하여 가격, 주소 리스트 담기
for문 사용
1. row값 사용

price=[]
address=[]

for idx, row in tqdm(df.iterrows()):
  req = Request(row["URL"], headers={'user-Agent':'chrome'})
  html = urlopen(req).read()
  soup_tmp = BeautifulSoup(html, 'html.parser')

  gettings = soup_tmp.find('p','addy').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)

2. df.index사용

price=[]
address=[]

for n in df.index[:]:
  req = Request(df["URL"][n], headers={'user-Agent':'chrome'})
  html = urlopen(req).read()
  soup_tmp = BeautifulSoup(html, 'html.parser')

  gettings = soup_tmp.find('p','addy').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(n)

DataFrame에 추가

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

6. 예제 3.3 - 시카고 맛집 데이터 지도 시각화

#Requirements

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

#read

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

#gmap

gmaps = googlemaps.Client(key=gmaps_key)
  • Multiple location 조건부 실행
    target_name 설정
    gmaps.geocode(target_name)
  • lat, lng값 구해서 리스트에 추가
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)

DataFrame에 추가

df['lat'] = lat
df['lng'] = lng
df.tail()

for문 사용하여 지도에 표시
folium.Marker(location=[위도,경도],popup=,tooltip=,icon=foliumIcon(icon=,prefix=)).add_to(mapping)

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

출처 : 제로베이스 데이터 취업 스쿨

여명의 눈동자 : https://ko.wikipedia.org/wiki/%EC%97%AC%EB%AA%85%EC%9D%98_%EB%88%88%EB%8F%99%EC%9E%90
시카고 맛집 :
https://www.chicagomag.com/chicago-magazine/november-2012/best-sandwiches-chicago/
네이버 금융 :
https://finance.naver.com/

profile
Hi Welcome

0개의 댓글