CodeGym /Các khóa học /Python SELF VI /Trích xuất dữ liệu từ cấu trúc HTML phức tạp

Trích xuất dữ liệu từ cấu trúc HTML phức tạp

Python SELF VI
Mức độ , Bài học
Có sẵn

1. Cơ bản làm việc với cấu trúc HTML phức tạp

Trước khi bắt đầu phân tích các cấu trúc HTML phức tạp, điều quan trọng là hiểu tại sao HTML có thể trở nên rối rắm. Các lập trình viên web thường sử dụng các thành phần lồng nhau phức tạp để tổ chức nội dung, dẫn đến sự đau đầu cho những ai đang cố gắng trích xuất dữ liệu từ các trang như vậy. Nhưng đừng lo — khi bạn có kế hoạch và công cụ tốt, việc này sẽ dễ dàng thôi!

Phân tích cây HTML

Hãy tưởng tượng tài liệu HTML như một cây: mỗi phần tử là một nút, có thể chứa văn bản hoặc các nút khác. Ở đầu cây này là html, sau đó là headbody, rồi tiếp theo là các phần tử con khác nhau. Các phần tử lồng nhau sâu hơn trong cây này.

Ví dụ về cấu trúc HTML đơn giản:

HTML

<html>
  <head>
    <title>Ví dụ</title>
  </head>
  <body>
    <div class="content">
      <h1>Tiêu đề</h1>
      <p>Đoạn văn 1</p>
      <p>Đoạn văn 2</p>
      <div class="nested">
        <ul>
          <li>Phần tử 1</li>
          <li>Phần tử 2</li>
          <li><span>Phần tử 3</span></li>
        </ul>
      </div>
    </div>
  </body>
</html>

Như bạn thấy, chúng ta có một div với class nested, chứa ul, và thành phần này lại chứa các phần tử li. Đây là một ví dụ về cách các thành phần có thể được lồng vào nhau.

2. BeautifulSoup để trích xuất dữ liệu

Trích xuất dữ liệu từ các phần tử lồng nhau

Hãy nhớ cách BeautifulSoup hoạt động. Chúng ta sẽ dùng BeautifulSoup để trích xuất văn bản từ danh sách li. Đến lúc trở thành một thám tử thực thụ và thu thập dữ liệu từ các cấu trúc lồng nhau này.

Python

from bs4 import BeautifulSoup

soup = BeautifulSoup(html, 'html.parser')
nested_items = soup.select('.nested ul li')

for item in nested_items:
    print(item.get_text())

Kết quả:


Phần tử 1
Phần tử 2
Phần tử 3

Như bạn thấy, chúng ta sử dụng phương thức select với CSS selector để tìm tất cả các phần tử li bên trong phần tử có class nested. Phương thức get_text() cho phép trích xuất văn bản trực tiếp từ các phần tử tìm thấy.

3. Làm việc với các phần tử đa cấp

Đôi khi dữ liệu không chỉ nằm sâu trong cấu trúc mà còn phân tán ở nhiều cấp độ khác nhau, khiến việc trích xuất trở nên phức tạp hơn. Hãy cùng tìm hiểu cách trích xuất dữ liệu từ một cây HTML phức tạp hơn.

Ví dụ về cấu trúc phức tạp:

HTML

<html>
  <body>
    <div class="wrapper">
      <div class="header">
        <h1>Đây là tiêu đề</h1>
      </div>
      <div class="content">
        <div class="article">
          <h2>Bài viết 1</h2>
          <p>Nội dung bài viết 1</p>
        </div>
        <div class="article">
          <h2>Bài viết 2</h2>
          <p>Nội dung bài viết 2</p>
        </div>
      </div>
      <div class="footer">
        <p>Thông tin liên hệ</p>
      </div>
    </div>
  </body>
</html>

Trích xuất dữ liệu từ các cấp độ

Bây giờ hãy thử trích xuất tiêu đề của tất cả các bài viết và nội dung của chúng.

Python

articles = soup.select('.content .article')

for article in articles:
    title = article.find('h2').get_text()
    content = article.find('p').get_text()
    print(f'Tiêu đề: {title}')
    print(f'Nội dung: {content}\n')

Dự kiến đầu ra:


Tiêu đề: Bài viết 1
Nội dung: Nội dung bài viết 1

Tiêu đề: Bài viết 2
Nội dung: Nội dung bài viết 2

Chúng ta sử dụng sự kết hợp giữa các phương thức selectfind để đạt được mục tiêu. select giúp tìm phần tử cha, trong khi find trích xuất thông tin từ phần tử con.

4. Đặc điểm làm việc với các phần tử lồng nhau

Khi xem xét các trang web, bạn có thể gặp phải những vấn đề như có nhiều phần tử lồng nhau có cùng class hoặc tag. Trong những trường hợp đó, việc sử dụng tìm kiếm theo ngữ cảnh và xác định rõ ràng các phần tử cần thiết sẽ giúp tránh lỗi.

Ví dụ về cấu trúc lồng nhau phức tạp:

HTML

<html>
  <body>
    <div class="container">
      <div class="item">
        <h2>Số 1</h2>
        <div class="details">Chi tiết 1</div>
      </div>
      <div class="item">
        <h2>Số 2</h2>
        <div class="details">Chi tiết 2</div>
        <div class="additional">
          <div class="info">Thông tin bổ sung</div>
        </div>
      </div>
    </div>
  </body>
</html>

Trích xuất dữ liệu có tính đến lồng nhau

Để tránh nhầm lẫn, bạn nên tìm các phần tử cụ thể hơn:

Python

items = soup.select('.container .item')

for item in items:
    number = item.find('h2').get_text()
    details = item.select_one('.details').get_text()
    additional_info = item.select_one('.additional .info')
    
    print(f'Số: {number}')
    print(f'Chi tiết: {details}')
    
    if additional_info:
        print(f'Thông tin bổ sung: {additional_info.get_text()}')
    print()

Ở đây, chúng ta sử dụng phương thức select_one, phương thức này chỉ trả về phần tử đầu tiên tìm thấy, để tránh trùng lặp dữ liệu từ các khối bổ sung.

5. Thực tế và các lỗi thường gặp

Khi làm việc với các cấu trúc HTML phức tạp, rất dễ bị nhầm lẫn hoặc gặp phải lỗi. Một lỗi phổ biến là cố truy cập vào một phần tử không tồn tại, dẫn đến AttributeError. Để tránh điều đó, luôn luôn kiểm tra sự tồn tại của phần tử trước khi làm việc với nó.

Một điều quan trọng khác là hiểu rằng không phải lúc nào bạn cũng cần trích xuất dữ liệu ngay lập tức. Đôi khi, việc phân tích sơ bộ cấu trúc, sử dụng thông báo debug và kiểm tra kết quả trung gian rất hữu ích.

Trong các dự án thực tế, kỹ năng làm việc với các cấu trúc HTML lồng nhau có thể cực kỳ quan trọng. Nó không chỉ áp dụng trong web scraping mà còn trong kiểm tra giao diện web, tự động hóa kiểm thử và thậm chí là phân tích dữ liệu từ các API phức tạp, nơi mà đầu ra có thể có định dạng được lồng vào.

Bình luận
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION