Python 网络数据获取神器 urllib:从入门到精通教程
在 Python 编程中,urllib包是获取网络资源的重要工具。本文详细介绍urllib包的使用方法,涵盖从简单的 URL 资源获取,到处理数据传输、HTTP 头部信息、异常情况,再到Opener和Handler的高级应用,帮助读者全面掌握利用urllib进行网络数据获取的技能,解决实际编程中的相关问题。
一、概述
urllib.request是 Python 用于获取 URL(统一资源定位符)的模块,它提供了urlopen函数,支持通过多种协议获取 URL 资源。urllib.request支持多种 “URL 方案”,本教程聚焦最常用的 HTTP 场景。在使用urllib时,简单场景下urlopen很容易使用,但遇到 HTTP 相关复杂情况时,需要了解超文本传输协议,RFC 2616 是 HTTP 的权威参考文档。
二、获取 URL 资源
(一)简单获取
使用urllib.request最简单的方式是直接调用urlopen函数,传入目标 URL。例如:
import urllib.request
with urllib.request.urlopen('http://python.org/') as response:
html = response.read()
如果想临时存储获取的资源,可以结合shutil.copyfileobj()和tempfile.NamedTemporaryFile()函数:
import shutil
import tempfile
import urllib.request
with urllib.request.urlopen('http://python.org/') as response:
with tempfile.NamedTemporaryFile(delete=False) as tmp_file:
shutil.copyfileobj(response, tmp_file)
with open(tmp_file.name) as html:
pass
(二)使用 Request 对象
urllib.request用Request对象表示 HTTP 请求。创建Request对象并传入 URL,再用urlopen打开,可获取响应。例如:
import urllib.request
req = urllib.request.Request('http://python.org/')
with urllib.request.urlopen(req) as response:
the_page = response.read()
urllib.request用同一接口处理所有 URL 方案,生成 FTP 请求只需修改 URL,如:
req = urllib.request.Request('ftp://example.com/')
三、数据传输
在 HTTP 请求中,有时需要向 URL 发送数据,通常使用 POST 请求(也可在 GET 请求中传递数据)。向服务器发送数据时,数据需编码并作为data参数传给Request对象,编码使用urllib.parse库的函数。
(一)POST 请求
例如,向 CGI 脚本发送数据:
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') # 数据应为字节串
req = urllib.request.Request(url, data)
with urllib.request.urlopen(req) as response:
the_page = response.read()
(二)GET 请求
在 GET 请求中传递数据,需将数据编码后添加到 URL 中:
import urllib.request
import urllib.parse
data = {}
data['name'] = 'Somebody Here'
data['location'] = 'Northampton'
data['language'] = 'Python'
url_values = urllib.parse.urlencode(data)
url = 'http://www.example.com/example.cgi'
full_url = url + '?' + url_values
data = urllib.request.urlopen(full_url)
四、HTTP 头部信息
HTTP 头部信息用于传递关于数据或请求本身的额外信息。有些网站会根据User - Agent头部信息识别客户端,urllib默认的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()
五、异常的处理
(一)URLError
当urlopen无法处理响应信息时,可能引发URLError(也可能引发其他内置异常)。通常是网络不通或服务器不存在导致,异常的reason属性包含错误代码和文本错误信息。例如:
import urllib.request
import urllib.error
req = urllib.request.Request('http://www.pretend_server.org')
try:
urllib.request.urlopen(req)
except urllib.error.URLError as e:
print(e.reason)
(二)HTTPError
HTTPError是URLError的子类,在 HTTP URL 特定情况下引发。服务器返回的 HTTP 响应包含状态码,默认处理器会处理部分响应,无法处理的响应会引发HTTPError,如 “404”(页面未找到)、“403”(请求遭拒)等。HTTPError实例的code属性对应服务器的错误信息。
| HTTP 错误码 | 含义 |
|---|---|
| 400 | Bad Request,请求语法错误或不支持的方法 |
| 401 | Unauthorized,需要身份认证 |
| 403 | Forbidden,请求被禁止 |
| 404 | Not Found,页面未找到 |
| 500 | Internal Server Error,服务器内部错误 |
处理异常有两种基本方案:
第一种方案:
from urllib.request import Request, urlopen
from urllib.error import URLError, HTTPError
req = Request(someurl)
try:
response = urlopen(req)
except HTTPError as e:
print('The server couldn\'t fulfill the request.')
print('Error code: ', e.code)
except URLError as e:
print('We failed to reach a server.')
print('Reason: ', e.reason)
else:
# 一切正常
第二种方案:
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:
# 一切正常
注意,except HTTPError必须首先被处理,否则except URLError将会同时捕获HTTPError。
六、info 和 geturl 方法
urlopen返回的响应(或HTTPError实例)包含两个有用的方法info()和geturl() 。
geturl():返回所获取页面的真实 URL,因为urlopen可能经过重定向,获取的页面 URL 未必是请求的 URL。info():返回一个类似字典的对象,描述所获取的页面,包含服务器送出的头部信息,如'Content - length'、'Content - type'等。
七、Opener 和 Handler
获取 URL 时会使用opener(urllib.request.OpenerDirector的实例),通常使用默认opener(通过urlopen),也可创建自定义opener。opener使用handler来处理不同的 URL 方案或特定操作。
(一)创建自定义 opener
可以实例化OpenerDirector并调用.add_handler(some_handler_instance)添加handler,也可使用build_opener便捷函数创建opener对象。例如,创建处理基本认证的opener:
import urllib.request
# 创建一个密码管理器
password_mgr = urllib.request.HTTPPasswordMgrWithDefaultRealm()
# 添加用户名和密码
top_level_url = "http://example.com/foo/"
password_mgr.add_password(None, top_level_url, username, password)
handler = urllib.request.HTTPBasicAuthHandler(password_mgr)
# 创建 "opener" (OpenerDirector 实例)
opener = urllib.request.build_opener(handler)
# 使用 opener 获取一个 URL
opener.open(a_url)
# 安装 opener,之后调用 urlopen 会使用此 opener
urllib.request.install_opener(opener)
(二)代理设置
urllib会自动检测并使用代理设置(通过ProxyHandler),但有时需要自定义。例如,不使用代理时:
import urllib.request
proxy_support = urllib.request.ProxyHandler({})
opener = urllib.request.build_opener(proxy_support)
urllib.request.install_opener(opener)
目前urllib.request尚不支持通过代理抓取https链接地址,但可通过扩展启用该功能。
八、套接字与分层
Python 获取 Web 资源的能力是分层的,urllib依赖http.client库,而http.client库又依赖套接字库。从 Python 2.3 开始,可以设置套接字等待响应的超时时间,避免程序挂起。例如:
import socket
import urllib.request
# 超时秒数
timeout = 10
socket.setdefaulttimeout(timeout)
req = urllib.request.Request('http://www.voidspace.org.uk')
response = urllib.request.urlopen(req)
总结
本文全面介绍了urllib包在 Python 中的使用方法,包括获取 URL 资源、处理数据和 HTTP 头部信息、异常处理、使用info和geturl方法,以及Opener和Handler的应用。通过学习这些内容,读者可以根据不同的网络需求,灵活运用urllib包实现各种网络数据获取任务。在实际编程中,要注意处理可能出现的异常情况,合理设置请求参数和头部信息,以确保程序的稳定性和正确性。
TAG: Python;urllib;网络资源获取;HTTP 请求;异常处理;Opener 和 Handler
学习资源和 URL
- Python 官方文档:urllib.request 文档,提供了
urllib.request模块的详细说明和函数用法。 - RFC 2616:Hypertext Transfer Protocol -- HTTP/1.1,HTTP 协议的权威文档,深入了解 HTTP 协议的基础。
- ASPN Cookbook Recipe:urllib 的 SSL 代理 opener (CONNECT 方法),用于扩展
urllib.request支持通过代理抓取https链接地址。 - HTTP 标头快速参考:可通过搜索引擎查找相关资料,了解 HTTP 标头的完整列表及其含义和用法。
浙公网安备 33010602011771号