用于网络抓取的 HTML 选择器指南

指南, 搜索, 蟒蛇, 11-08-20245 分钟阅读

HTML 选择器是网络搜刮的关键,它允许开发人员锁定网页上的特定元素。通过使用这些选择器,开发人员可以精确地提取数据。

网络抓取包括通过浏览网站的 HTML 结构来获取数据。HTML 选择器至关重要,它能让你精确定位特定的标记、属性或内容。无论是提取产品价格还是标题,选择器都是您的指南。

使用 HTML 选择器可以有效简化数据提取过程并减少错误。它们可帮助您专注于重要元素,节省从在线资源中收集见解所需的时间和精力。

在本博客中,我们将探讨如何使用 Python 和"Beautifulsoup"库来使用下面的选择器:

  • ID 选择器
  • 类选择器
  • 属性选择器
  • 分层选择器
  • 将这些选择器组合在一起

ID 选择器

在 HTML 中,ID 是分配给特定元素的唯一标识符,确保没有两个元素共享相同的 ID。这种唯一性使得 ID 选择器非常适合用于定位网页上的单一元素。举例来说,如果你要抓取一个有多个部分的网页,每个部分都可能有自己的 ID,这样你就可以不受干扰地从特定部分提取数据。

例如 本网站特别是以下内容 <div id="pages"> ...</div>

该元素包含其他嵌套的 HTML 元素,但最主要的是,该元素在该网站上是唯一的,我们可以利用这种情况,例如,当我们想抓取网站的特定部分时。在本例中,该元素包含一些其他文章,我们将在下文中使用其他选择器对其进行解释。页面上的这一部分看起来是这样的:

让我们用 Python 的 "requests "和 "bs4 "库来探讨一个简单的例子:

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}")

解释:

  • 发送请求:请求库发送 GET 请求,从目标 URL 获取 HTML 内容。
  • 解析 HTML:BeautifulSoup 可以解析 HTML,让我们可以搜索文档结构。
  • Find Specific <div>: 我们使用 soup.find("div", id="pages") 找到 <div> 元素 id="pages".
  • 显示内容: 如果 <div> 则打印其内容。如果找不到,则会显示一条信息,说明内容丢失。

ID 选择器的局限性

ID 选择器功能强大,但也有局限性。每次页面加载时都会改变的动态 ID 会使数据提取难以保持一致。在这种情况下,可能需要使用其他选择器来获得可靠的结果。

类选择器

类选择器非常灵活,因为它们可以让你锁定共享相同类的元素组。因此,对于具有重复元素的网页来说,类选择器是必不可少的。例如,一个显示产品列表的网站可以为每个产品项目指定相同的类。

我们再以 本网站.以上我们确定了一个 <div id="pages"> 元素,而在这个 div 元素中,有一些文章具有相同的类别。

正如您所看到的,我们有四个具有相同类别的元素 <div class="page">

下面是它们在网站上的样子:

在下面的代码中,我们将选择所有具有 "page "类的元素,并返回一个可用于进一步解析的列表。

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}")

解释:

  • 发送请求:我们使用请求向 URL 发送 GET 请求,检索网页的 HTML 内容。
  • 使用 BeautifulSoup 解析 HTML:如果请求成功,BeautifulSoup 就会解析 HTML,使我们能搜索元素并与之交互。
  • 按类别查找元素 我们使用 soup.find_all("div", class_="page") 查找所有 <div> 类为 "page "的元素,并以列表形式返回。
  • 保存到列表: 我们提取并清理每个元素的文本内容,将其保存到名为pages_list 的列表中。

类选择器的局限性

在使用类选择器时,要注意潜在的问题,如选择非预期元素。单个元素上的多个类可能需要额外过滤才能实现准确定位。

属性选择器

通过属性选择器,您可以根据 HTML 标记中特定属性的存在、值或部分值来定位元素。当类或 ID 不是唯一的,或需要过滤具有动态属性的元素(如 数据-* href 链接中的值。

在下面的示例中,我们将选中该图标上的所有图像 网页 并提取它们的源 URL 或 来源 属性。这就是元素在 html 结构和网页视图中的外观:

在以下代码中,我们利用 BeautifulSoup 来解析所有 <img> 元素,提取其 来源 属性,并将它们存储在一个列表中。

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}")

类选择器的局限性

属性选择器只能选择具有静态属性的元素,因此对动态内容(如通过 JavaScript 加载的元素)的效果较差。属性选择器依赖于稳定的 HTML 结构,因此频繁的网站布局变化会干扰属性选择器。此外,它们无法管理复杂的过滤或多重条件,这也限制了它们的精确性。如果多个元素共享类或名称等属性,它们还可能抓取到意外的元素。

分层选择器

通过分层选择器,可以根据 HTML 结构中 HTML 元素的位置及其与其他元素的关系来定位 HTML 元素。这种方法在处理表格或嵌套列表时特别有用,因为这些表格或列表中的数据是以父子格式组织的。

在本例中,我们使用分层选择器从以下网站的冰球队统计表中抓取数据 此网页.
表格包含以下行 <tr> 代表每个团队,每行包含单元格 <td> 包含队名、年份、胜负等信息。每一行都有 class="team",将其识别为我们数据中的相关条目。通过从 <table> to each <tr> and then to each <td>因此,我们可以有效地以结构化的方式获取数据。

下面有两张图片,可以帮助您直观地了解该表格在 HTML 结构中的位置以及在实际网页中的显示效果。

现在,让我们看看下面的代码,看看如何使用分层选择器来提取这些数据:

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}")

分层选择器的局限性

分层选择器依赖于 HTML 结构,因此布局的改变很容易破坏搜索脚本。它们还仅限于静态内容,无法访问 JavaScript 动态加载的元素。这些选择器通常需要通过父子关系进行精确导航,这在深度嵌套结构中很有难度。此外,在提取分散的数据时,它们的效率可能会很低,因为它们必须穿越多个层级才能到达特定的元素。

使用组合选择器更好地定位

每种选择器类型都有其独特的作用,将它们结合起来,我们就能从嵌套或结构化的内容中准确地导航和捕获数据。例如,使用 ID 选择器可以帮助定位主要内容区域,类选择器可以隔离重复元素,属性选择器可以提取特定链接或图片,而分层选择器则可以找到嵌套在特定部分中的元素。这些技术结合在一起,为刮擦结构化数据提供了一种强大的方法。

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}")

守则解释

  • ID 选择器: 首先,我们要找到id="pages "的主内容区域,它包含了我们需要的部分。
  • 类选择器: 在这个主区域内,我们使用 class="page" 来查找代表感兴趣部分的每个单独内容块。
  • 分层选择器 在每个 "页面 "块中,我们使用
    • page.find("h3", class_="page-title") 找到标题。
    • title_tag.find("a")["href"] 从标题中的锚标签获取链接 URL。
  • 属性选择器:我们访问每个链接的href 属性,以获取与每个部分相关的准确 URL。
  • 输出:脚本会打印每个部分的标题、链接和描述,从而提供从页面中抓取的数据的结构化视图。

结论

在网络搜刮中,掌握 HTML 选择器的使用方法可以大大提高数据提取技能,从而准确收集重要信息。ID、类、属性和分层选择器等选择器在不同的搜刮任务中都有特定的用途。将这些工具结合使用,你就能自信地应对各种网络搜索挑战。

为了练习, Scrape This Site Books to Scrape等网站提供了很好的示例,可以帮助你提高技能。如果您需要任何帮助或想与其他对网络搜索感兴趣的人交流,请随时加入我们的 Discord 频道 https://discord.com/invite/scrape。

刮得开心