如何用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 中转换为以下结构:
正如您所看到的,该结构是树状的,由节点和对象组成。
现在我们已经回顾了这一点,现在是时候更详细地了解 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> 元素。 |
XPath 元素
XPath 元素是用于从文档中选择元素的 XPath 表达式的核心。
下表包含最常见的 XPath 元素:
元素 | 使用 |
---|---|
price | 选择名为 的所有节点price 。 |
/ | 从根节点开始选择。 |
// | 从当前节点开始选择。 |
。 | 选择当前节点。 |
.. | 选择当前节点的父节点。 |
@ | 选择特定属性。 |
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> 所有元素。lang en |
/bookstore/book[price>35] | 选择其中元素值大于 35<book> 的所有元素。<bookstore> <price> |
通过下面的实际示例,这一点会更清楚。
XPath 示例
现在,让我们使用 XPath 来访问真实数据,例如Etsy上的产品价格。
您需要执行以下操作:
步骤#1:进入网站,右键单击价格,然后单击检查。您将看到以下页面:
正如您从图像中看到的,价格位于名为 的<span>
元素中。class
currency-value
步骤 #2:要获取价格,请按 CTRL+F 打开 XPath 搜索栏并粘贴以下行:
//span[@class='currency-value']
下表解释了此 XPath 表达式的含义:
部分 | 使用 |
---|---|
// | 选择文档中的所有节点,无论它们位于何处。 |
span | 选择具有<span> 元素的所有节点。 |
[@class='currency-value'] | 选择名称为 的所有类currency-value 。 |
这是我们得到的结果:
备注:要使用 XPath 抓取所有价格,您需要创建一个循环。请继续关注我们,我们将在以下部分中实现这一点。
Web浏览器中的XPath
网页和 HTML 通常遵循复杂的结构。因此,为了做好 XPath 网页抓取,我们需要一种快速的方法来获取我们想要抓取的元素的 XPath 语法。幸运的是,大多数 Web 浏览器都会为您生成 XPath 表达式。
为此,请打开与之前相同的网页,检查该元素,然后右键单击Copy XPath
。
这样,您将获得从根节点开始的元素的完整 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 语法了。
- 转到ScrapeMe,右键单击任何 Pokemon,然后选择
Inspect
。 - 右键单击任意
li
元素并选择Copy XPath
。
您复制的 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
。这是我们感兴趣的数据:
现在我们知道了每个元素的位置,让我们循环遍历每个 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()
完整的代码应该是这样的:
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等强大工具集成将使您的网络抓取体验变得更加轻松,因为您将避免被反抓取工具阻止。