Python BeautifulSoup 라이브러리 활용법 - HTML 파싱 완벽 가이드

解析库的 설치

pip3 install beautifulsoup4

BeautifulSoup 초기화

from bs4 import BeautifulSoup
sample_html = '''  
<div class="card">  
    <div class="card-header">  
        <h3>환영합니다</h3>  
    </div>  
    <div class="card-body">  
        - 사과
- 바나나
- 포도  
        - 사과
- 바나나  
    </div>  
</div>  
'''

parser = BeautifulSoup(sample_html, "lxml")

태그 선택자

요소 선택 - parser.태그명

sample_html = """
<html><head><title>동화 이야기</title></head>
<body>
<p class="intro" name="story"><b>동화 이야기</b></p>
<p class="content">한때 세 자매가 있었습니다; 그 이름들은
<a href="http://example.com/elsie" class="sister" id="link1"><!-- Elsie --></a>,
<a href="http://example.com/lacie" class="sister" id="link2">Lacie</a>와
<a href="http://example.com/tillie" class="sister" id="link3">Tillie</a>입니다;
그리고 그들은 우물의 바닥에 살았습니다.</p>
<p class="content">...</p>
"""
from bs4 import BeautifulSoup
parser = BeautifulSoup(sample_html, 'lxml')
print(parser.title)
print(type(parser.title))
print(parser.head)
print(parser.p)

출력 결과:

<title>동화 이야기</title>
<class 'bs4.element.Tag'>
<head><title>동화 이야기</title></head>
<p class="intro" name="story"><b>동화 이야기</b></p>

이름 가져오기 - parser.태그명.name

sample_html = """
<html><head><title>동화 이야기</title></head>
<body>
<p class="intro" name="story"><b>동화 이야기</b></p>
<p class="content">한때 세 자매가 있었습니다; 그 이름들은
<a href="http://example.com/elsie" class="sister" id="link1"><!-- Elsie --></a>,
<a href="http://example.com/lacie" class="sister" id="link2">Lacie</a>와
<a href="http://example.com/tillie" class="sister" id="link3">Tillie</a>입니다;
그리고 그들은 우물의 바닥에 살았습니다.</p>
<p class="content">...</p>
"""
from bs4 import BeautifulSoup
parser = BeautifulSoup(sample_html, 'lxml')
print(parser.title.name)

속성 가져오기 - parser.태그명.attrs[] 또는 parser.태그명[]

sample_html = """
<html><head><title>동화 이야기</title></head>
<body>
<p class="intro" name="story"><b>동화 이야기</b></p>
<p class="content">한때 세 자매가 있었습니다; 그 이름들은
<a href="http://example.com/elsie" class="sister" id="link1"><!-- Elsie --></a>,
<a href="http://example.com/lacie" class="sister" id="link2">Lacie</a>와
<a href="http://example.com/tillie" class="sister" id="link3">Tillie</a>입니다;
그리고 그들은 우물의 바닥에 살았습니다.</p>
<p class="content">...</p>
"""
from bs4 import BeautifulSoup
parser = BeautifulSoup(sample_html, 'lxml')
print(parser.p.attrs['name'])
print(parser.p['name'])

출력:

story
story

내용 가져오기 - parser.태그명.string

sample_html = """
<html><head><title>동화 이야기</title></head>
<body>
<p class="intro" name="story"><b>동화 이야기</b></p>
<p class="content">한때 세 자매가 있었습니다; 그 이름들은
<a href="http://example.com/elsie" class="sister" id="link1"><!-- Elsie --></a>,
<a href="http://example.com/lacie" class="sister" id="link2">Lacie</a>와
<a href="http://example.com/tillie" class="sister" id="link3">Tillie</a>입니다;
그리고 그들은 우물의 바닥에 살았습니다.</p>
<p class="content">...</p>
"""
from bs4 import BeautifulSoup
parser = BeautifulSoup(sample_html, 'lxml')
print(parser.p.string)

출력:

동화 이야기

중첩 선택 - parser.태그명.태그명

sample_html = """
<html><head><title>동화 이야기</title></head>
<body>
<p class="intro" name="story"><b>동화 이야기</b></p>
<p class="content">한때 세 자매가 있었습니다; 그 이름들은
<a href="http://example.com/elsie" class="sister" id="link1"><!-- Elsie --></a>,
<a href="http://example.com/lacie" class="sister" id="link2">Lacie</a>와
<a href="http://example.com/tillie" class="sister" id="link3">Tillie</a>입니다;
그리고 그들은 우물의 바닥에 살았습니다.</p>
<p class="content">...</p>
"""
from bs4 import BeautifulSoup
parser = BeautifulSoup(sample_html, 'lxml')
print(parser.head.title.string)

자식 노드 - parser.태그명.contents

sample_html = """
<html>
    <head>
        <title>동화 이야기</title>
    </head>
    <body>
        <p class="content">
            한때 세 자매가 있었습니다; 그 이름들은
            <a href="http://example.com/elsie" class="sister" id="link1">
                <span>Elsie</span>
            </a>
            <a href="http://example.com/lacie" class="sister" id="link2">Lacie</a> 
            그리고
            <a href="http://example.com/tillie" class="sister" id="link3">Tillie</a>
            그리고 그들은 우물의 바닥에 살았습니다.
        </p>
        <p class="content">...</p>
"""
from bs4 import BeautifulSoup
parser = BeautifulSoup(sample_html, 'lxml')
print(parser.p.contents)

자식 노드 - parser.태그명.children

sample_html = """
<html>
    <head>
        <title>동화 이야기</title>
    </head>
    <body>
        <p class="content">
            한때 세 자매가 있었습니다; 그 이름들은
            <a href="http://example.com/elsie" class="sister" id="link1">
                <span>Elsie</span>
            </a>
            <a href="http://example.com/lacie" class="sister" id="link2">Lacie</a> 
            그리고
            <a href="http://example.com/tillie" class="sister" id="link3">Tillie</a>
            그리고 그들은 우물의 바닥에 살았습니다.
        </p>
        <p class="content">...</p>
"""
from bs4 import BeautifulSoup
parser = BeautifulSoup(sample_html, 'lxml')
print(parser.p.children)
for idx, child in enumerate(parser.p.children):
    print(idx, child)

자손 노드 - parser.태그명.descendants (태그 내의 텍스트도 포함)

sample_html = """
<html>
    <head>
        <title>동화 이야기</title>
    </head>
    <body>
        <p class="content">
            한때 세 자매가 있었습니다; 그 이름들은
            <a href="http://example.com/elsie" class="sister" id="link1">
                <span>Elsie</span>
            </a>
            <a href="http://example.com/lacie" class="sister" id="link2">Lacie</a> 
            그리고
            <a href="http://example.com/tillie" class="sister" id="link3">Tillie</a>
            그리고 그들은 우물의 바닥에 살았습니다.
        </p>
        <p class="content">...</p>
"""
from bs4 import BeautifulSoup
parser = BeautifulSoup(sample_html, 'lxml')
print(parser.p.descendants)
for idx, child in enumerate(parser.p.descendants):
    print(idx, child)

부모 노드 - parser.태그명.parent

sample_html = """
<html>
    <head>
        <title>동화 이야기</title>
    </head>
    <body>
        <p class="content">
            한때 세 자매가 있었습니다; 그 이름들은
            <a href="http://example.com/elsie" class="sister" id="link1">
                <span>Elsie</span>
            </a>
            <a href="http://example.com/lacie" class="sister" id="link2">Lacie</a> 
            그리고
            <a href="http://example.com/tillie" class="sister" id="link3">Tillie</a>
            그리고 그들은 우물의 바닥에 살았습니다.
        </p>
        <p class="content">...</p>
"""
from bs4 import BeautifulSoup
parser = BeautifulSoup(sample_html, 'lxml')
print(parser.a.parent)

조상 노드 - parser.태그명.parents

sample_html = """
<html>
    <head>
        <title>동화 이야기</title>
    </head>
    <body>
        <p class="content">
            한때 세 자매가 있었습니다; 그 이름들은
            <a href="http://example.com/elsie" class="sister" id="link1">
                <span>Elsie</span>
            </a>
            <a href="http://example.com/lacie" class="sister" id="link2">Lacie</a> 
            그리고
            <a href="http://example.com/tillie" class="sister" id="link3">Tillie</a>
            그리고 그들은 우물의 바닥에 살았습니다.
        </p>
        <p class="content">...</p>
"""
from bs4 import BeautifulSoup
parser = BeautifulSoup(sample_html, 'lxml')
print(list(enumerate(parser.a.parents)))

兄弟 노드 - parser.태그명.next_siblings / previous_siblings

sample_html = """
<html>
    <head>
        <title>동화 이야기</title>
    </head>
    <body>
        <p class="content">
            한때 세 자매가 있었습니다; 그 이름들은
            <a href="http://example.com/elsie" class="sister" id="link1">
                <span>Elsie</span>
            </a>
            <a href="http://example.com/lacie" class="sister" id="link2">Lacie</a> 
            그리고
            <a href="http://example.com/tillie" class="sister" id="link3">Tillie</a>
            그리고 그들은 우물의 바닥에 살았습니다.
        </p>
        <p class="content">...</p>
"""
from bs4 import BeautifulSoup
parser = BeautifulSoup(sample_html, 'lxml')
print(list(enumerate(parser.a.next_siblings)))
print(list(enumerate(parser.a.previous_siblings)))

표준 선택자

find_all(name, attrs, recursive, text, **kwargs)

태그명, 속성, 내용으로 문서를 검색할 수 있습니다.

태그명으로 검색 - parser.find_all('태그명')

sample_html ='''
<div class="card">
    <div class="card-header">
        <h3>환영합니다</h3>
    </div>
    <div class="card-body">
        - 사과
- 바나나
- 포도
        - 사과
- 바나나
    </div>
</div>
'''
from bs4 import BeautifulSoup
parser = BeautifulSoup(sample_html, 'lxml')
print(parser.find_all('ul'))

속성으로 검색 - parser.find_all(attrs={})

sample_html ='''
<div class="card">
    <div class="card-header">
        <h3>환영합니다</h3>
    </div>
    <div class="card-body">
        - 사과
- 바나나
- 포도
        - 사과
- 바나나
    </div>
</div>
'''
from bs4 import BeautifulSoup
parser = BeautifulSoup(sample_html, 'lxml')
print(parser.find_all(attrs={'id': 'items-1'}))
print(parser.find_all(attrs={'name': 'item-list'}))
sample_html ='''
<div class="card">
    <div class="card-header">
        <h3>환영합니다</h3>
    </div>
    <div class="card-body">
        - 사과
- 바나나
- 포도
        - 사과
- 바나나
    </div>
</div>
'''
from bs4 import BeautifulSoup
parser = BeautifulSoup(sample_html, 'lxml')
print(parser.find_all(id='items-1'))
print(parser.find_all(class_='item'))

텍스트 내용으로 검색

sample_html ='''
<div class="card">
    <div class="card-header">
        <h3>환영합니다</h3>
    </div>
    <div class="card-body">
        - 사과
- 바나나
- 포도
        - 사과
- 바나나
    </div>
</div>
'''
from bs4 import BeautifulSoup
parser = BeautifulSoup(sample_html, 'lxml')
print(parser.find_all(text='사과'))

find(name, attrs, recursive, text, **kwargs)

find는 단일 요소를 반환하고, find_all은 모든 요소를 반환합니다.

sample_html ='''
<div class="card">
    <div class="card-header">
        <h3>환영합니다</h3>
    </div>
    <div class="card-body">
        - 사과
- 바나나
- 포도
        - 사과
- 바나나
    </div>
</div>
'''
from bs4 import BeautifulSoup
parser = BeautifulSoup(sample_html, 'lxml')
print(parser.find('ul'))
print(type(parser.find('ul')))
print(parser.find('page'))

find_parents() / find_parent()

find_parents()는 모든 조상 노드를 반환하고, find_parent()는 직접적인 부모 노드를 반환합니다.

find_next_siblings() / find_next_sibling()

find_next_siblings()는 뒤에 있는 모든兄弟 노드를 반환하고, find_next_sibling()는 뒤에 있는 첫 번째兄弟 노드를 반환합니다.

find_previous_siblings() / find_previous_sibling()

find_previous_siblings()는 앞에 있는 모든兄弟 노드를 반환하고, find_previous_sibling()는 앞에 있는 첫 번째兄弟 노드를 반환합니다.

find_all_next() / find_next()

find_all_next()는 노드 뒤에 있는 모든 조건에 맞는 노드를 반환하고, find_next()는 조건에 맞는 첫 번째 노드를 반환합니다.

find_all_previous() / find_previous()

find_all_previous()는 노드 뒤에 있는 모든 조건에 맞는 노드를 반환하고, find_previous()는 조건에 맞는 첫 번째 노드를 반환합니다.

CSS 선택자

select()를 통해 CSS 선택자 사용 - parser.select(CSS 선택자)

sample_html ='''
<div class="card">
    <div class="card-header">
        <h3>환영합니다</h3>
    </div>
    <div class="card-body">
        - 사과
- 바나나
- 포도
        - 사과
- 바나나
    </div>
</div>
'''
from bs4 import BeautifulSoup
parser = BeautifulSoup(sample_html, 'lxml')
print(parser.select('.card .card-header'))
print(parser.select('ul li'))
print(parser.select('#items-2 .item'))
print(type(parser.select('ul')[0]))
sample_html ='''
<div class="card">
    <div class="card-header">
        <h3>환영합니다</h3>
    </div>
    <div class="card-body">
        - 사과
- 바나나
- 포도
        - 사과
- 바나나
    </div>
</div>
'''
from bs4 import BeautifulSoup
parser = BeautifulSoup(sample_html, 'lxml')
for ul in parser.select('ul'):
    print(ul.select('li'))

속성 가져오기 - 요소.attrs[] 또는 요소[]

sample_html ='''
<div class="card">
    <div class="card-header">
        <h3>환영합니다</h3>
    </div>
    <div class="card-body">
        - 사과
- 바나나
- 포도
        - 사과
- 바나나
    </div>
</div>
'''
from bs4 import BeautifulSoup
parser = BeautifulSoup(sample_html, 'lxml')
for ul in parser.select('ul'):
    print(ul['id'])
    print(ul.attrs['id'])

내용 가져오기 - get_text()

sample_html ='''
<div class="card">
    <div class="card-header">
        <h3>환영합니다</h3>
    </div>
    <div class="card-body">
        - 사과
- 바나나
- 포도
        - 사과
- 바나나
    </div>
</div>
'''
from bs4 import BeautifulSoup
parser = BeautifulSoup(sample_html, 'lxml')
for li in parser.select('li'):
    print(li.get_text())

요약

  • lxml 파싱 라이브러리 사용을 권장하며, 필요시 html.parser 사용
  • 태그 선택은 기능은 약하지만速度快
  • find(), find_all()을 사용하여 단일 또는 여러 결과 검색 권장
  • CSS 선택기에 익숙하다면 select() 사용 권장
  • 속성과 텍스트 값 가져오기常用的 메서드 기억 필수

태그: python BeautifulSoup html-parsing web-scraping lxml

7월 5일 17:23에 게시됨