我们使用联盟链接。它们让我们能够维持运营,而您无需承担任何费用。

使用 Python 的 lxml 进行网页抓取:初学者教程

使用 Python 的 lxml 进行网页抓取的分步指南。

使用 lxml Python 进行网页抓取

Python 拥有许多用于网页抓取的优秀库,lxml 就是其中之一。在本指南中,您将了解为什么应该选择 Python 的 lxml 库进行网页抓取,如何为您的项目做好准备,以及如何通过一个实际示例构建一个健壮的 lxml 抓取器。您还将找到一些通用技巧,以帮助您获得更高的请求成功率。

什么是在 Python 中使用 lxml 进行 Web 抓取?

使用 Python 的 lxml 库进行网页抓取,是指从已下载的 HTML 或 XML 代码中获取并整理数据的过程。简单来说,该工具会选择必要的数据点,并将其提取为可读格式。

Python 的 lxml 不是一个独立的库——它需要其他工具来构建抓取工具。要发出请求并下载页面的 HTML 代码,您需要使用 HTTP 客户端(如 Requests)。下载数据后,lxml 才能定义元素及其属性,并构造数据。 

因此,本质上,使用 Python 中的 lxml 进行网络爬虫意味着在 HTTP 客户端获取数据后解析数据。

为什么选择 Python 的 lxml 进行网页抓取?

选择 lxml 有几个原因:

  • 可扩展。 lxml 封装了两个 C 库 - libxml2 和 libxalt - 使解析器具有高度可扩展性。它包括速度、本机 Python API 的简单性和 XML 特性等功能。
  • 指定 XML 结构。 该库支持三种模式语言,可帮助指定 XML 结构。此外,它还可以完全实现 XPath。它是一种有用的 网页抓取技术 用于识别 XML 文档中的元素。
  • 允许遍历数据。 lxml 能够浏览不同的 XML 和 HTML 结构。该库可以遍历子元素、同级元素和其他元素,而 Beautiful Soup 等解析器则无法做到这一点。
  • 轻资源。 lxml 的一个优点是它不占用太多内存。这使得该库运行速度很快,适合解析大量数据。

但 lxml 并非适用于所有解析任务。如果目标网页的 HTML 代码编写不佳或存在错误,该库很可能会解析失败。在这种情况下,它会回退到Beautiful Soup

使用 Python 构建 lxml 解析器的步骤

步骤 1:选择合适的工具

要使用 lxml 构建功能齐全的抓取工具,您还需要其他 Python 依赖项。

首先,选择一个 HTTP 客户端来获取数据。您可以使用 Python 的库,如 Requests、HTTPX 或 aiohttp。选择哪个取决于您的偏好和您心中的网页抓取项目。如果您不熟悉任何一个,请选择 Requests - 它是最古老的一个,并且非常可定制。

如果你想更进一步,通过抓取动态网站(例如电商网站或社交媒体网站)来提升技能,那么仅仅使用 HTTP 客户端和解析器是不够的。你需要一个能够渲染 JavaScript 的工具。在这种情况下,可以使用像Selenium这样的无头浏览器库来处理异步和 AJAX 请求。

第 2 步:确定目标网页

现在您已准备好工具,可以识别目标网页。例如,您可能希望抓取 Google 搜索结果以监控您和竞争对手的 Google 排名,或者从亚马逊等电子商务商店收集产品信息。 

我们提供了许多项目供您尝试——我们甚至专门准备了一份关于网络爬虫技巧的指南。此外,您也可以在模拟网站上练习——它们提供了掌握网络爬虫流程所需的所有要素。

步骤 3:查看网页抓取指南

如果你不了解一些网络爬虫的挑战,整个过程可能会变得非常棘手。从验证码提示到 IP 地址封禁,这些障碍都可能阻碍你的项目成功。因此,如果你认真对待你的项目,我建议你使用轮换代理服务器,它会根据需要更改你的 IP 地址和位置。

无论目标是什么(除了网络爬虫沙箱),您都应该知道网站通常会使用名为 robots.txt 的文件来管理机器人流量。它规定了您可以抓取哪些页面、哪些页面不能抓取,以及抓取的频率。总之,网络爬虫需要遵循这些以及其他准则——请花时间熟悉网络爬虫的最佳实践

此外,浏览器发出的请求包含带有设备信息的标头。你为什么要关心?如果用户代理字符串(一个重要的标头)缺失或格式错误,页面可能不允许你的抓取工具获取数据。大多数 HTTP 客户端都会发送其用户代理标头,因此在抓取真实目标时你需要更改它。但别担心——我稍后会告诉你如何操作。

使用 Python 的 lxml 进行 Web 抓取:分步教程

在本分步教程中,我们将从 IMDb 抓取本月最受欢迎的电影(及其所有信息)。由于 Python 的 lxml 是一个 Web 解析库,我们还将使用 Requests 下载数据。

该平台提供了更多有趣的列表供抓取 - 但请记住检查 robots.txt 并遵守其他网络抓取指南!

IMDb最受欢迎的电影截图
我们要抓取的 IMDb 页面。

硬件需求

  • Python 3。 检查您的设备上是否安装了最新版本。否则,请从 Python.org 下载。 
  • 要求。 填写 pip install requests 在您的操作系统终端中。 
  • lxml。 通过运行添加 pip install lxml
  • 代码编辑器。 您可以选择任何代码编辑器。例如,Notepad++、Visual Studio Code 或操作系统的文本编辑器。

导入库

步骤 1.首先,让我们导入必要的库。

				
					import requests
from lxml import etree
				
			

步骤 2.然后,定义你要抓取的 URL。

				
					url = "https://www.imdb.com/chart/moviemeter/"

				
			

添加指纹(标题)

现在,让我们在请求中添加指纹,使其看起来类似于 Chrome v116。请注意:浏览器版本变化很快,因此这可能已经过时了。 注意: 这是一个创建指纹的有用站点: https://httpbin.org/headers.
				
					headers = {
    "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7",
    "Accept-Encoding": "gzip, deflate, br",
    "Accept-Language": "en-US,en;q=0.9",
    "Referer": "https://www.google.com/",
    "Sec-Ch-Ua": "\"Chromium\";v=\"116\", \"Not)A;Brand\";v=\"24\", \"Google Chrome\";v=\"116\"", 
    "Sec-Ch-Ua-Mobile": "?0", 
    "Sec-Ch-Ua-Platform": "\"Windows\"", 
    "Sec-Fetch-Dest": "document", 
    "Sec-Fetch-Mode": "navigate", 
    "Sec-Fetch-Site": "cross-site", 
    "Sec-Fetch-User": "?1",
    "Upgrade-Insecure-Requests": "1",
    "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/116.0.0.0 Safari/537.36",
}
				
			

获取 HTML 内容

步骤 1.定义主要网络爬虫功能。

				
					def request():

				
			

第二步,向 IMDb 提出请求,并附上您的指纹。

				
					    response = requests.get(url, headers=headers)

				
			

步骤三:检查状态码。查找 200——这表示请求成功。

				
					    print(response.status_code)

				
			

步骤 4.收到响应后,使用lxml 提供的etree.HTML()解析器解析 HTML 内容。

				
					    tree = etree.HTML(response.text)

				
			

提取电影数据

步骤 1.创建一个新列表来保存你要抓取的电影信息。

				
					    movies_list = []

				
			

步骤 2.要查找要抓取的元素,请在页面上的任意位置单击鼠标右键,然后选择“检查”。查找<ul>标签,从 HTML 中提取内容以及其中的所有列表项。

列表项的示例。
列表项的示例。
				
					list_elem = tree.xpath(".//ul[contains(@class,'ipc-metadata-list')]/li")

				
			

让我们仔细看看代码:

  • ul – 无序列表标签。
  • li – 列表项。此选择器查找  包含一个元素 ipc 元数据列表t 类。您还需要  元件。
  • 标签 – 合并选定的列表项并将结果分配给新变量。 
  • 列表元素 – 所有列表项对象的列表。

步骤 3:现在,您可以遍历列表中的所有项目。

				
					    for list_item in list_elem:

				
			

步骤 4.创建一个json对象来存储信息。

				
					        json = {}

				
			

第五步。现在,让我们获取电影信息排名和片名。

1)首先,获取电影信息排名。使用 XPath 查找类名为meter-const-ranking的<div>元素,并将其赋值给变量movie_rank_elem

				
					        movie_rank_elem = list_item.xpath(".//div[contains(@class, 'meter-const-ranking')]")
				
			

2) movie_rank_elem本身也是一个 lxml 元素,因此我们可以使用xpath()函数来选择该元素内的内容。获取元素内的文本,由于该函数返回一个包含单个元素的列表,因此只需从列表中取出第一个元素并将其赋值给json字典即可。

				
					        json['rank_num'] = movie_rank_elem[0].xpath(".//text()")[0]

				
			

3) 接下来我们来提取标题。这里的区别在于,你需要选择一个class 为ipc-title__text的<h3>标签,并将文本直接赋值给字典中的title键。

				
					        json['title'] = list_item.xpath(".//h3[@class='ipc-title__text']/text()")[0]

				
			

步骤 6.现在,获取影片的发行日期、片长和内容分级信息。由于这些数据点没有特定的类名可以直接选择,因此流程略有不同。您需要选择具有相同标签和类名的元素,最终得到一个仅包含 1 到 3 个项目的列表。

				
					        movie_metadata_elems = list_item.xpath(".//span[contains(@class, 'cli-title-metadata-item')]")

				
			

注意:由于movie_metadata_elems列表包含 lxml 元素,因此您可以通过索引访问每个元素。

1)发布日期是第一项,因此其索引为 0,长度为 1,内容评级为 2。 

注意:并非所有电影都有内容分级,因此请查看片长以确认是否有分级。通过索引访问每个元素后,使用 XPath 获取文本值并将其赋值给字典。

				
					        json['release_date'] = movie_metadata_elems[0].xpath(".//text()")[0]
        json['length'] = movie_metadata_elems[1].xpath(".//text()")[0]
        if len(movie_metadata_elems) > 2:
            json['content_rating'] = movie_metadata_elems[2].xpath(".//text()")[0]
        else:
            json['content_rating']: None
				
			

2)要获取每部电影的评分和投票数,使用与之前类似的方法,选择每个元素并获取其中的文本。 

注意:并非每部电影都包含这两个元素中的一个或两个。为了解决这个问题,请添加一个“if”语句,以便在将结果添加到字典之前先返回一个列表。

				
					        movie_rating_elem = list_item.xpath(".//span[contains(@class, 'ipc-rating-star')]/text()")
        if movie_rating_elem: 
            json['rating'] = movie_rating_elem[0]
        movie_vote_count_elem = list_item.xpath(".//span[contains(@class, 'ipc-rating-star--voteCount')]/text()")
        if movie_vote_count_elem:
            json['vote_count'] = movie_vote_count_elem[1]
        json['url'] = "https://www.imdb.com/"+list_item.xpath(".//div[contains(@class, 'ipc-title')]/a/@href")[0]
				
			

步骤 7.然后,将json字典添加到movies_list列表中,让脚本继续解析下一个电影的列表项。

				
					        movies_list.append(json)

				
			

步骤 8.最后,打印输出结果。

				
					    print (movies_list)

if __name__ == "__main__":
request()
				
			
产量
输出。
这是完整的代码:
				
					import requests
from lxml import etree

url = "https://www.imdb.com/chart/moviemeter/"

headers = {
    "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7",
    "Accept-Encoding": "gzip, deflate, br",
    "Accept-Language": "en-US,en;q=0.9",
    "Referer": "https://www.google.com/",
    "Sec-Ch-Ua": "\"Chromium\";v=\"116\", \"Not)A;Brand\";v=\"24\", \"Google Chrome\";v=\"116\"",
    "Sec-Ch-Ua-Mobile": "?0",
    "Sec-Ch-Ua-Platform": "\"Windows\"",
    "Sec-Fetch-Dest": "document",
    "Sec-Fetch-Mode": "navigate",
    "Sec-Fetch-Site": "cross-site",
    "Sec-Fetch-User": "?1",
    "Upgrade-Insecure-Requests": "1",
    "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/116.0.0.0 Safari/537.36",
}

def request():
    response = requests.get(url, headers=headers)
    print(response.status_code)
    tree = etree.HTML(response.text)
    movies_list = []
    list_elem = tree.xpath(".//ul[contains(@class,'ipc-metadata-list')]/li")
    for list_item in list_elem:
        json = {}
        movie_rank_elem = list_item.xpath(".//div[contains(@class, 'meter-const-ranking')]")
        json['rank_num'] = movie_rank_elem[0].xpath(".//text()")[0]
        json['title'] = list_item.xpath(".//h3[@class='ipc-title__text']/text()")[0]
        movie_metadata_elems = list_item.xpath(".//span[contains(@class, 'cli-title-metadata-item')]")
        json['release_date'] = movie_metadata_elems[0].xpath(".//text()")[0]
        json['length'] = movie_metadata_elems[1].xpath(".//text()")[0]
        if len(movie_metadata_elems) > 2:
            json['content_rating'] = movie_metadata_elems[2].xpath(".//text()")[0]
        else:
            json['content_rating'] = None
        movie_rating_elem = list_item.xpath(".//span[contains(@class, 'ipc-rating-star')]/text()")
        if movie_rating_elem:
            json['rating'] = movie_rating_elem[0]
        movie_vote_count_elem = list_item.xpath(".//span[contains(@class, 'ipc-rating-star--voteCount')]/text()")
        if movie_vote_count_elem:
            json['vote_count'] = movie_vote_count_elem[1]
        json['url'] = "https://www.imdb.com/" + list_item.xpath(".//div[contains(@class, 'ipc-title')]/a/@href")[0]
        movies_list.append(json)
    print(movies_list)

if __name__ == "__main__":
    request()
				
			
Adam Dubois 的图片
亚当·杜波依斯
代理极客和开发人员。