上集回顾:
- 句法错误
- 异常
- 异常处理
- 触发异常
- finally子句
上集学习了Python代码编写过程中常见的一些错误和异常,熟悉这些知识有助于出错时快速定位错误原因。
本集学习网络请求的相关知识。现在是一个网络时代,互联网上可以说是包罗万象,只有你想不到的没有你找不到的。但互联网上最多的也是无用信息,有人甚至把互联网比作垃圾堆积场。所以要想利用好网络,就要学会利用搜索引擎等相关工具,以便在海量的信息出检索出有价值的信息。用Python程序自动收集整理目标信息也是一个很好的手段。要想检索网络信息,第一步肯定是要获取网络信息,而怎么获取网络信息就是本集的主角:urllib。
一、GET
urllib.request 是用于获取 URL (统一资源定位符)的 Python 模块。它以 urlopen 函数的形式提供了一个非常简单的接口,能用不同的协议获取 URL。
urllib.request 最简单的使用方式如下所示:
import urllib.request
with urllib.request.urlopen('http://www.baidu.com') as response:
html = response.read()
print(html[:300])
f = open('baidu.html', 'w', encoding='utf-8')
f.write(html.decode('utf-8'))
f.flush()
保存到test.py,然后命令行执行:
$ python test.py
b'<!DOCTYPE html><!--STATUS OK--><html><head><meta http-equiv="Content-Type" content="text/html;charset=utf-8"><meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1"><meta content="always" name="referrer"><meta name="theme-color" content="#ffffff"><meta name="description" content="\xe5\x85\xa8\xe7\x90\x83\xe9\xa2\x86\xe5\x85\x88\xe7'
另外还得到一个baidu.html文件,双击在浏览器打开,就是百度的界面。这就是urllib已经把百度首页的html代码获取并保存到本地了。
二、POST
有时需要向某个 URL 发送数据,通常此 URL 会指向某个CGI(通用网关接口)脚本或其他 web 应用。对于 HTTP 而言,这通常会用所谓的 POST 请求来完成。当要把 Web 页填写的 HTML 表单提交时,浏览器通常会执行此操作。但并不是所有的 POST 都来自表单:可以用 POST 方式传输任何数据到自己的应用上。对于通常的 HTML 表单,数据需要以标准的方式编码,然后作为 data
参数传给 Request 对象。编码过程是用 urllib.parse
库的函数完成的:
import urllib.parse
import urllib.request
url = 'http://www.someserver.com/cgi-bin/register.cgi'
values = {'name' : 'Michael Foord',
'location' : 'Northampton',
'language' : 'Python' }
data = urllib.parse.urlencode(values)
data = data.encode('ascii') # data should be bytes
req = urllib.request.Request(url, data)
with urllib.request.urlopen(req) as response:
the_page = response.read()
三、HTTP 头部信息
下面介绍一个具体的 HTTP 头部信息,以此说明如何在 HTTP 请求加入头部信息。
有些网站不愿被程序浏览到,或者要向不同的浏览器发送不同版本的网页。默认情况下,urllib 将自身标识为“Python-urllib/xy”(其中 x
、 y
是 Python 版本的主、次版本号,例如 Python-urllib/2.5
),这可能会让网站不知所措,或者干脆就使其无法正常工作。浏览器是通过头部信息 User-Agent
来标识自己的。在创建 Request 对象时,可以传入字典形式的头部信息。以下示例将生成与之前相同的请求,只是将自身标识为某个版本的 Internet Explorer:
import urllib.parse
import urllib.request
url = 'http://www.someserver.com/cgi-bin/register.cgi'
user_agent = 'Mozilla/5.0 (Windows NT 6.1; Win64; x64)'
values = {'name': 'Michael Foord',
'location': 'Northampton',
'language': 'Python' }
headers = {'User-Agent': user_agent}
data = urllib.parse.urlencode(values)
data = data.encode('ascii')
req = urllib.request.Request(url, data, headers)
with urllib.request.urlopen(req) as response:
the_page = response.read()
四、错误处理
如果 urlopen 无法处理响应信息,就会触发 URLError
。尽管与通常的 Python API 一样,也可能触发 ValueError
、 TypeError
等内置异常。
HTTPError
是 URLError
的子类,当 URL 是 HTTP 的情况时将会触发。
上述异常类是从 urllib.error
模块中导出的。
- URLError
触发 URLError 的原因,通常是网络不通(或者没有到指定服务器的路由),或者指定的服务器不存在。这时触发的异常会带有一个 reason 属性,是一个包含错误代码和文本错误信息的元组。
例如:
>>> req = urllib.request.Request('http://www.pretend_server.org')
>>> try: urllib.request.urlopen(req)
... except urllib.error.URLError as e:
... print(e.reason)
...
(4, 'getaddrinfo failed')
- HTTPError
从服务器返回的每个 HTTP 响应都包含一个数字的 “状态码”。有时该状态码表明服务器无法完成该请求。默认的处理函数将会处理这其中的一部分响应。如若响应是“redirection”,这是要求客户端从另一 URL 处获取数据,urllib 将会自行处理。对于那些无法处理的状况,urlopen 将会引发HTTPError
。典型的错误包括:“404”(页面无法找到)、“403”(请求遭拒绝)和“401”(需要身份认证)。
全部的 HTTP 错误码请参阅 RFC 2616 。
HTTPError
实例将包含一个整数型的“code”属性,对应于服务器发来的错误。
默认处理函数会自行处理重定向(300 以内的错误码),而且 100--299 的状态码表示成功,因此通常只会出现 400--599 的错误码。
可以如下处理:
from urllib.request import Request, urlopen
from urllib.error import URLError
req = Request(someurl)
try:
response = urlopen(req)
except URLError as e:
if hasattr(e, 'reason'):
print('We failed to reach a server.')
print('Reason: ', e.reason)
elif hasattr(e, 'code'):
print('The server couldn\'t fulfill the request.')
print('Error code: ', e.code)
else:
# everything is fine
本集总结:
- GET请求
- POST请求
- HTTP 头部信息
- 错误处理
下集见
网友评论