Hướng dẫn về Bộ chọn HTML để Trích xuất dữ liệu Web

Hướng dẫn , Scraping , Python ,08-11-20245 phút đọc

Bộ chọn HTML là chìa khóa để thu thập dữ liệu web, cho phép các nhà phát triển nhắm mục tiêu vào các thành phần cụ thể trên trang web. Bằng cách sử dụng các bộ chọn này, các nhà phát triển có thể trích xuất dữ liệu chính xác.

Web scraping liên quan đến việc lấy dữ liệu từ các trang web bằng cách điều hướng cấu trúc HTML của chúng. Bộ chọn HTML rất quan trọng, cho phép bạn xác định chính xác các thẻ, thuộc tính hoặc nội dung cụ thể. Cho dù trích xuất giá sản phẩm hay tiêu đề, bộ chọn chính là hướng dẫn của bạn.

Sử dụng bộ chọn HTML giúp hợp lý hóa việc trích xuất dữ liệu và giảm lỗi. Chúng giúp bạn tập trung vào các yếu tố quan trọng, tiết kiệm thời gian và công sức trong việc thu thập thông tin chi tiết từ các nguồn trực tuyến.

Trong blog này, chúng ta sẽ khám phá cách sử dụng các bộ chọn bên dưới với Python và thư viện " Beautifulsoup ":

  • Bộ chọn Id
  • Bộ chọn lớp
  • Bộ chọn thuộc tính
  • Bộ chọn phân cấp
  • Sự kết hợp của các bộ chọn này với nhau

Bộ chọn ID

Trong HTML, ID là các mã định danh duy nhất được gán cho các phần tử cụ thể, đảm bảo không có hai phần tử nào có cùng ID. Tính duy nhất này làm cho bộ chọn ID trở nên lý tưởng để nhắm mục tiêu đến các phần tử riêng lẻ trên một trang web. Ví dụ, nếu bạn đang thu thập dữ liệu từ một trang web có nhiều phần, mỗi phần có thể có ID riêng, cho phép bạn trích xuất dữ liệu từ một phần cụ thể mà không bị can thiệp.

Chúng ta hãy lấy ví dụ trang web này, đặc biệt là phần tử bên dưới <div id="pages"> ...</div>

Phần tử này chứa các phần tử HTML lồng nhau khác nhưng điều quan trọng nhất là phần tử này là duy nhất trên trang web này và chúng ta có thể tận dụng kịch bản này chẳng hạn khi chúng ta muốn trích xuất các phần cụ thể của trang web. Trong trường hợp này, phần tử này bao gồm một số bài viết khác mà chúng ta sẽ giải thích bằng các bộ chọn khác bên dưới. Sau đây là cách phần này trên trang trông như thế nào:

Hãy cùng khám phá một ví dụ đơn giản sử dụng thư viện "requests" và "bs4" của Python:

import requests
from bs4 import BeautifulSoup
# Step 1: Send a GET request to the website
url = "https://www.scrapethissite.com/pages/"
response = requests.get(url)
if response.status_code == 200:
   # Step 2: Parse the HTML content with BeautifulSoup
   soup = BeautifulSoup(response.text, 'html.parser')
  
   # Step 3: Find the div with id="pages"
   pages_div = soup.find("div", id="pages")
  
   # Step 4: Display the content or handle it as needed
   if pages_div:
       print("Content of the div with id='pages':")
       print(pages_div.text.strip())
   else:
       print("No div with id='pages' found.")
else:
   print(f"Failed to retrieve the webpage. Status code: {response.status_code}")

Giải thích:

  • Gửi yêu cầu: Thư viện yêu cầu gửi yêu cầu GET để lấy nội dung HTML từ URL đích.
  • Phân tích cú pháp HTML: BeautifulSoup phân tích cú pháp HTML, cho phép chúng ta tìm kiếm trong cấu trúc tài liệu.
  • Find Specific <div>: Chúng tôi sử dụng soup.find("div", id="trang") để xác định vị trí <div> phần tử với id="trang".
  • Hiển thị nội dung: Nếu <div> được tìm thấy, chúng tôi sẽ in nội dung của nó. Nếu không, một thông báo sẽ cho biết nó bị thiếu.

Hạn chế của Bộ chọn ID:

Bộ chọn ID rất mạnh nhưng có những hạn chế. ID động thay đổi theo từng lần tải trang có thể khiến việc trích xuất dữ liệu nhất quán trở nên khó khăn. Trong những tình huống này, việc sử dụng bộ chọn thay thế có thể cần thiết để có kết quả đáng tin cậy.

Bộ chọn lớp

Bộ chọn lớp linh hoạt vì chúng cho phép bạn nhắm mục tiêu vào các nhóm phần tử có cùng lớp. Điều này làm cho chúng trở nên cần thiết cho các trang web có các phần tử lặp lại. Ví dụ, một trang web hiển thị danh sách sản phẩm có thể chỉ định cùng một lớp cho từng mục sản phẩm.

Chúng ta hãy lấy một ví dụ nữa bằng cách sử dụng trang web này. Phía trên chúng tôi đã xác định một <div id="pages"> phần tử sử dụng ID Selector và trong các phần tử div này có một số bài viết có cùng lớp.

Như bạn có thể thấy chúng ta có bốn phần tử có cùng lớp <div class="page">

Dưới đây là hình ảnh của chúng trên trang web:

Trong đoạn mã dưới đây, chúng ta sẽ chọn tất cả các phần tử có lớp "page", điều này sẽ trả về một danh sách có thể được sử dụng để phân tích cú pháp thêm.

import requests
from bs4 import BeautifulSoup
# Step 1: Send a GET request to the website
url = "https://www.scrapethissite.com/pages/"
response = requests.get(url)
if response.status_code == 200:
   # Step 2: Parse the HTML content with BeautifulSoup
   soup = BeautifulSoup(response.text, 'html.parser')
  
   # Step 3: Find all elements with class="page"
   page_elements = soup.find_all("div", class_="page")
  
   # Step 4: Save each element's text content in a list
   pages_list = [page.text.strip() for page in page_elements]
  
   print("Content of elements with class 'page':")
   for i, page in enumerate(pages_list, start=1):
       print(f"Page {i}:")
       print(page)
       print("-" * 20)
else:
   print(f"Failed to retrieve the webpage. Status code: {response.status_code}")

Giải thích:

  • Gửi yêu cầu: Chúng tôi sử dụng yêu cầu để gửi yêu cầu GET tới URL, lấy nội dung HTML của trang web.
  • Phân tích cú pháp HTML bằng BeautifulSoup: Nếu yêu cầu thành công, BeautifulSoup sẽ phân tích cú pháp HTML, cho phép chúng ta tìm kiếm và tương tác với các phần tử.
  • Tìm phần tử theo lớp: Chúng tôi sử dụng soup.find_all("div", class_="trang") để xác định vị trí tất cả <div> các phần tử có lớp "trang", trả về chúng dưới dạng một danh sách.
  • Lưu vào danh sách: Chúng tôi trích xuất và dọn dẹp nội dung văn bản của từng phần tử, lưu vào danh sách có tên là pages_list .

Giới hạn của Bộ chọn lớp

Khi sử dụng bộ chọn lớp, hãy lưu ý đến các vấn đề tiềm ẩn như chọn các phần tử không mong muốn. Nhiều lớp trên một phần tử duy nhất có thể yêu cầu lọc bổ sung để đạt được mục tiêu chính xác.

Bộ chọn thuộc tính

Bộ chọn thuộc tính cho phép bạn nhắm mục tiêu các phần tử dựa trên sự hiện diện, giá trị hoặc giá trị một phần của các thuộc tính cụ thể trong thẻ HTML. Điều này đặc biệt hữu ích khi các lớp hoặc ID không duy nhất hoặc khi bạn cần lọc các phần tử có thuộc tính động, chẳng hạn như dữ liệu-* hoặc href giá trị trong liên kết.

Trong ví dụ sau, chúng ta sẽ chọn tất cả hình ảnh trên trang web và trích xuất URL nguồn của chúng hoặc nguồn thuộc tính. Đây là cách phần tử trông như thế nào trong cấu trúc html và chế độ xem trang web:

Trong đoạn mã sau, chúng tôi sử dụng BeautifulSoup để phân tích tất cả <img> các yếu tố, trích xuất của họ nguồn thuộc tính và lưu trữ chúng trong một danh sách.

import requests
from bs4 import BeautifulSoup
# Step 1: Send a GET request to the website
url = "https://www.scrapethissite.com/pages/frames/"
response = requests.get(url)
if response.status_code == 200:
   # Step 2: Parse the HTML content with BeautifulSoup
   soup = BeautifulSoup(response.text, 'html.parser')
  
   # Step 3: Find all <img> elements with a 'src' attribute
   image_elements = soup.find_all("img", src=True)
  
   # Step 4: Save the 'src' attributes in a list
   images_list = [img['src'] for img in image_elements]
  
   print("Image sources found on the page:")
   for i, src in enumerate(images_list, start=1):
       print(f"Image {i}: {src}")
else:
   print(f"Failed to retrieve the webpage. Status code: {response.status_code}")

Giới hạn của Bộ chọn lớp

Bộ chọn thuộc tính chỉ có thể chọn các phần tử có thuộc tính tĩnh, khiến chúng kém hiệu quả hơn đối với nội dung động, như các phần tử được tải qua JavaScript. Chúng phụ thuộc vào các cấu trúc HTML ổn định, do đó việc thay đổi bố cục trang web thường xuyên có thể làm gián đoạn chúng. Ngoài ra, chúng không thể quản lý bộ lọc phức tạp hoặc nhiều điều kiện, điều này hạn chế độ chính xác của chúng. Chúng cũng có thể chọn các phần tử không mong muốn nếu các thuộc tính như lớp hoặc tên được chia sẻ bởi nhiều phần tử.

Bộ chọn phân cấp

Bộ chọn phân cấp cho phép bạn nhắm mục tiêu các phần tử HTML dựa trên vị trí và mối quan hệ của chúng với các phần tử khác trong cấu trúc HTML. Cách tiếp cận này đặc biệt hữu ích khi làm việc với các bảng hoặc danh sách lồng nhau, trong đó dữ liệu được tổ chức theo định dạng cha-con.

Trong ví dụ này, chúng tôi đang sử dụng bộ chọn phân cấp để thu thập dữ liệu từ bảng thống kê đội khúc côn cầu được tìm thấy trên trang web này.
Bảng chứa các hàng <tr> đại diện cho mỗi đội và mỗi hàng chứa các ô <td> với thông tin như tên đội, năm, chiến thắng và thua cuộc. Mỗi hàng có lớp="đội", xác định nó là một mục nhập có liên quan trong dữ liệu của chúng tôi. Bằng cách điều hướng từ <table> to each <tr> and then to each <td>, chúng ta có thể thu thập dữ liệu một cách hiệu quả theo cách có cấu trúc.

Bên dưới, bạn sẽ thấy hai hình ảnh giúp bạn hình dung vị trí của bảng này trong cấu trúc HTML và cách nó xuất hiện trên trang web thực tế.

Bây giờ, chúng ta hãy xem đoạn mã bên dưới để biết cách sử dụng bộ chọn phân cấp để trích xuất dữ liệu này:

import requests
from bs4 import BeautifulSoup

url = "https://www.scrapethissite.com/pages/forms/"

# Step 1: Send a GET request to the website
response = requests.get(url)

if response.status_code == 200:
   # Step 2: Parse the HTML content with BeautifulSoup
   soup = BeautifulSoup(response.text, 'html.parser')
  
   # Step 3: Find all rows in the table with class="team"
   teams_data = []
   team_rows = soup.find_all("tr", class_="team")
  
   # Step 4: Extract and store each team's data
   for row in team_rows:
       team = {
           "name": row.find("td", class_="name").text.strip(),
           "year": row.find("td", class_="year").text.strip(),
           "wins": row.find("td", class_="wins").text.strip(),
           "losses": row.find("td", class_="losses").text.strip(),
           "ot_losses": row.find("td", class_="ot-losses").text.strip(),
           "win_pct": row.find("td", class_="pct").text.strip(),
           "goals_for": row.find("td", class_="gf").text.strip(),
           "goals_against": row.find("td", class_="ga").text.strip(),
           "goal_diff": row.find("td", class_="diff").text.strip(),
       }
       teams_data.append(team)
  
   # Step 5: Display the extracted data
   for team in teams_data:
       print(team)
else:
   print(f"Failed to retrieve the webpage. Status code: {response.status_code}")

Giới hạn của bộ chọn phân cấp

Bộ chọn phân cấp phụ thuộc vào cấu trúc HTML, do đó, những thay đổi trong bố cục có thể dễ dàng phá vỡ tập lệnh thu thập dữ liệu. Chúng cũng bị giới hạn ở nội dung tĩnh và không thể truy cập các phần tử được JavaScript tải động. Các bộ chọn này thường yêu cầu điều hướng chính xác qua các mối quan hệ cha-con, điều này có thể gây khó khăn trong các cấu trúc lồng nhau sâu. Ngoài ra, chúng có thể không hiệu quả khi trích xuất dữ liệu phân tán, vì chúng phải đi qua nhiều cấp để tiếp cận các phần tử cụ thể.

Sử dụng Bộ chọn kết hợp để nhắm mục tiêu tốt hơn

Mỗi loại bộ chọn phục vụ một mục đích riêng và việc kết hợp chúng cho phép chúng ta điều hướng và nắm bắt dữ liệu chính xác từ nội dung lồng nhau hoặc có cấu trúc. Ví dụ, sử dụng bộ chọn ID có thể giúp định vị vùng nội dung chính, bộ chọn lớp có thể cô lập các phần tử lặp lại, bộ chọn thuộc tính có thể trích xuất các liên kết hoặc hình ảnh cụ thể và bộ chọn phân cấp có thể tiếp cận các phần tử lồng nhau trong các phần cụ thể. Cùng nhau, các kỹ thuật này cung cấp một phương pháp tiếp cận mạnh mẽ để thu thập dữ liệu có cấu trúc.

import requests
from bs4 import BeautifulSoup
# Target URL
url = "https://www.scrapethissite.com/pages/"
response = requests.get(url)
if response.status_code == 200:
   # Step 2: Parse the HTML content with BeautifulSoup
   soup = BeautifulSoup(response.text, 'html.parser')
  
   # Use ID selector to find the main content
   main_content = soup.find(id="pages")
  
   # Use class selector to find each "page" section
   pages = main_content.find_all("div", class_="page") if main_content else []
  
   # Extract details from each "page" section using hierarchical selectors
   for page in pages:
       # Use hierarchical selector to find title link and URL within each "page"
       title_tag = page.find("h3", class_="page-title")
       title = title_tag.text.strip() if title_tag else "No Title"
       link = title_tag.find("a")["href"] if title_tag and title_tag.find("a") else "No Link"
      
       # Use class selector to find the description
       description = page.find("p", class_="lead session-desc").text.strip() if page.find("p", class_="lead session-desc") else "No Description"
      
       print(f"Title: {title}")
       print(f"Link: {link}")
       print(f"Description: {description}")
       print("-" * 40)
else:
   print(f"Failed to retrieve the webpage. Status code: {response.status_code}")

Giải thích về Bộ luật

  • Bộ chọn ID: Chúng ta bắt đầu bằng cách xác định vùng nội dung chính có id="pages", chứa các phần chúng ta cần.
  • Bộ chọn lớp: Bên trong khu vực chính này, chúng tôi sử dụng lớp="trang" để tìm từng khối nội dung riêng lẻ đại diện cho một phần quan tâm.
  • Bộ chọn phân cấp: Trong mỗi khối "trang", chúng tôi sử dụng:
    • trang.tìm("h3", class_="tiêu-đề-trang") để tìm tiêu đề.
    • thẻ tiêu đề.tìm("a")["href"] để lấy URL liên kết từ thẻ neo trong tiêu đề.
  • Bộ chọn thuộc tính : Chúng tôi truy cập thuộc tính href của mỗi liên kết để nắm bắt các URL chính xác được liên kết với từng phần.
  • Đầu ra: Tập lệnh in ra tiêu đề, liên kết và mô tả của từng phần, cung cấp dạng xem có cấu trúc về dữ liệu được thu thập từ trang.

Phần kết luận

Trong việc trích xuất dữ liệu web, biết cách sử dụng bộ chọn HTML có thể cải thiện đáng kể kỹ năng trích xuất dữ liệu của bạn, cho phép bạn thu thập thông tin quan trọng một cách chính xác. Các bộ chọn như ID, lớp, thuộc tính và bộ chọn phân cấp đều có công dụng cụ thể cho các tác vụ trích xuất khác nhau. Bằng cách sử dụng các công cụ này cùng nhau, bạn có thể tự tin xử lý nhiều thách thức trích xuất dữ liệu web.

Để thực hành, các trang web như Scrape This SiteBooks to Scrape cung cấp các ví dụ tuyệt vời giúp bạn cải thiện kỹ năng của mình. Và nếu bạn cần bất kỳ trợ giúp nào hoặc muốn kết nối với những người khác quan tâm đến việc thu thập dữ liệu web, hãy thoải mái tham gia kênh Discord của chúng tôi tại https://discord.com/invite/scrape .

Chúc bạn cạo vui vẻ!