BeautifulSoup는 HTML을 파싱하여 특정 요소를 탐색하고 수정할 수 있는 강력한 도구이다. 사용방법은 어렵지 않으나 매번 필요할 때마다 기능을 찾아서 적용하다 보니 정확한 사용법을 모르고 하는 듯 하여, 공식 문서를 보고 기능을 전체적으로 숙지할 필요가 있을 것 같다. 그래서 자주 사용할만한 기능의 동작방식을 이해하고 정리해 보았다.
1. 탐색
1) find & find_all
특정 태그를 찾는다. find
는 첫 번째 매칭되는 태그만, find_all
은 모두 찾는다.
사용예시
from bs4 import BeautifulSoup
html = """<div class="d1">
<div class="d2">
<span>메시지1</span>
<span>메시지2</span>
</div>
</div>
"""
soup = BeautifulSoup(html, "html.parser")
print(soup.find("span"))
print(soup.find_all("span"))
결과
<span>메시지1</span>
[<span>메시지1</span>, <span>메시지2</span>]
2) select
CSS 선택자를 사용해 요소를 찾는다.
사용예시
from bs4 import BeautifulSoup
html = """<div class="d1">
<div class="d2">
<span>메시지1</span>
<span>메시지2</span>
</div>
</div>
"""
soup = BeautifulSoup(html, "html.parser")
print(soup.select(".d2"))
결과
[<div class="d2">
<span>메시지1</span>
<span>메시지2</span>
</div>]
3) stripped_strings
HTML 요소 내부의 모든 텍스트를 공백을 제거한 상태로 하나씩 반환한다.
사용 예시
from bs4 import BeautifulSoup
html = """
<p>
Hello World!
</p>
<p>Another text</p>
"""
soup = BeautifulSoup(html, 'html.parser')
for string in soup.stripped_strings:
print(repr(string))
결과
'Hello World!'
'Another text'
4) string
요소 내에서 직접 포함된 텍스트를 반환한다. 요소가 여러 텍스트 노드를 포함하지 않는 경우에 유용하다. 주의할 점은, string
은 요소 내부에 텍스트 노드가 하나만 있을 때 사용 가능하며, 여러 텍스트가 섞여 있을 경우 None
을 반환할 수 있다.
사용 예시
from bs4 import BeautifulSoup
html = """<div class="d1">
<div class="d2">
<span>메시지1</span>
<span>메시지2</span>
</div>
</div>
"""
soup = BeautifulSoup(html, "html.parser")
print(soup.span.string)
print(soup.div.string)
결과
메시지1
None
5) find_parents
현재 태그의 모든 부모 요소를 리스트 형태로 반환한다. find_parents()
는 가장 바깥쪽의 부모까지 모두 반환한다.
사용 예시
from bs4 import BeautifulSoup
html = """<div class="d1">
<div class="d2">
<span>메시지1</span>
<span>메시지2</span>
<p>메시지3</p>
</div>
</div>
"""
soup = BeautifulSoup(html, "html.parser")
print(soup.p.find_parents())
결과
[<div class="d2">
<span>메시지1</span>
<span>메시지2</span>
<p>메시지3</p>
</div>, <div class="d1">
<div class="d2">
<span>메시지1</span>
<span>메시지2</span>
<p>메시지3</p>
</div>
</div>, <div class="d1">
<div class="d2">
<span>메시지1</span>
<span>메시지2</span>
<p>메시지3</p>
</div>
</div>
]
6) find_parent
첫 번째 부모 요소만 반환한다. find_parent()
는 가장 가까운 부모 하나만 반환한다.
사용 예시
from bs4 import BeautifulSoup
html = """<div class="d1">
<div class="d2">
<span>메시지1</span>
<span>메시지2</span>
<p>메시지3</p>
</div>
</div>
"""
soup = BeautifulSoup(html, "html.parser")
print(soup.p.find_parent())
결과
<div class="d2">
<span>메시지1</span>
<span>메시지2</span>
<p>메시지3</p>
</div>
7) find_next_siblings
현재 요소 이후에 나오는 모든 형제 요소들을 반환한다. find_next_siblings()
는 현재 태그 이후에 나오는 모든 형제를 가져온다.
사용 예시
from bs4 import BeautifulSoup
html = """<div class="d1">
<div class="d2">
<span>메시지1</span>
<span>메시지2</span>
<p>메시지 p1</p>
<p>메시지 p2</p>
<p>메시지 p3</p>
</div>
</div>
"""
soup = BeautifulSoup(html, "html.parser")
print(soup.p.find_next_siblings())
결과
[<p>메시지 p2</p>, <p>메시지 p3</p>]
8) find_previous_siblings
현재 요소 이전에 나오는 모든 형제 요소들을 반환한다. find_previous_siblings()
는 현재 태그 이전에 있는 형제 요소들을 반환한다.
사용 예시
from bs4 import BeautifulSoup
html = """<div class="d1">
<div class="d2">
<span>메시지1</span>
<span>메시지2</span>
<p>메시지 p1</p>
<p>메시지 p2</p>
<p>메시지 p3</p>
</div>
</div>
"""
soup = BeautifulSoup(html, "html.parser")
print(soup.p.find_previous_siblings())
결과
[<span>메시지2</span>, <span>메시지1</span>]
9) find_next
현재 요소 다음에 나오는 첫 번째 요소를 반환한다. find_next()
는 현재 요소 이후에 나오는 첫 번째 요소를 반환한다.
사용 예시
from bs4 import BeautifulSoup
html = """<div class="d1">
<div class="d2">
<span>메시지1</span>
<span>메시지2</span>
<p>메시지 p1</p>
<p>메시지 p2</p>
<p>메시지 p3</p>
</div>
</div>
"""
soup = BeautifulSoup(html, "html.parser")
print(soup.p.find_next())
결과
<p>메시지 p2</p>
2. 수정
1) extract
요소를 트리에서 제거하고 반환한다.
사용예시
from bs4 import BeautifulSoup
html = """
<div>
<p>Hello</p>
<p>World</p>
</div>
"""
soup = BeautifulSoup(html, "html.parser")
p_tag = soup.p.extract() # 첫 번째 <p> 요소 제거
print(soup)
결과
<div>
<p>World</p>
</div>
2) insert_before
선택한 요소 앞에 새 요소를 삽입한다.
사용예시
from bs4 import BeautifulSoup
html = """<div>
<p>World</p>
</div>
"""
soup = BeautifulSoup(html, "html.parser")
new_tag = soup.new_tag("p")
new_tag.string = "Hello"
soup.p.insert_before(new_tag)
print(soup)
결과
<div>
<p>Hello</p><p>World</p>
</div>
3) replace_with
요소를 트리에서 제거하고 반환한다.
사용예시
from bs4 import BeautifulSoup
html = """
<div class="d1">
<div class="d2">
<span>메시지1</span>
<span>메시지2</span>
</div>
</div>
"""
soup = BeautifulSoup(html, "html.parser")
soup.span.replace_with("새 메시지")
print(soup)
결과
<div class="d1">
<div class="d2">
새 메시지
<span>메시지2</span>
</div>
</div>
4) contents
요소의 직속 자식들을 리스트 형태로 반환한다.
사용예시
from bs4 import BeautifulSoup
html = """<div class="d1">
<div class="d2">
<span>메시지1</span>
<span>메시지2</span>
</div>
</div>
"""
soup = BeautifulSoup(html, "html.parser")
print(soup.div.contents)
결과
['\n', <div class="d2">
<span>메시지1</span>
<span>메시지2</span>
</div>, '\n']
5) unwrap
요소를 제거하고 그 내부 내용을 상위 요소에 병합한다.
사용예시
from bs4 import BeautifulSoup
html = """<div class="d1">
<div class="d2">
<span>메시지1</span>
<span>메시지2</span>
</div>
</div>
"""
soup = BeautifulSoup(html, "html.parser")
soup.span.unwrap()
print(soup)
결과
<div class="d1">
<div class="d2">
메시지1
<span>메시지2</span>
</div>
</div>
6) decompose
요소를 트리에서 제거하고 완전히 삭제한다.
사용예시
from bs4 import BeautifulSoup
html = """<div class="d1">
<div class="d2">
<span>메시지1</span>
<span>메시지2</span>
</div>
</div>
"""
soup = BeautifulSoup(html, "html.parser")
soup.span.decompose()
print(soup)
결과
<div class="d1">
<div class="d2">
<span>메시지2</span>
</div>
</div>
7) append
기존 요소의 자식으로 새 요소를 추가한다. append
는 기존 태그의 마지막 자식 요소로 새 요소를 추가할 때 유용하다.
사용예시
from bs4 import BeautifulSoup
html = """<div class="d1">
<div class="d2">
<span>메시지1</span>
<span>메시지2</span>
</div>
</div>
"""
soup = BeautifulSoup(html, "html.parser")
new_tag = soup.new_tag("span")
new_tag.string = "메시지3"
soup.span.append(new_tag)
print(soup)
결과
<div class="d1">
<div class="d2">
<span>메시지1<span>메시지3</span></span>
<span>메시지2</span>
</div>
</div>
8) extend
여러 요소를 한 번에 추가할 때 사용되며, append
와 유사하지만 리스트나 여러 요소를 한꺼번에 추가할 수 있다.
사용예시
from bs4 import BeautifulSoup
html = """<div class="d1">
<div class="d2">
<span>메시지1</span>
<span>메시지2</span>
</div>
</div>
"""
soup = BeautifulSoup(html, "html.parser")
new_tag1 = soup.new_tag("p")
new_tag1.string = "First"
new_tag2 = soup.new_tag("p")
new_tag2.string = "Second"
soup.span.extend([new_tag1, new_tag2])
print(soup)
결과
<div class="d1">
<div class="d2">
<span>메시지1<p>First</p><p>Second</p></span>
<span>메시지2</span>
</div>
</div>
9) clear
요소의 모든 자식들을 제거한다. clear
는 요소 내부를 비울 때 유용하다.
사용예시
from bs4 import BeautifulSoup
html = """<div class="d1">
<div class="d2">
<span>메시지1</span>
<span>메시지2</span>
</div>
</div>
"""
soup = BeautifulSoup(html, "html.parser")
soup.span.clear()
print(soup)
결과
<div class="d1">
<div class="d2">
<span></span>
<span>메시지2</span>
</div>
</div>