如何用XPath抓取网页数据

您是否发现从要抓取的页面中选择元素具有挑战性?那么,使用 XPath 进行网页抓取是轻松搜索文档并提取元素的方法!您将在本教程中学习如何使用它。

网页抓取中的 XPath 是什么?

XML 路径 (XPath) 是一种用于定位类似 XML 文档(如 HTML)的部分的语言。它允许您浏览节点树并使用XPath 表达式(一种用于检索数据的查询语言)选择元素。

为什么学习 XPath?

虽然它的执行性能比其他选择器慢,但它很方便,因为它比 CSS 选择器更强大。例如,您可以引用父元素并在任意方向导航 DOM。

DOM 速成课程

提醒一下,DOM(文档对象模型)是一个接口,它确定 HTML 文档中标签(标题、段落等)的层次结构。例如,看一下下面的页面:

<!doctype html>
<html>
    <head>
        <title>XPath for Web Scraping</title>
        <meta charset="utf-8" />
    </head>

    <body>
        <h1>What Is XPath</h1>
        <p>XPath is a language</p>
        <p>Check out our <a href="https://www.zenrows.com/blog">blog</a></p>
    </body>
</html>

它在 DOM 中转换为以下结构:

medium_DOM_ebc86cb775

正如您所看到的,该结构是树状的,由节点和对象组成。

现在我们已经回顾了这一点,现在是时候更详细地了解 XPath 了。

Web 抓取的 XPath 语法

接下来,我们将学习 XPath 语法并查看示例以了解如何从 HTML 文档中提取数据。

XPath 节点

如上所述,XPath 选择器将文档视为节点树。因此,文档中的元素遵循层次结构

我们将使用以下 HTML 作为示例:

<bookstore>

<book>
  <title>Harry Potter</title>
  <author>J K. Rowling</author>
  <year>2005</year>
  <price>29.99</price>
</book>

</bookstore>

让我们看看如何使用 XPath 术语进行嵌套:

学期 意义 例子
Parent 每个元素和属性都有一个父元素。 该元素是、和元素<book>的父元素。<title><author><year><price>
Children 具有零个、一个或多个子节点的节点。 <title>、和元素都是该元素的子<author>元素。<year><price><book>
Siblings 具有相同父节点的节点。 、、和元素都是同级元素<title><author><year><price>
Ancestors 节点的父节点、父节点的父节点等。 元素的祖先<title><book>元素和<bookstore>元素。
Descendants 节点的子节点、子节点的子节点等。 该元素的后代<bookstore><book><title><author><year><price>元素。
[/su_table]

XPath 元素

XPath 元素是用于从文档中选择元素的 XPath 表达式的核心。

下表包含最常见的 XPath 元素:

元素 使用
price 选择名为 的所有节点price
/ 从根节点开始选择。
// 从当前节点开始选择。
选择当前节点。
.. 选择当前节点的父节点。
@ 选择特定属性。
[/su_table]

XPath 谓词

谓词是写在方括号中的指定 XPath 表达式,用于查找特定节点或包含特定值的节点。

考虑以下代码:

<bookstore>

<book>
  <title lang="en">Harry Potter</title>
  <price>29.99</price>
</book>

<book>
  <title lang="en">Learning XML</title>
  <price>39.95</price>
</book>

</bookstore>

下表解释了 XPath 谓词及其结果。

谓词 使用
/bookstore/book[1] 选择<book>作为该元素的子元素的第一个元素<bookstore>
/bookstore/book[last()] <book>选择作为该元素的子元素的最后一个元素<bookstore>
//title[@lang] <title>选择具有名为 的属性的所有元素lang
//title[@lang='en'] 选择属性值为 的<title>所有元素。langen
/bookstore/book[price>35] 选择其中元素值大于 35<book>的所有元素。<bookstore><price>
[/su_table]

通过下面的实际示例,这一点会更清楚。

XPath 示例

现在,让我们使用 XPath 来访问真实数据,例如Etsy上的产品价格。

您需要执行以下操作:

步骤#1:进入网站,右键单击价格,然后单击检查。您将看到以下页面:

medium_image1_a3cddd305f

正如您从图像中看到的,价格位于名为 的<span>元素中。classcurrency-value

步骤 #2:要获取价格,请按 CTRL+F 打开 XPath 搜索栏并粘贴以下行:

//span[@class='currency-value']

下表解释了此 XPath 表达式的含义:

部分 使用
// 选择文档中的所有节点,无论它们位于何处。
span 选择具有<span>元素的所有节点。
[@class='currency-value'] 选择名称为 的所有类currency-value
[/su_table]

这是我们得到的结果:

medium_image3_bc732c7e6c

备注:要使用 XPath 抓取所有价格,您需要创建一个循环。请继续关注我们,我们将在以下部分中实现这一点。

Web浏览器中的XPath

网页和 HTML 通常遵循复杂的结构。因此,为了做好 XPath 网页抓取,我们需要一种快速的方法来获取我们想要抓取的元素的 XPath 语法。幸运的是,大多数 Web 浏览器都会为您生成 XPath 表达式。

为此,请打开与之前相同的网页,检查该元素,然后右键单击Copy XPath

medium_image1_2c6664c208

这样,您将获得从根节点开始的元素的完整 XPath:

//*[@id="content"]/div[1]/div[1]/div/div[3]/div[8]/div[2]/div[10]/div[1]/div/div/ol/li[1]/div/div/a[1]/div[2]/div[1]/p/span[2]

然而,与我们之前编写的 XPath 表达式相比,这个表达式非常难以阅读。

将 XPath 与 Python 和 Selenium 结合使用进行网页抓取

了解基础知识后,让我们通过使用Python(最流行的 Web 抓取语言)和Selenium(最常用的 Web 浏览器自动化工具)进行抓取来了解 XPath 在实践中如何工作。

我们的目标网站?ScrapeMe,神奇宝贝电商。

步骤#1:安装依赖项

在编辑器中打开终端并在系统上安装 Selenium 和 Chrome WebDriver。

pip install selenium webdriver-manager

步骤#2:设置环境

然后,创建一个名为 的 Python 文件scraper.py,导入依赖项并初始化 WebDriver。

from selenium import webdriver 
from webdriver_manager.chrome import ChromeDriverManager # Automatically download the web driver binaries
from selenium.webdriver.chrome.service import Service as ChromeService
from selenium.webdriver.chrome.options import Options 
from selenium.webdriver.common.by import By # Util that helps to select elements with XPath
import csv # CSV library that helps us save our result

options = Options() 
options.headless = True # Run selenium under headless mode
 
driver = webdriver.Chrome(options=options, service=ChromeService(ChromeDriverManager().install())) # Initialize the driver instance

现在我们已经准备好了抓取工具,让我们进行一些 XPath 抓取!

步骤#3:过滤 HTML 并提取数据

在抓取数据之前,我们需要设置一个 CSV 文件来保存数据。以下代码file.csv为此文件创建 和 列名称。然后,它初始化一个 CSV writer,并将数据输入到 CSV 文件中。

filecsv = open('file.csv', 'w', encoding='utf8')
csv_columns = ['name', 'price', 'img', 'link']
writer = csv.DictWriter(filecsv, fieldnames = csv_columns)
writer.writeheader()

好的,是时候获取每个 Pokémon 的 XPath 语法了。

  1. 转到ScrapeMe,右键单击任何 Pokemon,然后选择Inspect
  2. 右键单击任意li元素并选择Copy XPath

medium_4_d9106ee13a

您复制的 XPath 是这样的:

//*[@id="main"]/ul/li[3]

为了获取所有元素,请删除最后一个谓词:

//*[@id="main"]/ul/li

回到Python代码,浏览网页并find_elements使用上面的表达式选择所有神奇宝贝的方法:

driver.get("https://scrapeme.live/shop/") 

pokemons = driver.find_elements(By.XPATH, "//*[@id='main']/ul/li")

要获取每个 Pokémon 内元素的 XPath,请右键单击它们的任意名称并选择Inspect。这是我们感兴趣的数据:

medium_5_f54f6b8ea0

现在我们知道了每个元素的位置,让我们循环遍历每个 Pokémon 并使用 XPath 选择元素。

for pokemon in pokemons:
    name = pokemon.find_element(By.XPATH, ".//h2").text
    price = pokemon.find_element(By.XPATH, ".//span").text
    img = pokemon.find_element(By.XPATH, ".//img").get_attribute("src")
    link = pokemon.find_element(By.XPATH, ".//a").get_attribute("href")

我们使用该find_element方法在 Pokémon 中查找单个元素,并使用该.text方法获取名称和价格,因为它们在 HTML 中定义为文本。对于图像和链接,它们位于<src><href>标签下,因此我们get_attribute对每个都使用了该方法。

现在,将每个元素保存到文件中并关闭驱动程序。

    writer.writerow({'name': name, 'price': price, 'img': img, 'link': link})

filecsv.close()
driver.close()

这是我们得到的输出:

medium_6_ee5e7961bf

完整的代码应该是这样的:

from selenium import webdriver 
from webdriver_manager.chrome import ChromeDriverManager # Automatically download the web driver binaries
from selenium.webdriver.chrome.service import Service as ChromeService
from selenium.webdriver.chrome.options import Options 
from selenium.webdriver.common.by import By # Util that helps to select elements with XPath
import csv # CSV library that helps us save our result

options = Options() 
options.headless = True # Run selenium under headless mode
 
driver = webdriver.Chrome(options=options, service=ChromeService(ChromeDriverManager().install())) # Initialize the driver instance

filecsv = open('file.csv', 'w', encoding='utf8')
csv_columns = ['name', 'price', 'img', 'link']
writer = csv.DictWriter(filecsv, fieldnames = csv_columns)
writer.writeheader()

driver.get("https://scrapeme.live/shop/") 

pokemons = driver.find_elements(By.XPATH, "//*[@id='main']/ul/li")

for pokemon in pokemons:
    name = pokemon.find_element(By.XPATH, ".//h2").text
    price = pokemon.find_element(By.XPATH, ".//span").text
    img = pokemon.find_element(By.XPATH, ".//img").get_attribute("src")
    link = pokemon.find_element(By.XPATH, ".//a").get_attribute("href")

    writer.writerow({'name': name, 'price': price, 'img': img, 'link': link})
    
filecsv.close()
driver.close()

备注:虽然这是一个静态网站,但我们有一份关于使用 Python 进行动态网页抓取的指南,您可能会觉得有用。此外,如果您想从更复杂的网站抓取电子商务数据,请查看我们的亚马逊网络抓取教程。

CSS 与 XPath 网页抓取

有许多可用的选择器,包括类型、类、ID、XPath 和 CSS 选择器。最流行的是最新的,所以让我们讨论 CSS 选择器和 XPath 表达式之间的差异,看看哪一个最适合您的用例。

但在此之前,您需要考虑一个好的选择器应该执行以下操作

  • 只找到您需要的元素,不重复。
  • 如果 UI 发生更改,则返回相同的结果。
  • 清晰、简单易懂且快速。

XPath 唯一地标识 HTML 文档的元素,并且可以有效地查找您需要的确切元素,且不会出现重复

CSS 选择器依赖于 CSS 属性,而 XPath 则依赖于 ID、类和 HTML 结构。因此,如果 UI 发生更改,它们将无法返回相同的结果。XPath 在这里可能更有帮助。

XPath 选择器的唯一缺点是它比 CSS 选择器慢一点

结论

XPath 是一个准确的选择器,可帮助您从网站中选择和提取数据。然而,虽然它是一个很棒的工具,可以帮助您从网站获取所需的准确数据,但它本身并不能完成这项工作。

将 XPath 与ZenRows等强大工具集成将使您的网络抓取体验变得更加轻松,因为您将避免被反抓取工具阻止。

类似文章