새소식

반응형
Toy Project/Crawler

[Crawler] 파이썬 웹 크롤링(기본편) 2 - beautifulsoup

  • -
반응형

파이썬 로고 이미지입니다.
파이썬

파이썬 웹 크롤링(기본 편) 2 - beautifulsoup


BeautifulSoup은 HTML 및 XML 문서를 파싱 하고, 문서의 특정 부분에서 데이터를 추출하는 데 사용되는 파이썬 라이브러리이다. 이를 통해 웹 스크레이핑과 같은 작업을 수행할 수 있다. 주로 웹 페이지에서 원하는 정보를 추출하기 위해 사용된다. 또한, HTML 또는 XML 문서를 구문 분석하고, 해당 문서의 요소에 쉽게 접근할 수 있는 메서드와 속성을 제공한다. 이를 통해 사용자는 원하는 정보를 추출하거나 문서의 구조를 탐색하는 작업을 편리하게 수행할 수 있다.

 

pip install beautifulsoup4

위의 명령어를 입력하여 beautifulsoup 라이브러리를 설치할 수 있다.

 

설치가 완료되었다면 간단한 예제 코드로 beaitifulsoup의 사용법을 한 번 살펴보자.

import requests
from bs4 import BeautifulSoup

# naver 서버에 대화를 시도
response = requests.get("http://www.naver.com/")

# naver 에서 html 응답
html = response.text

# html 번역
soup = BeautifulSoup(html, 'html.parser')

# id값이 shortcutArea인 요소 1개를 가져옴
word = soup.select_one("#shortcutArea")
print(word)

requests 라이브러리를 사용하여 Naver의 웹 페이지에 HTTP GET 요청을 보내고, 받은 응답을 BeautifulSoup을 사용하여 파싱 하는 과정을 나타내는 예제 코드이다.

 

<div class="shortcut_area" id="shortcutArea" role="region"></div>

실행 결과

 

  • response = requests.get("http://www.naver.com/") - Naver의 웹 페이지에 GET 요청을 보내고, 서버에서의 응답을 response 변수에 저장한다.
  • html = request.text - 서버로부터 받은 응답 중 HTML 내용을 text 속성을 통해 추출하여 html 변수에 저장한다.
  • soup = BeautifulSoup(html, 'html.parser') - BeautifulSoup을 사용하여 HTML 문서를 파싱 한다. 첫 번째 파라미터로는 파싱 할 HTML 문서(위의 예제에서는 html 변수), 두 번째 파라미터로는 파서의 종류를 지정한다. 여기서는 기본 파서로 'html.parser'를 사용하였다.
  • word = soup.select_one("#shortcutArea") - soup 객체를 사용하여 CSS 선택자를 활용해 원하는 요소를 선택한다. 여기서는 id가 "shortcutArea"인 요소를 선택하고, 이를 word 변수에 저장한다.
  • print(word) - 선택한 요소를 출력한다.

종합하면, 이 코드는 Naver의 웹 페이지에서 id가 "shortcutArea"인 요소를 찾아서 출력하는 간단한 예제이다. CSS 선택자를 사용하여 특정 요소를 선택하는 방법을 익히고, 해당 요소의 내용이나 속성을 추출하는 기본적인 스크레이핑 작업을 수행하고 있다.(📣 Naver 페이지의 구성요소가 변경되어 위의 요소가 이 글을 보고 따라 하시는 독자분들에겐 없을 수 도 있다는 첨 참고 부탁한다.)

 

이젠 beautifulsoup의 주요 메서드는 어떤 것들이 있는지 한 번 알아보자.

 

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

  • name - 태그의 이름이나 태그 이름의 리스트를 지정한다.
  • attrs - 속성과 값으로 이루어진 딕셔너리를 지정하여 해당 속성을 가진 태그를 검색한다.
  • recursive - 자식 요소만 탐색할지, 모든 자손 요소를 탐색할지를 결정한다.
  • string - 태그의 텍스트를 검색한다.
  • **kwargs - 기타 추가적인 속성을 지정할 수 있다.
import requests
from bs4 import BeautifulSoup

# HTML 예시
html_content = """
<html>
    <body>
        <div class="content">
            <h1>Main Title</h1>
            <p>Paragraph 1</p>
            <p>Paragraph 2</p>
            <ul>
                <li>Item 1</li>
                <li>Item 2</li>
            </ul>
        </div>
        <div class="sidebar">
            <h2>Sidebar Title</h2>
            <p>Additional information</p>
        </div>
    </body>
</html>
"""

# BeautifulSoup 객체 생성
soup = BeautifulSoup(html_content, 'html.parser')

# find 메서드를 사용하여 특정 태그를 찾기
title_tag = soup.find('h1')  # 태그 이름으로 찾기
paragraph_tag = soup.find('p', class_ = 'content')  # 클래스 속성으로 찾기
item_tag = soup.find('li', {'class': 'item', 'id': 'item2'})  # 여러 속성으로 찾기

# 결과 출력
print("Title :", title_tag.text if title_tag else "Not Found")
print("Paragraph :", paragraph_tag.text if paragraph_tag else "Not Found")
print("Item :", item_tag.text if item_tag else "Not Found")
Title : Main Title
Paragraph : Not Found
Item : Not Found

실행 결과

 

 

find_all(name, attrs, recursive, string, limit, **kwargs)

  • limit - 검색 결과의 최대 개수를 제한한다.
  • (나머지는 find() 함수와 동일)
import requests
from bs4 import BeautifulSoup

# HTML 예시
html_content = """
<html>
    <body>
        <div class="content">
            <h1>Main Title</h1>
            <p>Paragraph 1</p>
            <p>Paragraph 2</p>
            <ul>
                <li>Item 1</li>
                <li>Item 2</li>
            </ul>
        </div>
        <div class="content">
            <h2>Secondary Title</h2>
            <p>Another paragraph</p>
        </div>
    </body>
</html>
"""

# BeautifulSoup 객체 생성
soup = BeautifulSoup(html_content, 'html.parser')

# find_all 메서드를 사용하여 특정 태그 모두 찾기
paragraphs = soup.find_all('p')  # 모든 <p> 태그 찾기
content_divs = soup.find_all('div', class_ = 'content')  # 클래스 속성으로 찾기

# 결과 출력
print("Paragraphs : ")
for paragraph in paragraphs:
    print(paragraph.text)

print("\nContent Divs : ")
for div in content_divs:
    print(div.text)
Paragraphs :
Paragraph 1      
Paragraph 2      
Another paragraph

Content Divs :   

Main Title       
Paragraph 1      
Paragraph 2      

Item 1
Item 2



Secondary Title  
Another paragraph

실행 결과

 

 

select(css_selector)

  • CSS 선택자를 사용하여 요소를 선택한다.
  • 반환값은 리스트이며, 선택한 모든 요소가 포함된다.
import requests
from bs4 import BeautifulSoup

# HTML 예시
html_content = """
<html>
    <body>
        <div id="main-content">
            <h1>Main Title</h1>
            <p class="paragraph">Paragraph 1</p>
            <p class="paragraph">Paragraph 2</p>
            <ul>
                <li>Item 1</li>
                <li>Item 2</li>
            </ul>
        </div>
        <div id="secondary-content">
            <h2>Secondary Title</h2>
            <p class="paragraph">Another paragraph</p>
        </div>
    </body>
</html>
"""

# BeautifulSoup 객체 생성
soup = BeautifulSoup(html_content, 'html.parser')

# select 메서드를 사용하여 CSS 선택자로 요소 선택
main_title = soup.select('#main-content h1')  # id가 'main-content'인 div 안의 h1 태그
paragraphs = soup.select('.paragraph')  # class가 'paragraph'인 모든 p 태그
secondary_title = soup.select('#secondary-content h2')  # id가 'secondary-content'인 div 안의 h2 태그

# 결과 출력
print("Main Title :", main_title[0].text)
print("\nParagraphs :")
for paragraph in paragraphs:
    print(paragraph.text)
print("\nSecondary Title :", secondary_title[0].text)
Main Title : Main Title

Paragraphs :
Paragraph 1
Paragraph 2
Another paragraph

Secondary Title : Secondary Title

실행 결과

 


prettify()

  • 파싱 된 문서를 예쁘게 출력한다. 들여 쓰기와 줄 바꿈을 추가하여 가독성을 높인다.
import requests
from bs4 import BeautifulSoup

# HTML 예시
html_content = """
<html>
    <head>
        <title>Sample Page</title>
    </head>
    <body>
        <div id="main-content">
            <h1>Main Title</h1>
            <p class="paragraph">Paragraph 1</p>
            <p class="paragraph">Paragraph 2</p>
        </div>
    </body>
</html>
"""

# BeautifulSoup 객체 생성
soup = BeautifulSoup(html_content, 'html.parser')

# prettify 메서드를 사용하여 HTML을 정리된 형태로 출력
pretty_html = soup.prettify()

# 결과 출력
print(pretty_html)
<html>
 <head>
  <title>
   Sample Page
  </title>
 </head>
 <body>
  <div id="main-content">
   <h1>
    Main Title
   </h1>
   <p class="paragraph"> 
    Paragraph 1
   </p>
   <p class="paragraph"> 
    Paragraph 2
   </p>
  </div>
 </body>
</html>

실행 결과

 

 

get_text(separator, strip)

  • 현재 선택한 요소의 텍스트를 추출한다.
  • separator - 각 요소의 텍스트를 구분하는 문자열을 지정한다.
  • strip - 공백을 제거할지 여부를 결정한다.
import requests
from bs4 import BeautifulSoup

# HTML 예시
html_content = """
<html>
    <head>
        <title>Sample Page</title>
    </head>
    <body>
        <div id="main-content">
            <h1>Main Title</h1>
            <p class="paragraph">Paragraph 1</p>
            <p class="paragraph">Paragraph 2</p>
        </div>
    </body>
</html>
"""

# BeautifulSoup 객체 생성
soup = BeautifulSoup(html_content, 'html.parser')

# get_text 메서드를 사용하여 텍스트 추출 (기본값)
text_default = soup.get_text()
print("Default Separator:")
print(text_default)

# get_text 메서드를 사용하여 텍스트 추출 (separator 지정)
text_with_separator = soup.get_text(separator = ' | ')
print("\nCustom Separator : ")
print(text_with_separator)

# get_text 메서드를 사용하여 텍스트 추출 (strip 적용)
text_with_strip = soup.get_text(strip = True)
print("\nWith Strip : ")
print(text_with_strip)

Sample Page        



Main Title
Paragraph 1        
Paragraph 2        





Custom Separator : 

 | 
 |
 | Sample Page |
 |
 |
 |
 | Main Title |
 | Paragraph 1 |
 | Paragraph 2 |
 |
 |
 |


With Strip :
Sample PageMain TitleParagraph 1Paragraph 2

실행 결과

 

 

find_parent(name, attrs, **kwargs)

  • name - 찾을 부모 요소의 이름을 지정한다. 문자열이나 정규표현식을 사용할 수 있다.
  • attrs - 찾을 부모 요소의 속성과 값을 딕셔너리로 지정한다.
  • **kwargs - 다양한 검색 조건을 키워드 인수로 추가할 수 있다.
from bs4 import BeautifulSoup

html_content = """
<html>
    <head>
        <title>Sample Page</title>
    </head>
    <body>
        <div id="main-content">
            <h1>Main Title</h1>
            <p class="paragraph">Paragraph 1</p>
            <p class="paragraph">Paragraph 2</p>
        </div>
    </body>
</html>
"""

soup = BeautifulSoup(html_content, 'html.parser')

# class가 'paragraph'인 p 요소의 부모를 찾음
parent_of_paragraph = soup.find("p", class_ = "paragraph").find_parent()
print("Parent Element :")
print(parent_of_paragraph)

# id가 'main-content'인 div 요소의 부모를 찾음 (존재하지 않음)
nonexistent_parent = soup.find("div", id = "main-content").find_parent()
print("\nNonexistent Parent Element :")
print(nonexistent_parent)
Parent Element :
<div id="main-content">
<h1>Main Title</h1>
<p class="paragraph">Paragraph 1</p>
<p class="paragraph">Paragraph 2</p>
</div>

Nonexistent Parent Element :        
<body>
<div id="main-content">
<h1>Main Title</h1>
<p class="paragraph">Paragraph 1</p>
<p class="paragraph">Paragraph 2</p>
</div>
</body>

실행 결과

 

 

find_previous_sibling(name, attrs, **kwargs)

  • name - 찾을 이전 형제 요소의 이름을 지정한다. 문자열이나 정규표현식을 사용할 수 있다.
  • attrs - 찾을 이전 형제 요소의 속성과 값을 딕셔너리로 지정한다.
  • **kwargs - 다양한 검색 조건을 키워드 인수로 추가할 수 있다.
from bs4 import BeautifulSoup

html_content = """
<html>
    <head>
        <title>Sample Page</title>
    </head>
    <body>
        <div id="main-content">
            <h1>Main Title</h1>
            <p class="paragraph">Paragraph 1</p>
            <p class="paragraph">Paragraph 2</p>
            <span>Span Element</span>
        </div>
    </body>
</html>
"""

soup = BeautifulSoup(html_content, 'html.parser')

# class가 'paragraph'인 p 요소의 이전 형제를 찾음
previous_sibling_of_paragraph = soup.find("p", class_= "paragraph").find_previous_sibling()
print("Previous Sibling Element : ")
print(previous_sibling_of_paragraph)

# span 요소의 이전 형제를 찾음
previous_sibling_of_span = soup.find("span").find_previous_sibling()
print("\nPrevious Sibling Element of Span : ")
print(previous_sibling_of_span)
Previous Sibling Element :
<h1>Main Title</h1>

Previous Sibling Element of Span :  
<p class="paragraph">Paragraph 2</p>

실행 결과

 

 

has_attr(name)

  • 현재 태그가 지정된 속성을 가지고 있는지 확인한다.
from bs4 import BeautifulSoup

html_content = """
<html>
    <head>
        <title>Sample Page</title>
    </head>
    <body>
        <div id="main-content">
            <h1>Main Title</h1>
            <p class="paragraph">Paragraph 1</p>
            <p class="paragraph" custom_attr="example">Paragraph 2</p>
            <span>Span Element</span>
        </div>
    </body>
</html>
"""

soup = BeautifulSoup(html_content, 'html.parser')

# class가 'paragraph'인 p 요소가 custom_attr 속성을 가지고 있는지 확인
paragraph_with_attr = soup.find("p", class_="paragraph")
if paragraph_with_attr.has_attr("custom_attr"):
    print(f"{paragraph_with_attr} has 'custom_attr' attribute.")
else:
    print(f"{paragraph_with_attr} does not have 'custom_attr' attribute.")
<p class="paragraph">Paragraph 1</p> does not have 'custom_attr' attribute.

실행 결과

 

 

 

728x90
반응형
Contents

포스팅 주소를 복사했습니다

이 글이 도움이 되었다면 공감 부탁드립니다.