일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | ||||
4 | 5 | 6 | 7 | 8 | 9 | 10 |
11 | 12 | 13 | 14 | 15 | 16 | 17 |
18 | 19 | 20 | 21 | 22 | 23 | 24 |
25 | 26 | 27 | 28 | 29 | 30 | 31 |
- kafka설치
- select_one()
- webscrap
- pivot_table
- read_table
- to_json
- findall()
- 코딩생활
- to_html
- keras
- to_csv
- to_excel
- Join
- find_all()
- read_excel
- 녘
- pandas
- find()
- DataFrame
- read_csv
- TensorFlow
- read_fwf
- select_related()
- 강남데이트
- groupby
- 웹스크랩
- 강남 녘
- 갈비스테이크
- topic생성
- iloc
- Today
- Total
자드's
[ Pandas ] Python의 pandas 라이브러리를 이용한 데이터분석의 기초 ( Series, DataFrame ) - (4) : Beautiful Soup 본문
[ Pandas ] Python의 pandas 라이브러리를 이용한 데이터분석의 기초 ( Series, DataFrame ) - (4) : Beautiful Soup
최자드 2022. 11. 29. 20:45Beautiful Soup
데이터 분석을 하기 위해서 데이터들을 수집해야한다
웹이라는 정보의 바다에서 궁금한 데이터가 있어 분석을 하고싶다면
먼저 데이터를 불러오는 것이 우선 업무이다
데이터들을 불러오는 데에 사용하는 것이
Beautiful Soup이다.
알아보도록 하자
Beautiful Soup 을 이용한 웹스크랩의 기본
먼저 Beautiful Soup 라이브러리를 사용하기 전에 설치가 필요하다
아나콘다 설치가 되어있기 때문에 따로 설치하지 않았지만
만약, 설치가 되어있지 않다면
pip install beautifulsoup4, pip install requests 를 입력해 설치 해주도록 하자
먼저 이용 전에
각각의 방법의 장단점을 살펴보자
스크랩을 원하는 페이지의 소스를 받아오면 처음엔 String type으로 받아온다
이를 BeautifulSoup 객체로 만들어주는 과정을 거친 후에
객체 안에서 원하는 데이터를 뽑아주기만 하면 된다
# 웹 문서 읽기 (scraping)
# crawling : scrap, selenium ...
# Beautiful soup을 이용 : XML, HTML 문서 처리
import requests
from bs4 import BeautifulSoup
baseUrl = "https://www.naver.com/index.html"
sourceData = requests.get(baseUrl)
print(sourceData)
plainText = sourceData.text # 웹에서 소스 불러오기까지 완료
#print(plainText)
print(type(plainText)) # <class 'str'> 하지만 스트링타입임
convertData = BeautifulSoup(plainText, 'lxml') # Beautiful soup 객체 생성과 Parser를 사용
#print(convertData)
print(type(convertData)) # <class 'bs4.BeautifulSoup'> 뷰티풀숲 객체가 되었음
find_all( ) 메소드 ( 괄호 안에 있는 요소를 모두 찾아옴)
BeautifulSoup 객체 안에서 <a> 태그를 모두 찾아서 herf 속성과, string을 추출하는 코드
for atag in convertData.find_all('a'): # 웹브라우저 소스에있는 <a> 만 찾아와보기
href = atag.get('href') # <a>의 href속성과
title = atag.string # <a>의 String
print(href,' ',title) # 출력
이를 이용해 웹에서 원하는 데이터만 추출할 수 있다
기본적으로 사용하는 방법은 끝이다.
Beautiful Soup의 메소드
먼저 BeautifulSoup의 기본 사용방법을 알아보자
from bs4 import BeautifulSoup
html_page = '''
<html><body>
<h1>제목 태그</h1>
<p>웹 문서 스크래핑</p>
<p>특정 페이지 문서</p>
</body></html>
'''
print(type(html_page)) # <class 'str'>
soup = BeautifulSoup(html_page,'html.parser')
print(type(soup)) # <class 'bs4.BeautifulSoup'>
print(soup)
print()
h1 = soup.html.body.h1
print('h1:',h1, type(h1)) # <class 'bs4.element.Tag'>
print('h1:',h1.string, type(h1.string)) # <class 'bs4.element.NavigableString'>
print('h1:',h1.text, type(h1.text)) # <class 'str'>
print()
p1 = soup.html.body.p # 첫번째 p요소
print('p1:',p1.string)
p2 = p1.next_sibling.next_sibling # 두번째 p요소 # 이런식으로 요소를 하나하나 찾기엔 너무 힘들다
print('p2:',p2.string)
html.parser로 트리형식으로 만들어 준 후에
해당 요소를 직접 선택해서 형태로 불러올 수 있다.
또한, 저런 방식으로 찾는다면 첫요소만 찾아오고 다음 요소를 찾을 땐
p2 = p1.next_sibling.next_sibling 과 같이 계속해서
".next_sibling "
이래서 언제 다 찾아요...
이런 불편한걸 만들었을 천재들이 아니다.
당연히 편리하게 사용할 수 있는 메소드가 존재한다
아래의 4가지 검색용 메소드를 알아보자.
from bs4 import BeautifulSoup
BeautifulSoup.find()
BeautifulSoup.findAll() # 혹은 find_all()
BeautifulSoup.select_one()
BeautifulSoup.select()
먼저 find( ) 메소드를 알아보자.
이름과 같이 1개만 찾는 검색용 메소드이다.
find( )메소드는 기본사용법과 크게 다르지 않다.
마찬가지로 먼저 선택된 요소만 가져온다.
차이점이라면 class 와 id 가 부여된 요소를
지정해서 가져올 수 있다는 점이다.
print('\n검색용 메소드 : find()')
html_page2 = '''
<html><body>
<h1 id='title'>제목 태그</h1>
<p>웹 문서 스크래핑</p>
<p id='my' class='our'>특정 페이지 문서</p>
</body></html>
'''
soup2 = BeautifulSoup(html_page2, 'html.parser')
print(soup2.p,' ', soup2.p.string) # 첫번째 p요소
print(soup2.find('p').string) # 위와 같음 # find()는 먼저 선택된 element만 선택됨
print(soup2.find(['p','h1']).string) # 변수를 복수로 써줄 수 있지만 # find()는 한개만 넘어옴
print(soup2.find(id='title').string)
print(soup2.find(id='my').string)
print(soup2.find(class_='our').string) # class는 _를 붙여줘야함
print(soup2.find(attrs={'class':'our'}).string) # attrs 에 dict 형식으로 넣어줘도 됨
print(soup2.find(attrs={'id':'my'}).string)
findAll( ), find_all( ) 메소드를 알아보자
두개는 같은 메소드다 (이름만 다를 뿐)
find( ) 메소드와의 차이점을 알아보면
선택한 요소를 '모두' 찾아온다는 점
여러개의 요소를 입력해도 '모두' 찾아온다는 점
모두 찾아오기 때문에 반복문을 사용해서 원하는 내용들이 있다면
조건문과 반복문을 사용해서 추출하여 사용하면 된다.
정규표현식을 사용해 미리 조건을 걸 수도 있다.
print('\n검색용 메소드 : findAll(), find_all()')
html_page3 = '''
<html><body>
<h1 id='title'>제목 태그</h1>
<p>웹 문서 스크래핑</p>
<p id='my' class='our'>특정 페이지 문서</p>
<div>
<a href="https://www.naver.com" class='aa'>naver</a><br/>
<a href="https://www.daum.net" class='aa'>daum</a>
</div>
</body></html>
'''
soup3 = BeautifulSoup(html_page3, 'html.parser')
print(soup3.find_all('p')) # p요소를 모두 찾아줌
print(soup3.find_all('a'))
print(soup3.find_all(['a','p'])) # 변수를 복수로 사용할 수 있다
print(soup3.find_all(class_='aa'), '클래스') # 속성명으로 선택해서 찾을 수 있다
print(soup3.findAll('p'), '대문자 All') # 이름만 다를뿐 위와 같은 메소드이다
print()
links = soup3.findAll('a')
for i in links:
print(i.attrs['href'],' - ',i.string) # 응용
import re # 정규표현식
links2 = links = soup3.findAll(href=re.compile(r'^https'))
for i in links2:
print(i.attrs['href'],' - ',i.string)
select_one( ), select( ) 메소드도 앞서 본 2개의 메소드와 비슷하다.
차이점만 빠르게 보자면
javascript에서 class와 id를 선택할 때 " . "과 " # "을 사용했는데
여기서 똑같이 class = " . " , id = " # "을 사용해서 불러올 수 있다
print('\nCSS의 selector 사용')
html_page4 = '''
<html><body>
<div id='hello'>
<a href="https://www.naver.com" class='aa'>naver</a><br/>
<span>
<a href="https://www.daum.net" class='aa'>daum</a>
</span>
<ul class='world'>
<li>안녕</li>
<li>반갑</li>
</ul>
</div>
<div id='hi' class='good'>
second div
</div>
</body></html>
'''
soup4 = BeautifulSoup(html_page4, 'html.parser')
print(soup4.select_one('div')) # 첫번째 div 태그만 선택됨 # select_one()은 단수를 반환
print()
print(soup4.select_one('div#hi')) # id가 hi인 div가 선택됨
print(soup4.select_one('div.good')) # class가 good인 div가 선택됨
print()
print(soup4.select('div')) # select()은 복수를 반환
print(soup4.select('div#hello > a')) # 자식 (직계)
print(soup4.select('div#hello a')) # 자손
print(soup4.select('div#hello > span > a')) # span 안의 <a>태그만 선택
lis = soup4.select('div#hello ul.world > li') # li 요소 선택
print(lis)
msg = list() # []
for i in lis:
msg.append(i.string)
자식요소와 자손요소가 헷갈린다면 참고하자
출처 : https://sectumsempra.tistory.com/57
자식 | 자손 |
![]() |
![]() |
간단 예제
예제를 통해서
find( )와 select( )의 사용법과 결과물을 보자
# 웹문서 읽기 1
from urllib.request import urlopen # 읽어올 때 쓰는 클래스 둘 중 하나만 쓰면됨
import requests
from bs4 import BeautifulSoup
#print('벅스 차트')
url = urlopen('https://music.bugs.co.kr/chart')
soup = BeautifulSoup(url.read(), 'html.parser')
#print(soup,type(soup)) # <class 'bs4.BeautifulSoup'>
musics = soup.findAll('td',class_='check')
print(musics)
for i,music in enumerate(musics):
print("{}위:{}".format(i+1, music.input['title']))
print('--------------------------------------------------------------------------')
![]() |
# 웹문서 읽기 2
import urllib.request as req
url = 'https://ko.wikipedia.org/wiki/%EC%9D%B4%EC%88%9C%EC%8B%A0'
wiki = req.urlopen(url)
soup2 = BeautifulSoup(wiki,'html.parser')
#mw-content-text > div.mw-parser-output > p:nth-child(6) 검사창에서 copy selector 해온 경로 (select 메소드에 줄 경로)
result = soup2.select('div.mw-parser-output > p > b') # 위 p요소에서 b만 선택해보자
for a in result:
if(a.string != None):
print(a.string)
print('-----------------------------------------------------------------------')
![]() |
뭐가 좋고 나쁘고는 없다.
본인이 사용하기 편한 방법으로 코드를 짜면 된다.
갱신형스크랩(schedular)
웹에는 시간이 지나면서 변하는 데이터도 존재한다.
대표적으로 주식 차트, 음악 인기차트 등
이러한 데이터들을 일정 주기로 불러오기 위해서
time.sleep( )을 이용해보자.
맛보기용
# 일정 시간 마다 웹 문서 읽기 (scheduler)
# 동적인 data를 읽을 때 사용 (ex = 주식, 현재인원 등등)
# import schedule # pip install schedule 스케쥴러 모듈 지원
import time
import datetime
import urllib.request as req
from bs4 import BeautifulSoup
import requests
def work():
url = 'https://finance.naver.com/marketindex/'
# data = req.urlopen(url) # 방법 1 데이터를 보낼 때 인코딩하여 바이너리 형태로 보낸다
data = requests.get(url).text # 방법 2 데이터를 보낼 때 딕셔너리 형태로 보낸다
soup = BeautifulSoup(data, 'html.parser')
price = soup.select_one("div.head_info > span.value").string
print('미국USD :',price)
t = datetime.datetime.now() # 현재 시간
fname = './USD/' + t.strftime('%Y-%m-%d-%H-%M-%S') + '.txt' # 경로와 파일명을 지정 - 현재 날짜 및 시간
with open(fname, 'w') as f: # 파일 저장
f.write(price)
while True:
print('recall')
work()
time.sleep(5) # 5초 마다 work() 함수 호출
# if 문을 이용해서 마감시간을 정할수도 있다
![]() |
xml과 json 파일 읽어오기
xml, json 도 불러올 수 있다.
위의 다른 방법과는 다르게
.read() 로 파일을 읽고 .decode()로 디코딩을 해서 불러와야 한다.
xml과 json은 웹브라우저에
인코딩이 되어서 올라가기 때문에
다시 불러올 때 디코딩을 해서 불러오는 것이다.
# Beautiful Soup 으로 XML 문서 처리
# https://raw.githubusercontent.com/pykwon/python/master/seoullibtime5.xml
import urllib.request as req
from bs4 import BeautifulSoup
url = 'https://raw.githubusercontent.com/pykwon/python/master/seoullibtime5.xml'
plainText = req.urlopen(url).read().decode()
print(plainText)
soup = BeautifulSoup(plainText, 'lxml') # html.parser와 같은 역할
libData = soup.select('row')
for data in libData:
name = data.find('lbrry_name').text
addr = data.find('adres').text
print('도서관명 :',name)
print('주소 :',addr)
json은 스크랩할 때 BeautifulSoup이 필요 없다.
대신에, 따로 json객체를 import해서 메소드를 이용해서 불러온다.
# web에서 JSON 문서 읽기
# JSON 은 Beautiful Soup이 필요가 없다
import json
import urllib.request as req
url = 'https://raw.githubusercontent.com/pykwon/python/master/seoullibtime5.json'
plainText = req.urlopen(url).read().decode() # json 문서 웹에서 가져오기
#print(type(plainText)) # <class 'str'>
jsonData = json.loads(plainText) # str --> dict : json 디코딩
#print(type(jsonData)) # <class 'dict'>
print()
# print(jsonData['SeoulLibraryTime']['row'][0]['LBRRY_NAME']) # B.S가 필요없다
libDatas = jsonData.get('SeoulLibraryTime').get('row')
# print(libDatas)
datas = []
for ele in libDatas:
name = ele.get('LBRRY_NAME')
tel = ele.get('TEL_NO')
addr = ele.get('ADRES')
print(name + '\t' + tel + '\t' + addr)
imsi = [name,tel,addr]
datas.append(imsi)
import pandas as pd
df = pd.DataFrame(datas, columns=['도서관 이름', '전화번호', '주소'])
print(df)
df.to_html('도서관정보.html')
Beautiful Soup을 이용한 web scraping에 대해서 알아봤는데
스크랩 자체는 간단하고, 따로 필요한 데이터를 수집할 때 요긴하게 써먹을 것 같다.
다음 포스팅은 아마도
KoNLPy 를 사용해서
간단한 형태소 분석을 하는 방법이 될 것 같다
Beautiful Soup을 사용해 웹스크랩과
KoNLPy 형태소 분석을 같이 사용해보는 것 까지 다시 복습해보자