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

使用 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 写得不好或有问题,这个库很可能会失败。在这种情况下,它包括一个回退到 美丽的汤.

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

步骤 1:选择合适的工具

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

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

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

第 2 步:确定目标网页

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

有很多项目供你尝试——我们甚至准备了一个单独的 关于一些网络抓取想法的指导。 否则,你可以 练习你的技能 在虚拟网站上——它们提供了掌握网页抓取过程所需的所有必要元素。 

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

如果你不知道一些 网页抓取挑战,这个过程可能会变成一个真正的麻烦。从 CAPTCHA 提示到 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():

				
			

步骤 2。 然后,向 IMDb 发出请求并随附您的指纹。

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

				
			

步骤 3。 检查状态代码。查找 200 – 表示请求成功。

				
					    print(response.status_code)

				
			

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

				
					    tree = etree.HTML(response.text)

				
			

提取电影数据

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

				
					    movies_list = []

				
			

步骤 2。 要查找要抓取的元素,请右键单击页面上的任意位置,然后按 检查。 寻找  标签,从 HTML 和其中的所有列表项中获取内容。

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

				
			

让我们仔细看看代码:

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

第三步:  现在,您可以遍历所有列表项。

				
					    for list_item in list_elem:

				
			

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

				
					        json = {}

				
			

步骤 5。 现在,我们来获取电影信息排名和标题。

1)首先,获取电影信息排名。查找  元素类别 米常数排名 使用 XPath 并将其分配给变量 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)让我们继续提取标题。这里的区别在于,您将选择一个  带有一类的标签 ipc-title__text 并直接将文本分配给 标题 键入你的字典。

				
					        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.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 的图片
亚当·杜波依斯
代理极客和开发人员。