Python urllib 库 | Python 的 urllib.request 用于 HTTP 请求

2024 年 08 月 29 日 | 阅读 9 分钟

在本教程中,我们将学习 Python 的 urllib.request 并向示例 URL 发出 GET 请求。我们还将向示例 REST API 发出 GET 请求以获取一些 JSON 数据。我们还将学习如何使用 urllib.request 库发出 POST 请求。urllib 库在使用 Python 代码打开 URL 方面起着至关重要的作用。除了打开 URL,该库还有许多功能。稍后我们将探讨其重要功能。让我们简要介绍一下 urllib 库。

Python urllib 模块

Python 的 urllib 模块允许我们通过 Python 代码访问网站。urllib 的此功能提供了灵活性,可以在我们的 Python 代码中运行 GET、POST 和 PUT 方法并模拟 JSON 数据。我们可以使用 urllib 库下载数据、访问网站、解析数据和修改头部。urllib 有两个版本 - urllib2 和 urllib3。urllib2 用于 Python 2,urllib3 用于 Python 3。urllib3 具有一些高级功能。

有些网站不允许程序侵入其网站数据并增加其服务器负载。当它们发现此类程序时,有时可能会选择阻止该程序或提供与普通用户可能使用的不同数据。但是,我们可以通过简单的代码克服这种情况。我们只需要修改用户代理,它包含在我们发送的请求头部中。

对于那些不知道的人来说,头部是与服务器共享的数据片段,以便服务器可以了解我们。它就是 Python 版本告诉网站我们正在尝试使用 urllib 和 Python 版本访问网站的地方。

urllib 模块由几个用于处理 URL 的模块组成。它们如下所示 -

  • urllib.request 用于打开和读取。
  • urllib.parse 用于解析 URL
  • urllib.error 用于引发的异常
  • urllib.robotparser 用于解析 robot.txt 文件

大多数情况下,urllib 包会随 Python 安装一起提供,如果它不在您的环境中。我们可以使用以下命令下载它。

它将在您的环境中安装 urllib。

HTTP 消息基础

为了更好地理解 urllib.request,我们需要了解 HTTP 消息。HTTP 消息可以称为文本,以字节流的形式传输,遵循 RFC 7230 中指定的指南。解码后的 HTTP 消息可以像下面这样简单。

一个 GET 请求在根 (/) 指定,使用 HTTP/1.1 协议。HTTP 方法有两个主要部分 - 元数据和正文。上面的消息包含所有元数据,但没有正文。响应也由两部分组成 -

正如我们所看到的,响应以状态码 200 OK 开始。这是响应的元数据。我们已经展示了标准的 HTTP 消息,但有些可能会违反这些规则或遵循旧规范。我们可能会获得许多键值对数据,例如表示所有响应头部。

urllib.request

让我们了解 urllib.request.OpenURL() 方法的以下示例。我们需要导入 urllib3 模块并将 URL 的打开分配给一个变量,我们可以在其中使用 read() 命令读取数据。

当我们使用 urllib.request.urlopen() 发出请求时,它返回 HTTPResponse 对象。我们可以使用 dir() 函数打印 HTTPResponse 对象以查看不同的方法和属性。

示例 -

输出

['__abstractmethods__', '__class__', '__del__', '__delattr__', '__dict__', '__dir__', '__doc__', '__enter__', '__eq__', '__exit__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__iter__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__next__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '_abc_impl', '_checkClosed', '_checkReadable', '_checkSeekable', '_checkWritable', '_check_close', '_close_conn', '_get_chunk_left', '_method', '_peek_chunked', '_read1_chunked', '_read_and_discard_trailer', '_read_next_chunk_size', '_read_status', '_readall_chunked', '_readinto_chunked', '_safe_read', '_safe_readinto', 'begin', 'chunk_left', 'chunked', 'close', 'closed', 'code', 'debuglevel', 'detach', 'fileno', 'flush', 'fp', 'getcode', 'getheader', 'getheaders', 'geturl', 'headers', 'info', 'isatty', 'isclosed', 'length', 'msg', 'peek', 'read', 'read1', 'readable', 'readinto', 'readinto1', 'readline', 'readlines', 'reason', 'seek', 'seekable', 'status', 'tell', 'truncate', 'url', 'version', 'will_close', 'writable', 'write', 'writelines']

示例 -

输出

b'<!doctype html><html itemscope="" itemtype="http://schema.org/WebPage" lang="en-IN"><head><meta content="text/html; charset=UTF-8" http-equiv="Content-Type"><meta content="/images/branding/googleg/1x/googleg_standard_color_128dp.png" itemprop="image"><title>Google</title><script nonce="miKBzQYvtiMON4gUmZ+2qA==">(function(){window.google={kEI:\'lj1QYuXdLNOU-AaAz5XIDg\',kEXPI:\'0,1302536,56873,1710,4348,207,4804,2316,383,246,5,1354,4013,1238,1122515,1197791,610,380090,16114,19398,9286,17572,4859,1361,9290,3027,17582,4020,978,13228,3847,4192,6430,22112,629,5081,1593,1279,2742,149,1103,841,6296,3514,606,2023,1777,520,14670,3227,2845,7,17450,16320,1851,2614,13142,3,346,230,1014,1,5444,149,11325,2650,4,1528,2304,6463,576,22023,3050,2658,7357,30,13628,13795,7428,5800,2557,4094,4052,3,3541,1,16807,22235,2,3110,2,14022,1931,784,255,4550,743,5853,10463,1160,4192,1487,1020,2381,2718,18233,28,2,2,5,7754,4567,6259,3008,3,3712,2775,13920,830,422,5835,11862,3105,1539,2794,8,4669,1413,1394,445,2,2,1,6395,4561,10491,2378,701,252,1407,10,1,8591,113,5011,5,1453,637,162,2,460,2,430,586,969,593,5214,2215,2343,1866,1563,4987,791,6071,2,1,5829,227,161,983,3110,773,1217,2780,933,504,1259,957,749,6,601,23,31,748,100,1392,2738,92,2552,106,197,163,1315,1133,316,364,810,3,333,233,1586,229,81,967,2,440,357,298,258,1863,400,1698,417,4,881,219,20,396,2,397,481,75,5444944,1269,5994875,651,2801216,882,444,3,1877,1,2562,1,748,141,795,563,1,4265,1,1,2,1331,4142,2609,155,17,13,72,139,4,2,20,2,169,13,19,46,5,39,96,548,29,2,2,1,2,1,2,2,7,4,1,2,2,2,2,2,2,353,513,186,1,1,158,3,2,2,2,2,2,4,2,3,3,269,1601,141,1002,98,214,133,10,9,9,2,10,3,1,11,10,6,239

上面的代码返回 www.google.com 的源代码;我们可以使用正则表达式清理结果。网页是使用 HTML、CSS 和 JavaScript 制作的,但我们的程序通常只提取文本。因此,正则表达式变得有用;我们将在下一节中使用它。

数据传输有两种方法 - GET 和 POST。GET 方法用于获取数据,POST 方法用于通过服务器发送数据,就像我们发布一些数据并根据发布获取请求一样。我们还使用 GET 和 POST 从/向 URL 发出请求。

现在让我们看看 urllib.parse 的用途。

urllib.parse

urllib.parse 帮助定义操纵 URL 及其组件部分以创建或销毁它们的功能。有一种方法可以硬编码值并将其传递给 URL,但我们可以使用 urllib 来完成。让我们了解以下示例。

示例 -

在上面的代码中,我们定义了要与 POST 方法一起使用的值以与 URL 一起发送。为此,我们首先需要编码所有值。然后我们编码为 utf-8 字节。我们编码了字典请求。然后,我们使用带有请求的 URL 打开 URL。最后,我们使用 read() 读取该响应。

示例 -

输出

urllib.error.HTTPError: HTTP Error 405: Method Not Allowed

当我们运行上面的代码时,Google 将返回 405,方法不被允许。Google 不允许使用 Python 脚本发送请求。我们可以使用带有搜索栏的另一个网站来使用 Python 发送请求。

有时网站不喜欢被垃圾邮件发送者或机器人访问,或者它们可能会区别对待它们。过去,大多数网站都会阻止程序。维基百科曾经直接阻止程序,但现在它们会提供像 Google 这样的页面。

每次请求 URL 时,我们都会发送一个头部,其中包含有关我们的基本信息。头部中有一个 user-agent 值,它定义了访问网站服务器的浏览器。这就是 Google Analytics 确定我们正在使用什么浏览器的方式。

默认情况下,如果我们在使用 Python 3.4 版本,则 user-agent 为 urllib 3.4。这对于网站要么是未知的,要么它们会完全阻止它。

示例 -

我们已经修改了头部并运行了相同的东西。我们发出了请求,我们的响应确实不同。

常见的 urllib.request 故障

运行 urllib.request 程序时,程序可能会抛出错误。在本节中,我们将处理开始时最常见的几个错误。

在理解特定错误之前,我们将学习如何实现错误处理。

实现错误处理

Web 开发饱受错误的困扰,解决这些错误可能需要大量时间。我们将定义在使用 urllib.request 时如何处理 HTTP、URL 和超时错误。

HTTP 状态码附加在状态行中的每个响应中。如果我们在响应中读取状态码,则请求到达其目标。有预定义的状态码与响应一起使用。例如 - 200 和 201 表示成功的请求。如果请求码是 404 和 405,则表示出了问题。

也可能存在连接错误,或者提供的 URL 不正确。在这种情况下,urllib.request 将引发错误。

最后,服务器响应时间过长。可能是网络连接慢,服务器宕机,或者服务器被编程为忽略特定请求。为了克服这个问题,我们可以将 timeout 参数传递给 urlopen() 函数,以便在一定时间后引发 TimeoutError。我们需要首先使用 try...except 子句捕获它们来解决这些问题。

示例 -

request_func() 函数接受一个字符串作为参数,它将尝试使用 urllib.request 从 URL 获取请求。如果 URL 不正确,它将捕获 URLError。它还会捕获引发错误的 HTTPError 对象。如果没有错误,它将打印状态并返回正文和响应。

正如我们所观察到的,我们已经用 timeout 参数调用了 urlopen() 函数,这将导致在指定秒数后引发 TimeoutError。程序将等待十秒钟,这是等待响应的良好时间。

处理 403 错误

403 状态表示服务器理解请求但不满足它。这是我们在进行网络爬虫时常见的错误。如上所述,可以使用 User-Agent 头部解决此错误。两个主要相关的 4xx 代码有时会混淆。

  • 401 未授权
  • 403 禁止

401 错误 - 如果用户未识别或未登录并且必须执行某些操作才能获得访问权限(例如登录注册),则服务器返回此错误。

403 错误 - 如果用户已识别但无权访问该资源,则服务器返回此错误。

幸运的是,我们可以通过修改网络上的 User-Agent 字符串来处理此类错误,其中包括用户代理数据库。

请求包生态系统

本节将阐明围绕 Python HTTP 请求的包生态系统。存在多个包,没有明确的标准。我们必须熟悉满足我们要求的正确包。

什么是 urllib2 和 urllib3?

urllib 库分为多个部分。如果我们回顾 Python 1.2 的早期版本,当时原始的 urllib 被引入,大约在 1.6 版本左右,添加了一个经过改进的 urllib2。但当 Python 3 被引入时,原始的 urllib 被弃用,urllib2 放弃了 2,沿用了原始的 urllib 名称。

urllib3 是在 urllib2 仍然存在时开发的第三方库。它是一个独立维护的库。

何时应该使用 requests 而不是 urllib.requests

了解何时使用 request 或 urllib.request 库很重要。urllib.request 旨在成为一个低级库,它揭示了有关 HTTP 请求工作的许多细节。

当用户与许多不同的 REST API 交互时,强烈推荐使用 request 库。请求库的官方文档声称“为人而建”,并成功围绕 HTTP 创建了一个直观、安全、简单的 API。请求库允许我们轻松完成复杂的任务,尤其是在字符编码方面。使用 urllib 库,我们必须注意编码并采取措施确保无错误体验。

如果您更专注于学习更标准的 Python 以及如何处理 HTTP 请求,那么 urllib.request 是一个很好的入门方式。您甚至可以更进一步,使用非常低级的 http 模块。

结论

我们已经详细讨论了 urllib 库,并学习了如何使用 Python 脚本发出请求。我们可以在我们的项目中使用这个内置模块,使它们在更长时间内保持无依赖。本教程探讨了 urllib 库及其较低级的模块,例如 urllib.request,并解释了如何处理常见错误以及如何解决它们。