[데이터 분석 심화 개념] 웹 자동화 개념 정리 4️⃣ (Beautifulsoup)
이번 글은 코드잇 강의를 수강하면서 배운 내용을 주로 하여 정리되어 있습니다. (코드잇 스프린트 데이터 애널리스트 트랙 1기 훈련생)
웹에서 데이터 얻기(Beautifulsoup)
크롬 개발자 도구
크롬 개발자 도구(Chrome Developer Tools)는 웹 개발자들이 웹 페이지를 분석하고 디버깅하는 데 사용하는 도구입니다.
이 도구는 웹 페이지의 구조, 스타일, 네트워크 요청 등을 실시간으로 확인하고 수정할 수 있도록 도와줍니다.
개발자 도구를 사용하면 웹 페이지가 어떻게 구성되어 있는지, 그리고 각 요소가 어떻게 스타일링되고 동작하는지 이해할 수 있습니다.
개발자 도구 사용법
- Windows : 웹 페이지에서 마우스 오른쪽 버튼을 클릭한 후 "검사"를 선택하거나, 키보드에서 F12 키를 눌러 개발자 도구를 열 수 있습니다.
- Mac : 웹 페이지에서 마우스 오른쪽 버튼을 클릭한 후 "검사"를 선택하거나, 키보드에서 Command + Option + I 키를 눌러 개발자 도구를 열 수 있습니다.
Elements 탭이란?
크롬 개발자 도구의 "Elements" 탭은 웹 페이지의 HTML 구조와 CSS 스타일을 실시간으로 확인하고 수정할 수 있는 곳입니다. 웹 페이지의 모든 요소를 검사하고 편집할 수 있어서, 디자인이나 레이아웃을 조정할 때 매우 유용합니다.
Elements 탭의 주요 기능
- HTML 구조 보기:
- Elements 탭에서는 웹 페이지의 HTML을 트리 구조로 보여줍니다. 각 HTML 태그는 하나의 노드로 표시되며, 이 노드를 클릭하면 그 안에 포함된 하위 요소들을 볼 수 있습니다.
- 이 트리를 통해 페이지의 어떤 부분이 어떤 HTML 코드로 구성되어 있는지 쉽게 확인할 수 있습니다.
- CSS 스타일 확인 및 변경:
- 특정 HTML 요소를 클릭하면, 그 요소에 적용된 CSS 스타일이 화면 오른쪽에 표시됩니다. 이 스타일을 직접 수정할 수도 있는데, 이렇게 수정한 내용은 페이지에 즉시 반영됩니다. 예를 들어, 버튼의 색상을 바꾸거나 글자 크기를 조정하는 등의 작업을 할 수 있습니다.
- 실시간 편집:
- HTML 요소나 CSS 스타일을 바로 수정해 볼 수 있습니다. 페이지의 구조나 디자인을 실험하면서 원하는 결과가 나올 때까지 조정할 수 있습니다. 이렇게 하면 브라우저에서 바로 변경 결과를 확인할 수 있기 때문에 매우 직관적입니다.
- 요소 선택:
- 개발자 도구의 왼쪽 상단에 있는 선택 도구(화살표 아이콘)를 사용하면, 웹 페이지에서 직접 요소를 클릭해 선택할 수 있습니다. 예를 들어, 웹 페이지에서 특정 버튼을 클릭하면, 그 버튼이 HTML 구조에서 어디에 있는지 자동으로 찾아줍니다.
개발자 도구를 사용하는 이유
- 디버깅: 웹 페이지가 예상대로 동작하지 않을 때, 문제를 찾아 수정할 수 있습니다.
- 디자인 수정: 페이지의 디자인을 실시간으로 조정하고, CSS 코드를 변경해 볼 수 있습니다.
- 학습: 웹 페이지가 어떻게 구성되어 있는지 배우고, 다른 웹 사이트의 디자인이나 코드를 분석하는 데 유용합니다.
Beautiful soup 라이브러리
Beautiful Soup은 파이썬에서 HTML 및 XML 파일을 파싱(parsing)하는 데 사용되는 매우 인기 있는 라이브러리입니다. 웹 스크래핑(web scraping) 작업에서 자주 사용되며, 웹 페이지에서 데이터를 추출하는 과정을 쉽게 도와줍니다.
Beautiful Soup의 주요 기능
- HTML/XML 파싱: Beautiful Soup은 HTML과 XML 문서를 파싱하여 태그, 속성, 텍스트 등을 쉽게 다룰 수 있도록 도와줍니다.
- 태그 탐색 및 검색: 특정 태그나 속성, 텍스트를 기준으로 원하는 요소를 검색하고 탐색할 수 있습니다.
- 트리 구조 탐색: HTML 문서는 트리 구조로 되어 있으며, Beautiful Soup은 부모-자식 관계, 형제 관계 등을 통해 트리를 쉽게 탐색할 수 있습니다.
- 데이터 수정: 파싱한 HTML 문서에서 데이터를 추출할 뿐만 아니라, 특정 요소를 수정하거나 삭제할 수도 있습니다.
Beautiful Soup 설치
Beautiful Soup은 pip을 사용하여 설치할 수 있습니다.
pip install beautifulsoup4
추가적으로, HTML 파싱을 위해 lxml 또는 html.parser를 사용할 수 있습니다.
lxml을 사용하려면 아래와 같이 추가 패키지를 설치해야 합니다.
pip install lxml
Beautiful Soup 기본 사용법
밑의 예시는 BeautifulSoup라이브러리를 불러와 간단한 웹 페이지를 파싱하고 데이터를 추출하는 내용을 설명하고 있습니다.
from bs4 import BeautifulSoup
# 예제 HTML
html_doc = """
<html>
<head><title>The Dormouse's story</title></head>
<body>
<h1>This is a heading</h1>
<p class="title"><b>The Dormouse's story</b></p>
<p class="story">Once upon a time there were three little sisters; and their names were
<a href="http://example.com/elsie" class="sister" id="link1">Elsie</a>,
<a href="http://example.com/lacie" class="sister" id="link2">Lacie</a> and
<a href="http://example.com/tillie" class="sister" id="link3">Tillie</a>;
and they lived at the bottom of a well.</p>
<p class="story">...</p>
</body>
</html>
"""
# Beautiful Soup 객체 생성
soup = BeautifulSoup(html_doc, 'html.parser')
# HTML의 title 태그 가져오기
print(soup.title)
# 혹은 title이라는 태그가 있다면 밑 방법으로도 title 태그를 가져올 수 있음
print(soup.select('title'))
# title 태그의 텍스트 가져오기
print(soup.title.string)
# 첫 번째 p 태그 가져오기
print(soup.p)
# 모든 a 태그 가져오기
for link in soup.find_all('a'):
print(link.get('href'))
# 특정 id를 가진 태그 가져오기
print(soup.find(id="link2").string)
주요 메소드 및 속성
- soup.title: <title> 태그를 반환합니다.
- soup.title.string: <title> 태그 내의 텍스트를 반환합니다.
- soup.find_all(name, attrs, recursive, string, limit, **kwargs): 주어진 조건에 맞는 모든 태그를 리스트로 반환합니다.
- soup.find(name, attrs, recursive, string, **kwargs): 주어진 조건에 맞는 첫 번째 태그를 반환합니다.
- soup.get_text(): 문서 내의 모든 텍스트를 하나의 문자열로 반환합니다.
- soup.get('속성명'): 특정 태그의 속성 값을 가져옵니다.
원하는 태그 선택하기 : 태그 선택 방법
- 태그 이름으로 선택하기
특정 태그 이름을 사용하여 해당 태그를 선택할 수 있습니다. soup.find()는 첫 번째로 발견된 태그를 반환하고, soup.find_all()은 모든 해당 태그를 리스트로 반환합니다.
# 첫 번째 <p> 태그 선택
first_p_tag = soup.find('p')
# 모든 <a> 태그 선택
all_a_tags = soup.find_all('a')
- 속성을 사용해 선택하기
태그의 속성(예: id, class, name, href 등)을 기준으로 특정 태그를 선택할 수 있습니다.
# id가 'link1'인 태그 선택
tag_with_id = soup.find(id='link1')
# class가 'sister'인 모든 <a> 태그 선택
tags_with_class = soup.find_all('a', class_='sister')
# 특정 속성을 가진 태그 선택
tag_with_attrs = soup.find('a', attrs={'href': '<http://example.com/elsie>'})
- CSS 선택자를 사용해 선택하기
CSS 선택자를 이용하면 더욱 정교하게 태그를 선택할 수 있습니다. select() 메서드를 사용하면 CSS 선택자와 유사하게 태그를 선택할 수 있습니다.
# 모든 <a> 태그 중 class가 'sister'인 것 선택
css_selected_tags = soup.select('a.sister')
# id가 'link1'인 태그 선택
css_selected_tag = soup.select_one('#link1')
- 계층 구조를 따라 선택하기
HTML 문서는 계층 구조를 이루고 있으므로, 특정 태그의 부모, 자식, 형제 태그를 선택할 수 있습니다.
# <p> 태그 안의 <b> 태그 선택
parent_tag = soup.find('p')
b_tag = parent_tag.find('b')
# 첫 번째 <a> 태그의 다음 형제 태그 선택
first_a_tag = soup.find('a')
next_sibling = first_a_tag.find_next_sibling('a')
- 텍스트 내용을 기준으로 선택하기
태그의 텍스트 내용 자체를 기준으로 태그를 선택할 수 있습니다. 이 때 string, text 파라미터를 사용합니다.
# 텍스트가 'Elsie'인 태그 선택
tag_with_text = soup.find('a', string='Elsie')
# 특정 텍스트 패턴을 포함하는 태그 선택 (정규 표현식 사용 가능)
import re
tag_with_regex = soup.find('a', string=re.compile(r'El'))
예제: 뉴스 기사 제목 및 링크 추출
밑은 웹 페이지에서 뉴스 기사 제목과 링크를 추출하는 예시입니다.
from bs4 import BeautifulSoup
import requests
# 웹 페이지 가져오기
url = "<http://example.com/news>"
response = requests.get(url)
soup = BeautifulSoup(response.content, 'html.parser')
# 뉴스 기사 제목과 링크 추출
articles = soup.find_all('h2', class_='title')
for article in articles:
title = article.get_text()
link = article.find('a')['href']
print(f"Title: {title}")
print(f"Link: {link}")
find 와 find_all 메소드
Beautiful Soup에는 필요한 태그를 선택하는 방법이 크게 .select() 메소드를 활용하는 방법과.find() 메소드를 활용하는 방법 두가지가 있습니다.
두 방법 모두 다 기능이 비슷하기 때문에 둘 중 하나만 알아도 무방하기 때문에 이번 목차에서는 find 와 find_all 메소드에 대해 설명하도록 하겠습니다.
find와 find_all 메소드는 웹 스크래핑에서 HTML 문서를 탐색하는 데 사용되는 Python의 BeautifulSoup 라이브러리의 중요한 메소드입니다.
find() 메소드는 select_one()과 비슷하고, find_all()메소드는 select()와 비슷합니다.
find()는 매칭되는 태그를 (최대) 하나만 가져오는데 쓰이고 find_all()은 매칭되는 태그를 모두 가져오는데 쓰이고 있습니다.(리턴값의 형식도 똑같다.)
find()는 태그 자체나 None을 리턴하고 find_all()은 리스트를 리턴합니다.
BeautifulSoup 기본 설정
먼저 BeautifulSoup을 사용하려면 HTML 문서를 파싱해야 합니다. 이를 위해 BeautifulSoup 객체를 생성합니다.
from bs4 import BeautifulSoup
html_content = """<html><body><h1>Title</h1><p class='content'>First paragraph.</p><p class='content'>Second paragraph.</p></body></html>"""
soup = BeautifulSoup(html_content, 'html.parser')
find 메소드
find 메소드는 HTML에서 첫 번째로 일치하는 태그를 반환합니다. 특정 태그, 클래스, ID 등을 기준으로 검색할 수 있습니다.
- 태그로 찾기:
first_paragraph = soup.find('p')
print(first_paragraph)
위 코드는 첫 번째 <p> 태그를 반환합니다.
- 클래스로 찾기:
first_content = soup.find('p', class_='content')
print(first_content)
위 코드는 클래스가 content인 첫 번째 <p> 태그를 반환합니다.
- ID로 찾기:
first_title = soup.find('h1')
print(first_title)
위 코드는 첫 번째 <h1> 태그를 반환합니다.
find_all 메소드
find_all 메소드는 HTML에서 모든 일치하는 태그를 리스트 형태로 반환합니다. find와 마찬가지로 특정 태그, 클래스, ID 등을 기준으로 검색할 수 있습니다.
- 태그로 찾기:
all_paragraphs = soup.find_all('p')
print(all_paragraphs)
위 코드는 모든 <p> 태그를 리스트로 반환합니다.
- 클래스로 찾기:
all_content = soup.find_all('p', class_='content')
print(all_content)
위 코드는 클래스가 content인 모든 <p> 태그를 리스트로 반환합니다.
- 여러 태그로 찾기:
all_links_and_paragraphs = soup.find_all(['p', 'a'])
print(all_links_and_paragraphs)
위 코드는 <p> 태그와 <a> 태그를 모두 리스트로 반환합니다.
- 모든 태그 가져오기:
all_tags = soup.find_all(True)
print(all_tags)
위 코드는 HTML 문서의 모든 태그를 리스트로 반환합니다.
속성 사용
태그를 찾을 때 특정 속성을 기준으로 필터링할 수도 있습니다. 이때 속성 이름과 속성 값을 함께 지정해 줍니다.
filtered_paragraphs = soup.find_all('p', id="some-id", class_="some-class")
print(filtered_paragraphs)
위 코드는 id가 "some-id"이고, class가 "some-class"인 모든 <p> 태그를 리스트로 반환합니다.
속성만을 이용해 태그를 필터링할 수도 있습니다. 이 경우 태그 이름을 생략하고 속성만 지정하면 됩니다.
filtered_tags = soup.find_all(id="some-id", class_="some-class")
print(filtered_tags)
위 코드는 id가 "some-id"이고, class가 "some-class"인 모든 태그를 리스트로 반환합니다.
또한, 특정 속성이 존재하는지 여부로 필터링할 수도 있습니다. 속성 값 대신 True 또는 False를 사용하면 됩니다.
filtered_paragraphs = soup.find_all('p', id=True, class_=False)
print(filtered_paragraphs)
위 코드는 id 속성은 있지만 class 속성은 없는 모든 <p> 태그를 반환합니다.
중첩 태그 탐색
find와 find_all 메소드는 중첩 태그에 대한 문법을 별도로 제공하지 않지만, 태그 내에 중첩된 태그를 찾기 위해 메소드 체이닝을 사용할 수 있습니다.
div_tag = soup.find('div', class_='some-class')
nested_paragraphs = div_tag.find_all('p')
print(nested_paragraphs)
위 코드는 클래스가 "some-class"인 <div> 태그 내부의 모든 <p> 태그를 반환합니다.
또는 CSS 선택자를 사용하여 중첩된 태그를 한 번에 선택할 수도 있습니다.
nested_paragraphs = soup.select('div.some-class p')
print(nested_paragraphs)
위 코드는 클래스가 "some-class"인 <div> 태그 내부의 모든 <p> 태그를 CSS 선택자를 사용해 한 번에 반환합니다.
차이점
- find: 첫 번째 일치하는 요소를 반환합니다.
- find_all: 모든 일치하는 요소를 리스트로 반환합니다.
이 두 메소드는 웹 페이지에서 원하는 정보를 효율적으로 추출하는 데 유용합니다. 작은 차이점이 있지만, 올바르게 사용하면 필요한 데이터를 효과적으로 얻을 수 있습니다.
위에서 설명한 내용을 바탕으로, 웹 개발자나 데이터 분석가들이 웹 페이지의 구조를 이해하고, 원하는 데이터를 효율적으로 추출할 수 있는 방법을 배울 수 있습니다. 크롬 개발자 도구를 통해 웹 페이지의 HTML과 CSS 구조를 분석하고, Beautiful Soup 라이브러리를 활용해 필요한 정보를 손쉽게 스크래핑할 수 있습니다. 이러한 기술들은 웹 크롤링과 데이터 분석에 필수적이며, 이를 통해 다양한 데이터를 수집하고 분석하는 데 있어 강력한 도구로 활용될 수 있습니다.
감사합니다!
출처 및 참고자료 : 코드잇 사이트 강의 '웹 자동화' https://www.codeit.kr/topics/web-automation