1. 이번에는 위키백과의 문서를 가져와보자. 작성자가 좋아하는 보더콜리에 대한 정보를 가져와볼 것이다.
https://ko.wikipedia.org/wiki/%EB%B3%B4%EB%8D%94_%EC%BD%9C%EB%A6%AC\
보더 콜리 - 위키백과, 우리 모두의 백과사전
위키백과, 우리 모두의 백과사전.
ko.wikipedia.org
2. 위의 url에 들어가보면, url 뒤의 wiki/~~~ 부분이 %EB%B3%...이 아니라 '보더_콜리'임을 알 수 있다. 위키피디아의 경우 url 인코딩이 utf-8이기 때문에 저런 한글 글자들을 잘 불러온다. 그러나 다른 대부분의 페이지에서는 utf-8인코딩을 사용하지 않는다. 따라서 저렇게 풀어서 url을 작성하는데, 문제는 저렇게 html제목을 직접 url에 get형식으로 받아오는 경우 글자수 제한이 발생하기도 한다는 것이다.(특히 한글이 길 경우)
3. bs4에서 코드를 짤 때는 이런 인코딩 문제를 대비하여 url에 직접 들어가는 문자를 변수로 선언하기도 한다.
import urllib
from urllib.request import Request
#중요한 부분!
html = 'https://ko.wikipedia.org/wiki/{search_words}'
req = Request(html.format(search_words = urllib.parse.quote('보더_콜리')))
response = urlopen(req)
soup = BeautifulSoup(response, 'html.parser')
soup
* string선언 시 {}를 넣어주면 해당 중괄호 안의 값은 변수가 되어 외부에서 받아와줄 수 있게 된다.(자바스크립트에서 ${}를 사용하는 것과 비슷)
* html이라는 변수의 format명령어로 search_words를 urllib의 .parse.quote()함수로 한글 글자를 utf-8파일로 변환해준다.
* 그 다음에는 앞서 한 것과 똑같이,
response = urlopen(req)
soup = BeautifulSoup(response, 'html.parser')
soup
를 통해서 bs4를 통해 html을 받아온다.

4. 해당 위키피디아 페이지를 들어가면 가장 아래에 강아지 품종들을 모아 놓았다. 한 번 이 목록들을 받아와보자. 지금 받아온 html을 보면 <li>태그 안에 견종들이 표시되어 있음을 볼 수 있다. 그렇다면 <li>태그 값들을 한번 find_all로 전체 불러오기해보자.

n = 0
for each in soup.find_all('li'):
print('=>' + str(n) + ('=' * 40))
print(each)
n+=1

5. <li>태그를 찾을 때마다 1씩 증가하는 n을 표시하도록 하여 보다 쉽게 데이터를 활용할 수 있게 되었다. 이렇게 하면 슬라이싱 등의 기능을 통해 다시 한 번 필요없는 부분을 쳐낼 수 있다.

6. 이번에는 '시카고에서 가장 맛있는 샌드위치 50선'이라는 외국 기사에서 데이터를 뽑아내보자. 이 페이지는 bs 입문자들이 웹페이지를 크롤링을 통해 분석하기에 매우 적절하다고 한다.
7. 먼저 아래의 링크를 통해 시카고 샌드위치 맛집 50선 페이지에 들어가보자!
https://www.chicagomag.com/chicago-magazine/november-2012/best-sandwiches-chicago/
The 50 Best Sandwiches in Chicago
Our list of Chicago’s 50 best sandwiches, ranked in order of deliciousness
www.chicagomag.com
8. 먼저 페이지 url을 분석해보자.
- 먼저 url을 base url과 sub url로 분할한다.(실제로 검색해보면 홈페이지 주소인 base url의 뒤에 붙는 sub url이 바뀔 때가 있기 때문이다.)
- headers라는 새로운 변수가 나타난다. 이건 자동화된 봇이 웹브라우저에 들어오는 것을 차단하는 기능을 회피하여 사용자가 웹 브라우저인 것처럼 보여주기 위해서이다.(봇이나 스크래퍼로 사이트에서 감지하면 일부 기능이 차단될 수 있다.)
from bs4 import BeautifulSoup
# from urllib.request import urlopen
from urllib.request import Request, urlopen
url_base = 'https://www.chicagomag.com'
url_sub = '/chicago-magazine/november-2012/best-sandwiches-chicago/'
url = url_base + url_sub
# html = urlopen(url)
req = Request(url, headers = {'User-Agent': 'Chrome'})
html = urlopen(req).read()
soup = BeautifulSoup(html, 'html.parser')
soup

9. 우리는 '시카고의 50개의 맛집'을 찾고 있다. 구글 크롬의 개발자 도구(ctrl+shift+i)에서 요소 확인 기능(ctrl+shift+c) 등으로 html요소들을 확인하다 보면 div의 sammy클래스에서 해당 부분들을 표시하고 있음을 볼 수 있다.


10. div의 sammy클래스들을 읽어 보자. 아주 많은 정보들이 들어온다.

11. 한 항목만 살펴보자. 랭킹(sammyRank), 가게 이름, 메뉴(<b>BLT</b>)가 보인다.

12. soup.find_all('div', 'sammy')[0]의 객체 타입은 bs4.element.Tag라는 bs4의 고유객체이다. 객체 타입이 이렇다는 것은 즉 find명령을 사용할 수 있다는 것이다.

13. soup.find_all('div', 'sammy')[0]객체에 find_all 명령을 적용해보자.



14. 이제 가게 이름, 메뉴 등을 분석해보자. 아까 sammyListing객체 안에 가게 이름, 메뉴 데이터 등이 \n으로 구분되어 있었던 것을 볼 수 있었다. 이것을 슬라이싱하면 쉽게 가게 이름, 메뉴 데이터 등을 알아낼 수 있을 것이다.


15. 지금까지 한 방식을 활용해서 50개의 베스트 가게를 소개하는 메인페이지에서 랭크, 메뉴이름, 가게 이름, 각각의 가게를 소개하는 웹주소를 알아내는 방법을 확인하여 전체 반복문으로 완성해 보자.
from urllib.parse import urljoin
import re
url_base = 'https://www.chicagomag.com'
# 필요한 내용을 담을 빈 리스트를 준비
# 리스트로 하나씩 컬럼을 만들고
# DataFrame으로 합칠 예정
rank = []
main_menu = []
cafe_name = []
url_add = []
list_soup = soup.find_all('div', 'sammy') # 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])
# urljoin 함수는 item.find('a')['href']로 가져온 url이 절대주소면 url_base에 붙여넣지 않고, 상대주소면 url_base에 붙여넣는 함수이다
url_add.append(urljoin(url_base, item.find('a')['href']))
이렇게 잘 얻어오는 것을 알 수 있다.

16. 이제 이렇게 얻어온 것들을 DataFrame으로 만든다. pandas를 응용해서 웹크롤링으로 얻어온 list들을 column화한다.

17. 컬럼 순서를 바꾸어 보자. Rank, Cafe, Menu, URL순서로 바꿔 보자.

18. 마지막으로 df.to_csv()로 저장하자.
df.to_csv('../data/03. best_sandwiches_list_chicago_ds_study.csv', sep=',', encoding='UTF-8')'데이터분석 > 미니프로젝트 02. 웹 데이터 분석(크롤링)' 카테고리의 다른 글
| 미니프로젝트 02-01-04. 데이터 시각화 (0) | 2024.04.13 |
|---|---|
| 미니프로젝트 02-01-03. 시카고 맛집 데이터 하위 페이지 분석 (2) | 2024.04.13 |
| 미니프로젝트 02-01-01. Beatiful Soup 기초와 웹데이터 (1) | 2024.04.05 |