[Python] 웹페이지 분석/Beautiful Soup 모듈 (1)


Beautiful Soup란?

Beautiful Soup은 웹페이지 분석 모듈로, HTML 코드에서 특정 태그나 값을 추출(parsing;파싱)할 때 사용하는 라이브러리입니다. requests 모듈로 HTML 소스를 받아오고 Beaitoful Soup은 이를 파싱합니다. parsing(파싱)이란 가공되지 않은 문자열에서 필요한 부분을 추출하여 의미있는 구조화된 데이터로 만드는 과정입니다.

 

[관련 문서]

https://www.crummy.com/software/BeautifulSoup/bs4/doc/

 

Beautiful Soup Documentation — Beautiful Soup 4.12.0 documentation

Beautiful Soup Documentation Beautiful Soup is a Python library for pulling data out of HTML and XML files. It works with your favorite parser to provide idiomatic ways of navigating, searching, and modifying the parse tree. It commonly saves programmers h

www.crummy.com


설치방법

pip install bs4

 

티스토리 웹페이지 분석(기본)

# 모듈 가져오기
import requests
from bs4 import BeautifulSoup as bs

#웹사이트 소스 가져오기
res = requests.get('https://www.tistory.com/')
html = res.text

#html.parser를 이용하여 bs4 객체로 변환 후 웹페이지를 분석
soup = bs(html, 'html.parser')

데이터 추출

Beautiful Soup을 사용하여 웹페이지의 특정 태그를 가져오는 방법을 알아보겠습니다. find(), find_all(), select() 함수를 사용할 수 있습니다. 다양한 방법으로 실행해보기위해 html 코드를 그냥 막 만들어왔습니다. 사용할 html 코드는 다음과 같습니다.

import requests
from bs4 import BeautifulSoup as bs

#html 실습용 소스코드
html = '''
<!DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Beautiful Soup Ex</title>
    </head>
    
    <body>
        <div class="tistory_info">
            <h3>Tistroy</h3>
            <p id="color1" class="tistory_color">티스토리는 오렌지색
                <ul class="list1">
                    <li><a href="https://feed.com">피드</a></li>
                    <li><a href="https://story.com">스토리</a></li>
                    <li><a href="https://skin.com">스킨</a></li>
                    <li><a href="https://forum.com">포럼</a></li>
                </ul>
                <span class="life">라이프</span>
                <span class="travel">여행</span>
                <span class="it">IT</span>
                <button id="ok" type="submit">ok</button>
            </p>
        </div>

        <div class="naver_info">
            <h3>Naver</h3>
            <p id="color2" class="naver_color">네이버는 초록색
                <ul class="list2">
                    <li><a href="https://mail.com">메일</a></li>
                    <li><a href="https://cafe.com">카페</a></li>
                    <li><a href="https://finance.com">증권</a></li>
                </ul>
                <span class="ytn">YTN</span>
                <span class="mbc">mbc</span>
                <span class="jtbc">jtbc</span>
                <button id="cancel" type="submit">cancel</button>
            </p>
        </div>
    </body>
</html>
'''

soup = bs(html, 'html.parser')

 

1. find() 함수

find()는 HTML 코드에서 원하는 태그를 가져올 수 있습니다. 동일한 태그가 여러 개 있을 경우 첫번째 태그 한 개만 가져옵니다.

print(soup.find('title'))
print(soup.find('li'))

#출력값
#<title>Beautiful Soup Ex</title>
#<li><a href="https://feed.com">피드</a></li>

HTML 코드를 보면 <span> 태그에서도 class속성이 각각 다른 것을 알 수 있습니다. span 태그를 속성값을 이용해서 가져올 수도 있습니다. 

print(soup.find('span', class_='life'))
print(soup.find('span', class_='ytn'))

#출력값
#<span class="life">라이프</span>
#<span class="ytn">YTN</span>

 

2. find_all() 함수

find_all()은 동일한 태그가 여러 개인 경우 모두 가져옵니다. 

print(soup.find_all('li'))

#'a' 출력값
'''
[<li><a href="https://feed.com">피드</a></li>, <li><a href="https://story.com">스토리</a></li>,
<li><a href="https://skin.com">스킨</a></li>, <li><a href="https://forum.com">포럼</a></li>, 
<li><a href="https://mail.com">메일</a></li>, <li><a href="https://cafe.com">카페</a></li>, 
<li><a href="https://finance.com">증권</a></li>]
'''

만약 두 개의 태그를 같이 찾고 싶다면 리스트로 묶어서 찾을 수 있습니다.

print(soup.find_all(['button','h3']))

#출력값
'''
[<h3>Tistroy</h3>, <button id="ok" type="submit">ok</button>, 
<h3>Naver</h3>, <button id="cancel" type="submit">cancel</button>]
'''

 

3. select() 함수

select()는 다양한 옵션들을 가지고 있습니다. 

#1. select('태그명')
print(soup.select('p'))
#2. select('태그명[속성]')
print(soup.select('a[href]'))

#인덱스 사용 가능
print(soup.select('a[href]')[0])
print(soup.select('a[href]')[5])
#3. select('.클래스명')
print(soup.select('.list1'))
#4. select('상위태그 > 하위태그 > 하위태그 > ...')
print(soup.select('div > p > ul > li'))

#인덱스 사용가능
print(soup.select('div > p > ul > li')[0])
print(soup.select('div > p > ul > li')[3])
#5.select('상위태그.클래스명' > '하위태그.클래스명')
print(soup.select('p.tistory_color > span.travel'))
#6. select('#id명')
print(soup.select('#ok'))
#7. select('#id명 > 태그명.클래스명')
print(soup.select('#color2 > ul.list2'))

 

4. 텍스트 추출

태그 내에 있는 텍스트를 추출하는 방법입니다. find()로 찾을 때는 하나만 추출하기 때문에 바로 print를 할 수 있지만, find_all()로 찾을 때는 모든 값을 찾기 때문에 for문을 사용해야합니다.

a = soup.find('a')
print(a.string) #피드

span = soup.find_all('span')
for i in span:
    print(i.string)
#출력값
'''
라이프
여행
IT
YTN
mbc
jtbc
'''

#태그를 제외한 문자열 추출
print(soup.get_text()) #출력값은 길어서 생략