Web Scraping & Bots · 강의

복잡한 HTML 구조 탐색

깊게 중첩되었거나 불규칙한 구조의 HTML 문서를 효과적으로 순회하는 기법을 학습합니다.

레슨 1/411개 단계

복잡한 HTML 구조 탐색은(는) CoddyKit의 무료 Web Scraping & Bots 강의입니다. 이것은 4개 중 1번째 강의입니다. 아래에서 전체 강의를 무료로 읽을 수 있으며, 내장 코드 에디터와 24/7 AI 튜터와 함께 브라우저에서 직접 실습할 수 있습니다. 이 강의는 Web Scraping & Bots 학습 경로의 일부이며, 진행 상황이 웹과 CoddyKit 앱에 동기화됩니다. Web Scraping & Bots 강의에는 총 4개의 강의가 포함되어 있습니다.

이 강의의 일부는 아직 번역되지 않았으며 영어로 표시됩니다.

Beyond Simple Extraction

What happens when the data you need isn't neatly tucked into an element with a unique ID or class? Sometimes, web pages have complex layouts that require a more sophisticated approach.

In this lesson, we'll learn how to "walk" through the HTML structure, finding elements based on their relationships to others. This technique is called HTML tree traversal.

The HTML Tree Structure

Think of an HTML document like a family tree. Every element (like a <div>, <p>, or <h1>) is a "node."

  • Parent: An element that contains other elements.
  • Child: An element directly inside another element.
  • Sibling: Elements at the same level, sharing the same parent.
  • Descendant: Any element inside a parent, directly or indirectly.

Understanding these relationships is key to navigating complex pages.

Children: Direct Descendants

To get the direct children of an element, BeautifulSoup offers a couple of ways. The .contents property returns a list of all children, including NavigableStrings (text nodes).

The .children property returns an iterator, which is often more memory-efficient for large documents. Let's see an example.

from bs4 import BeautifulSoup

html_doc = """
<div class="parent">
  <p>Child 1</p>
  <span>Child 2</span>
  Text node
</div>
"""
soup = BeautifulSoup(html_doc, 'html.parser')
parent_div = soup.find('div', class_='parent')

print("Using .contents:")
for child in parent_div.contents:
  print(f"- {child.name or 'Text'}: {repr(child)[:20]}...")

print("\nUsing .children:")
for child in parent_div.children:
  print(f"- {child.name or 'Text'}: {repr(child)[:20]}...")

Moving Up: Parents

Sometimes you find an element, but need information from its containing element. BeautifulSoup allows you to easily move "up" the tree.

  • The .parent property gives you the direct parent of an element.
  • The .parents property gives you an iterator for all ancestor elements, all the way up to the document root.
from bs4 import BeautifulSoup

html_doc = """
<div class="grandparent">
  <div class="parent">
    <p class="child">Hello</p>
  </div>
</div>
"""
soup = BeautifulSoup(html_doc, 'html.parser')
child_p = soup.find('p', class_='child')

print(f"Child: {child_p.name}")
print(f"Direct Parent: {child_p.parent.name}")

print("All Ancestors:")
for p in child_p.parents:
  if p.name: # Filter out [document] and other non-tag elements
    print(f"- {p.name}")

Side-by-Side: Single Siblings

Elements at the same level are called siblings. You can move between them using .next_sibling and .previous_sibling.

Be aware that these properties will also include "NavigableString" objects if there's whitespace or text directly between your tags. You might need to check if the result is a tag.

from bs4 import BeautifulSoup

html_doc = """
<div class="items">
  <p>Item 1</p>
  <span>Item 2</span>
  <p>Item 3</p>
</div>
"""
soup = BeautifulSoup(html_doc, 'html.parser')
item_one = soup.find('p', string='Item 1')

# The next sibling after <p>Item 1</p> is usually a newline character (NavigableString)
# We need to find the *next tag* sibling
next_tag = item_one.next_sibling
while next_tag and not next_tag.name:
    next_tag = next_tag.next_sibling

print(f"Item 1: {item_one.text}")
if next_tag:
  print(f"Next tag sibling: {next_tag.text}")
else:
  print("No next tag sibling found.")

All Siblings: next_siblings

To get all the siblings that come after or before a particular tag, you can use the .next_siblings and .previous_siblings iterators.

This is extremely useful when you've found one element and need to extract data from all related elements at the same level.

from bs4 import BeautifulSoup

html_doc = """
<div class="menu">
  <a href="#home">Home</a>
  <a href="#about">About</a>
  <a href="#contact">Contact</a>
</div>
"""
soup = BeautifulSoup(html_doc, 'html.parser')
home_link = soup.find('a', href='#home')

print("All next siblings after Home:")
for sibling in home_link.next_siblings:
  if sibling.name == 'a': # Only interested in <a> tags
    print(f"- {sibling.text}: {sibling['href']}")

Beyond Siblings: find_next

Sometimes, the data you need isn't a direct child or sibling, but appears somewhere later in the HTML document relative to your current element. This is where .find_next() and .find_all_next() come in.

These methods search the rest of the document after the current tag, regardless of parent-child-sibling relationships. Similarly, .find_previous() and .find_all_previous() search before.

from bs4 import BeautifulSoup

html_doc = """
<div class="header">
  <h2>Section Title</h2>
</div>
<p>Some introductory text.</p>
<div class="content">
  <p>First paragraph.</p>
  <span>Important data!</span>
  <p>Second paragraph.</p>
</div>
"""
soup = BeautifulSoup(html_doc, 'html.parser')
section_title = soup.find('h2')

# Find the next <span> tag anywhere after the h2
important_data_span = section_title.find_next('span')

print(f"Section Title: {section_title.text}")
if important_data_span:
  print(f"Data found after title: {important_data_span.text}")

# Find all <p> tags after the h2
all_next_paragraphs = section_title.find_all_next('p')
print("All paragraphs after title:")
for p in all_next_paragraphs:
    print(f"- {p.text}")

Chaining Traversal Methods

The real power of traversal comes from chaining these methods. You can start at one point, move to a parent, then find a sibling, and then extract data from its children.

This allows you to navigate very specific, complex pathways to reach exactly the data you need, even if it's not directly addressable by a simple selector.

from bs4 import BeautifulSoup

html_doc = """
<div class="product-listing">
  <div class="product">
    <h3>Laptop X</h3>
    <p class="price">$1200</p>
  </div>
  <div class="product">
    <h3>Mouse Y</h3>
    <p class="price">$50</p>
  </div>
</div>
<div class="summary">
  <p>Total items: 2</p>
</div>
"""
soup = BeautifulSoup(html_doc, 'html.parser')

# Find "Laptop X" and then get its price
laptop_h3 = soup.find('h3', string='Laptop X')
if laptop_h3:
  # The price is a sibling of the h3
  price_tag = laptop_h3.find_next_sibling('p', class_='price')
  if price_tag:
    print(f"{laptop_h3.text} price: {price_tag.text}")

# Find the product listing, then get the text of the summary's paragraph
product_listing_div = soup.find('div', class_='product-listing')
if product_listing_div:
  summary_div = product_listing_div.find_next_sibling('div', class_='summary')
  if summary_div:
    summary_text = summary_div.find('p').text
    print(f"Summary: {summary_text}")

Handling Text Nodes

When traversing, you'll often encounter NavigableString objects. These represent the text content that isn't wrapped in its own HTML tag, like the whitespace (newlines and spaces) between tags.

BeautifulSoup treats these as distinct nodes in the tree. When using traversal methods like .next_sibling, you might get a NavigableString before you get the next actual tag. Always check .name or type() if you only want tags.

from bs4 import BeautifulSoup

html_doc = """
<div>
  Hello
  <p>World</p>
  !
</div>
"""
soup = BeautifulSoup(html_doc, 'html.parser')
div_tag = soup.find('div')

print("Children of the div:")
for child in div_tag.children:
  if child.name:
    print(f"- Tag: {child.name}, Text: {child.text}")
  else:
    print(f"- Text Node: {repr(child)}")

# Accessing a specific NavigableString
hello_text_node = list(div_tag.children)[0]
print(f"\nFirst child (text node): '{hello_text_node.strip()}'")

Traversal Challenge

Consider the following HTML snippet. You want to extract the "Availability" status for "Product B". Which sequence of BeautifulSoup traversal methods would correctly get you the text "In Stock" starting from the <h3> tag for "Product B"?

<html>
<body>
<div class="catalog">
  <div class="item">
    <h3>Product A</h3>
    <p>Price: $10</p>
    <span>Status: Out of Stock</span>
  </div>
  <div class="item">
    <h3>Product B</h3>
    <p>Price: $20</p>
    <span>Availability: In Stock</span>
  </div>
  <div class="item">
    <h3>Product C</h3>
    <p>Price: $30</p>
    <span>Status: Low Stock</span>
  </div>
</div>
</body>
</html>

Recap: Mastering Traversal

Congratulations! You've learned how to navigate complex HTML structures using BeautifulSoup's powerful traversal methods.

  • We explored moving up (.parent, .parents), down (.contents, .children), and sideways (.next_sibling, .previous_sibling, .next_siblings, .previous_siblings) in the HTML tree.
  • You also saw how to find elements anywhere after or before a current tag using .find_next() and .find_previous().
  • Mastering these techniques allows you to extract data from even the most challenging and irregularly structured web pages.

Next, we'll dive into using CSS selectors for even more precise data extraction!

무료로 시작

AI 튜터와 함께 Python을(를) 배우세요 — 무료

브라우저에서 실제 코드를 작성하고 실행하며, 24/7 AI 튜터로부터 즉각적인 도움을 받고, 웹이나 앱에서 중단한 부분부터 계속 학습하세요.

코스
12
레슨
48

자주 묻는 질문

“복잡한 HTML 구조 탐색” 강의는 무료인가요?

네 — “복잡한 HTML 구조 탐색” 전체 내용을 이 웹사이트에서 무료로 읽을 수 있습니다. 인터랙티브하게 실습하려면(내장 코드 에디터와 24/7 AI 튜터), CoddyKit PRO로 업그레이드하면 Web Scraping & Bots 강의 전체를 잠금 해제할 수 있습니다. Web Scraping & Bots 강의에는 총 4개의 강의가 포함되어 있습니다.

“복잡한 HTML 구조 탐색”에서 뭘 배우나요?

깊게 중첩되었거나 불규칙한 구조의 HTML 문서를 효과적으로 순회하는 기법을 학습합니다. 브라우저에서 직접 실행하는 실습 코드로 Web Scraping & Bots을(를) 배우며, 24/7 AI 튜터가 강의를 진행하면서 질문에 답변해줍니다.

Web Scraping & Bots을(를) 시작하는 데 경험이 필요한가요?

사전 경험은 필요하지 않습니다. CoddyKit의 Web Scraping & Bots은(는) 초급자부터 고급 학습자까지를 위해 구성되어 있으므로, 여기서 시작하거나 처음부터 시작할 수 있으며 자신의 속도대로 진행할 수 있습니다. 이것은 4개 중 1번째 강의입니다.

“복잡한 HTML 구조 탐색” 강의는 얼마나 걸리나요?

대부분의 CoddyKit 강의는 약 5~10분이 소요됩니다. 각 강의는 간결하고 인터랙티브하여 꾸준한 진행이 가능하며, 웹과 앱에서 중단한 부분부터 바로 시작할 수 있습니다.

이 Web Scraping & Bots 강의에서 코드를 작성하고 실행할 수 있나요?

네. 모든 Web Scraping & Bots 강의에는 내장 코드 에디터가 포함되어 있으므로, 브라우저에서 바로 실제 코드를 작성하고 실행한 후 즉시 AI 피드백을 받을 수 있습니다 — 로컬 설정이 필요 없습니다.

이 강의의 모든 강의

  1. 복잡한 HTML 구조 탐색
  2. 정밀한 CSS 선택자
  3. 견고한 선택을 위한 XPath
  4. HTML 표에서 데이터 추출하기
← Web Scraping & Bots(으)로 돌아가기