刚接触使用 XPath 定位页面元素?那么你来对地方了,下面的文章将为你提供入门所需的全部指南。
当进行网页爬取时,你如何在 HTML 或 XML 页面上定位元素?通常,许多解析库会提供它们特定的 API 来实现这一点。
在某些情况下,这些库支持使用 CSS 选择器,这使得定位目标元素和数据点变得更加容易。然而,当你需要爬取动态内容,而元素的 ID 和类名是动态变化的时,这些方法将不再适用。
此时,唯一的选择就是使用 XPath,它是一种强大的方法,可以通过部分或完整的文本内容来定位元素。在本文中,我将为你讲解关于 XPath contains() 的所有知识,以及如何有效地使用它从爬取的 HTML 或 XML 页面中解析数据。
什么是 XPath contains() 函数?
XPath 是 XML 路径语言的缩写。它最初设计用于解析 XML 文档并从中提取数据。但是,它也支持 HTML 文档。
XPath contains 函数是 XPath 语言的一部分,可以说是核心函数之一。它用于匹配内容或属性中含有特定字符串的元素。下面我们来看看它的语法。
contains(haystack, needle)
这就像大海捞针,而且它做得非常好。其中 haystack 变量是一个字符串,它包含完整的 HTML 文档或其子字符串。另一方面,needle 是您想要查找的项目,它也以字符串的形式提供,通常只是其中的一部分。
XPath Contains 与 CSS 选择器
对于熟悉网页抓取的人来说,你会发现大多数程序员更喜欢使用 CSS 选择器来解析和添加额外内容,你可以通过标签名称、ID 和类来找到元素。
您还可以使用子选择器和后代选择器搜索元素。对于大多数程序员来说,使用 CSS 选择器比
XPath contains() 更简单、更易于维护且更方便。即使有这些优点,为什么还要使用 XPath 而不是 CSS 选择器呢?
- 缺少静态选择器属性
如果您知道包含目标数据的元素的 ID、类、标签名称或其他属性,CSS 选择器将大放异彩。在某些情况下,这些都不存在或它们是动态的。无论哪种情况,您都不能使用 CSS 选择器。您需要使用 XPath contains(),因为它是专门为此而设计的。
- 根据文本内容匹配元素
如果您想根据文本内容匹配 HTML 元素,您知道这不能仅使用 CSS 选择器来完成。您需要使用其他一些俗气的方法,包括使用正则表达式 (Regex) 才能成功实现这一点。但是,XPath 非常擅长根据元素的部分文本匹配和查找元素。
- 双向搜索流
CSS 选择器只能单向搜索 — 即从父元素到子元素/后代。但是,对于 XPath,您可以通过两种方式搜索元素。
即父级到子级,以及从子级到父级。这使得 XPath 成为比 CSS 选择器更灵活、更强大的解析工具。它唯一的主要问题是它的可读性不如 CSS 选择器。
如何使用 XPath 访问元素
XQuery 是用于从 XML 和 HTML 页面文档中查询数据的语言。它就像数据库的 SQL。要从 HTML 文档中提取数据,我们使用基于 XPath 表达式构建的查询。
在解析和提取网页数据时,有两种方法可以实现。您可以使用绝对或相对 XPath 来访问内容。下面是如何使用这两种方法的示例。
- 绝对 XPath
在绝对 XPath 中,您从文档根节点(即 html 标记到正文)开始,并继续向下移动到要从中提取数据的特定元素。例如,如果您想提取 h1 元素的文本,则您可以按如下所示编写 XPath。
html/body/h1
如您所见,我们使用其绝对路径从 html 元素移动到 h1。虽然这有效,但对文档结构进行一点更改就会使此表达式无效。
- 相对 XPath
与绝对 XPath 不同,在相对版本中,您只需指定元素标签名称并提供一些过滤器来帮助您访问它。当与“包含”功能结合使用时,它为您提供了一种更灵活、更可扩展的方法来访问和获取网页元素中的数据。
让我们使用相对 XPath 复制上述相同的操作。
//h1 Just //h1 will do the magic.
如何使用浏览器开发者工具获取元素 XPath
如果您仔细检查页面的 HTML,您应该能够手动生成元素的 XPath。但是,这不是最好的方法。您实际上可以使用开发人员工具从浏览器中轻松获取它。
在本节中,我将向您展示如何使用 Chrome 开发人员工具获取网页上元素的 XPath 表达式。假设我想获取wikipedia.org英文主页上的 h1 元素,下面是如何获取它的屏幕截图。
如上所示,我位于开发者工具中。您可以通过右键单击页面并单击“检查”选项来访问它。
确保元素选项卡处于焦点中,然后单击鼠标光标状图标以单击“欢迎使用维基百科”标题。这将突出显示它所包含的元素。转到复制,然后选择复制 XPath 选项。以下内容将被复制到您的剪贴板 – 您可以将其粘贴到任何地方。
[@id="Welcome_to_Wikipedia"]
如您所见,浏览器在这种情况下使用了 ID。如果我不使用浏览器来执行此操作,我会使用另外两种方法,它们都是有效的。
//h1[@id="Welcome_to_Wikipedia"] //h1
在上面的第一个替代方案中,我指定了元素标签名称,即 h1。与从 Google Chrome 中获取的相比,它更具体。最后一个替代方案很宽泛,尽管它有效,但不推荐。让我们来看看可接受的不同部分。
- //* 或 //h1
//* 部分表示选择任何元素。这是因为星号 (*) 是匹配所有元素的通配符。就我而言,我从使用 * 切换到 h1,这样我会更具体。根据您想要达到的特定元素和数据点,您可能需要具体化或保持宽泛。
- [@id=“Welcome_to_Wikipedia”]
@ 字符用于指定元素的属性,例如类、ID 和名称等。在表达式中,使用了元素 ID 和值“Welcome_to_Wikipedia”。
根据从 Chrome 复制的 XPath 表达式,XPath 将查找具有 Welcome_to_Wikipedia 作为 ID 的元素。如果我们使用我自己的版本,它将仅查找具有该 ID 的 h1 元素。
对于 //h1 表达式,这将适用于只有一个 h1 元素的页面。因此,尽管它在这种情况下可以工作,但不建议使用它。
如何使用 XPath contains()匹配文本内容
为了向您展示如何使用 XPath contains(),我们需要一个 HTML 文档来处理。下面是我专门为本指南创建的文档。
<div class="product-container"> <div class="product" id="product-1"> <img src="https://example.com/product1.jpg" alt="Elegant Wristwatch"> <h3>Elegant Wristwatch</h3> <p>A timeless piece for any occasion.</p> <p>Rating: 4.5/5</p> <p>Comments: 23</p> </div> <div class="product" id="product-2"> <img src="https://example.com/product2.jpg" alt="Wireless Earbuds"> <h3>Wireless Earbuds</h3> <p>Experience crystal-clear sound on the go.</p> <p>Rating: 3.8/5</p> <p>Comments: 15</p> </div> <div class="product" id="product-3"> <img src="https://example.com/product3.jpg" alt="Smartwatch"> <h3>Smartwatch</h3> <p>Stay connected and healthy with this stylish smartwatch.</p> <p>Rating: 4.2/5</p> <p>Comments: 37</p> </div> <div class="product" id="product-4"> <img src="https://example.com/product4.jpg" alt="Gaming Headset"> <h3>Gaming Headset</h3> <p>Immerse yourself in your favorite games.</p> <p>Rating: 4.9/5</p> <p>Comments: 12</p> </div> <div class="product" id="product-5"> <img src="https://example.com/product5.jpg" alt="Portable Charger"> <h3>Portable Charger</h3> <p>Power up your devices on the go.</p> <p>Rating: 3.5/5</p> <p>Comments: 28</p> </div> </div>
上面的代码用于保存 5 个产品数据的产品容器。每个产品都保存在自己的 div 元素中,但它们都共享相同的类名,即“product”。但是,它们具有不同的 ID。
现在让我们使用 XPath contains()提取所有产品名称。
//div[contains(@id, 'product-')]//h3/text()
上面的表达式将提取所有产品名称。简单来说,它的作用是获取所有 ID 以 product- 开头的 div 元素的文本。这样,它能够捕获动态元素 ID,例如 product-1、product-2、product-3 等。让我们看看它是如何实现的。
- //div[contains(@id, ‘product-‘)]:此部分代码选择所有 ID 包含字符串“product-”的 div 元素
- //h3/text():此部分代码的作用是选择每个产品 div 中的 h3 元素并从中提取文本内容。h3 元素保存每个产品的产品名称。
这样,无论产品 div 元素 ID 是 product-1 还是 product-2,都将被捕获。这是 XPath contain 方法的强大功能之一。
如何在 Request 中使用 XPath contains()
如今,大多数网络爬虫宁愿使用Request和 BeautifulSoup 进行爬取,也不愿考虑使用 Lxml 作为 BeautifulSoup 的替代品。有趣的是,当面对元素 ID 动态且不可预测的场景时,BeautifulSoup 将无法完成工作。
在本节中,我将向您展示如何使用Request和 BeautifulSoup 来抓取产品名称,使用上面提供的数据。首先,您需要使用以下命令安装 lxml 包。
pip install lxml
Now to the short script to demonstrate how to use requests and XPath contains.
from lxml import html
import requests
url = ''
response = requests.get(url)
html_content = response.content
tree = html.fromstring(html_content)
product_names = tree.XPath("//div[contains(@id, 'product-')]//h3/text()")
print(product_names)
正如你在上面看到的,与使用 BeautifulSoup 不同,我使用了 lxml,它是速度最快的解析器之一。通过 html.fromstring 方法创建了一个文档树,然后使用 tree.XPath 方法并将表达式作为字符串传入,从而爬取所需的数据。
注意到我并没有传入实际的 URL 吗?这是因为在向你展示如何使用 lxml 进行爬取时,我使用了与主表达式相同的表达式,但使用的是我提供的文档。
结 论
毫无疑问,使用 XPath 可能看起来像一种较为传统的方式,因为 CSS 选择器提供了一种更简单、更可读且更易维护的数据解析方式。
然而,这并非总是如此。在某些场景下,你需要使用 XPath,尤其是 XPath 的 contains() 函数,而在这些场景中,CSS 选择器是无法解决问题的。如果你遇到这样的情况,可以参考上面的指南来访问并解析所需的数据。

