Python的urllib.request用于HTTP请求

Python的urllib.request用于HTTP请求

在本教程中,我们将学习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方法以及在我们的Python代码中模拟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安装一起提供,如果没有在您的环境中,可以使用以下命令下载:

pip install urllib

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

HTTP消息的基础

为了更好地理解urllib.request,我们需要了解HTTP消息。HTTP消息可以被视为文本,以字节流的形式传输,遵循RFC 7230指定的指南。解码的HTTP消息可以如下所示。

GET / HTTP/1.1
Host: www.google.com

GET请求使用HTTP/1.1协议在根路径(/)进行。HTTP方法有两个主要部分-元数据和主体。上述消息具有所有元数据但没有主体。响应也由两个部分组成-

HTTP/1.1 200 OK
Content-Type: text/html; charset=ISO-8859-1
Server: gws
(... other headers ...)

<!doctype html><html itemscope="" itemtype="http://schema.org/WebPage"

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

urllib.request

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

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

示例

from urllib.request import urlopen
with urlopen("https://www.google.com") as response:
    print(dir(response))

输出:

['__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']

示例

import urllib.request

request_url = urllib.request.urlopen('https://www.google.com/')
print(request_url.read())

输出:

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来完成。让我们理解以下示例。

示例

# used to parse values into the url
import urllib.parse

url = 'https://www.google.com/search'
values = {'query' : 'python tutorial'}

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

示例

data = urllib.parse.urlencode(values)
data = data.encode('utf-8') # data should be bytes
req = urllib.request.Request(url, data)
resp = urllib.request.urlopen(req)
respData = resp.read()

print(respData)

输出:

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

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

有时,网站不喜欢被垃圾邮件发送者或机器人访问,或者它们可能对它们进行不同的处理。在过去,大多数网站会阻止程序。维基百科曾经直接阻止程序,但现在它们会提供一个类似Google的页面。

每次请求URL时,我们都会发送一个标头,其中包含关于我们的基本信息。标头中有一个用户代理值,用于定义访问网站服务器的浏览器。这就是Google Analytics确定我们使用的浏览器的方式。

默认情况下,如果我们使用Python 3.4版本,则urllib的用户代理为3.4。这要么在网站上是未知的,否则它们将完全阻止它。

示例:

import urllib.parse
import urllib.request

try:
    url = 'https://www.google.com/search?q=python-tutorial'

    # now, with the below headers, we defined ourselves as a simpleton who is
    # still using internet explorer.
    headers = {}
    headers['User-Agent'] = "Mozilla/5.0 (X11; Linux i686) AppleWebKit/537.17 (KHTML, like Gecko) Chrome/24.0.1312.27 Safari/537.17"
    request = urllib.request.Request(url, headers = headers)
    resp = urllib.request.urlopen(request)
    respData = resp.read()

    saveFile = open('ModifyHeaders.txt','w')
    saveFile.write(str(respData))
    saveFile.close()
except Exception as e:
    print(str(e))

我们已经修改了我们的标题,并运行了相同的内容。我们发出请求,我们的响应确实是不同的。

常见的urllib.request问题

在运行urllib.request程序时,程序可能会抛出错误。在本节中,我们将解决一些最常见的在刚开始时遇到的错误。

在了解具体的错误之前,我们将学习如何实施错误处理。

实施错误处理

Web开发常常出现错误,解决这些错误可能需要很长时间。我们将定义如何处理在使用urllib.request时出现的HTTP、URL和超时错误。

每个响应的状态行中都附带有HTTP状态码。如果我们能够读取响应中的状态码,那么请求就会到达目标。有预定义的状态码与响应配对使用。例如- 200和201代表成功的请求。如果请求的状态码是404和405,则表示有问题。

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

最后,服务器需要很长时间才能响应。可能是网络连接慢,服务器停机,或者服务器被编程忽略特定的请求。为了解决这个问题,我们可以通过向 urlopen() 函数传递一个超时参数,在一定时间后引发 TimeoutError 。我们需要先使用try….expect子句捕获这些错误来解决这些问题。

示例

from urllib.error import HTTPError, URLError
from urllib.request import urlopen

def request_func(url):
    try:
        with urlopen(url, timeout=10) as response:
            print(response.status)
            return response.read(), response
    except HTTPError as error:
        print(error.status, error.reason)
    except URLError as error:
        print(error.reason)
    except TimeoutError:
        print("Request timed out")

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

正如我们所观察到的,我们调用了带有超时参数的 urlopen() 函数,它将在指定的秒数后引发一个 TimeoutError 。程序将等待十秒钟,这是等待响应的一个很好的时间。

处理403错误

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

  • 401未授权
  • 403禁止访问

401错误 – 如果用户未经识别或登录,并且必须做些什么才能获得访问权限(如登录或注册),服务器将返回此错误。

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

幸运的是,我们可以通过修改网络上的User-Agent字符串来处理这种错误,包括一个User-Agent数据库。

请求包生态系统

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

什么是urllib2和urllib3

urllib库被分成了几个部分。如果我们回顾早期版本的Python 1.2,当最初的urllib被引入时,大约在版本1.6左右,新增了一种改进的urllib2。但是,当引入Python 3时,原始的urllib被弃用,并且urllib2去掉了”2″,使用了原始的urllib名称。

  • urllib.error
  • urllib.parse
  • urllib.request
  • urllib.response
  • urllib.robotparser

urllib3是一个独立开发的第三方库,它是在urllib2还存在时开发的。

何时使用requests而不是urllib.requests

重要的是要知道何时使用request或urllib.request库。urllib.request旨在成为一个低级别的库,揭示了关于HTTP请求工作的许多细节。

请求 库在用户与许多不同的 REST API 进行交互时是非常推荐的。请求库的官方文档声称它是“为人类而建”,并成功地创建了一个直观、安全和简单的 HTTP API。请求库使我们能够轻松地执行复杂的任务,特别是在字符编码方面。使用 urllib 库时,我们必须注意编码,并采取措施确保没有错误的体验。

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

结论

我们详细讨论了 urllib 库,并学习了如何使用 Python 脚本进行请求。我们可以在项目中使用这个内置模块,使它们长时间不依赖其他库。本教程探讨了 urllib 库及其低级模块,如 urllib.request,并解释了如何处理常见错误以及如何解决它们。

Camera课程

Python教程

Java教程

Web教程

数据库教程

图形图像教程

办公软件教程

Linux教程

计算机教程

大数据教程

开发工具教程