Python使用urllib2获取网络资源实例讲解


Posted in Python onDecember 02, 2013

这是具有利用不同协议获取URLs的能力,他同样提供了一个比较复杂的接口来处理一般情况,例如:基础验证,cookies,代理和其他。
它们通过handlers和openers的对象提供。
urllib2支持获取不同格式的URLs(在URL的":"前定义的字串,例如:"ftp"是"ftp:python.ort/"的前缀),它们利用它们相关网络协议(例如FTP,HTTP)
进行获取。这篇教程关注最广泛的应用--HTTP。
对于简单的应用,urlopen是非常容易使用的。但当你在打开HTTP的URLs时遇到错误或异常,你将需要一些超文本传输协议(HTTP)的理解。
最权威的HTTP文档当然是RFC 2616(http://rfc.net/rfc2616.html)。这是一个技术文档,所以并不易于阅读。这篇HOWTO教程的目的是展现如何使用urllib2,
并提供足够的HTTP细节来帮助你理解。他并不是urllib2的文档说明,而是起一个辅助作用。
获取 URLs

最简单的使用urllib2将如下所示

import urllib2
response = urllib2.urlopen('http://python.org/')
html = response.read()

urllib2的很多应用就是那么简单(记住,除了"http:",URL同样可以使用"ftp:","file:"等等来替代)。但这篇文章是教授HTTP的更复杂的应用。
HTTP是基于请求和应答机制的--客户端提出请求,服务端提供应答。urllib2用一个Request对象来映射你提出的HTTP请求,在它最简单的使用形式中你将用你要请求的
地址创建一个Request对象,通过调用urlopen并传入Request对象,将返回一个相关请求response对象,这个应答对象如同一个文件对象,所以你可以在Response中调用.read()。

import urllib2
req = urllib2.Request('https://3water.com')
response = urllib2.urlopen(req)
the_page = response.read()

记得urllib2使用相同的接口处理所有的URL头。例如你可以像下面那样创建一个ftp请求。

req = urllib2.Request('ftp://example.com/')

在HTTP请求时,允许你做额外的两件事。首先是你能够发送data表单数据,其次你能够传送额外的关于数据或发送本身的信息("metadata")到服务器,此数据作为HTTP的"headers"来发送。
接下来让我们看看这些如何发送的吧。
Data数据
有时候你希望发送一些数据到URL(通常URL与CGI[通用网关接口]脚本,或其他WEB应用程序挂接)。在HTTP中,这个经常使用熟知的POST请求发送。这个通常在你提交一个HTML表单时由你的浏览器来做。
并不是所有的POSTs都来源于表单,你能够使用POST提交任意的数据到你自己的程序。一般的HTML表单,data需要编码成标准形式。然后做为data参数传到Request对象。编码工作使用urllib的函数而非
urllib2。

import urllib
import urllib2
url = 'https://3water.com'
values = {'name' : 'Michael Foord',
          'location' : 'Northampton',
          'language' : 'Python' }
data = urllib.urlencode(values)
req = urllib2.Request(url, data)
response = urllib2.urlopen(req)
the_page = response.read()

记住有时需要别的编码(例如从HTML上传文件--看http://www.w3.org/TR/REC-html40/interact/forms.html#h-17.13 HTML Specification, Form Submission的详细说明)。
如ugoni没有传送data参数,urllib2使用GET方式的请求。GET和POST请求的不同之处是POST请求通常有"副作用",它们会由于某种途径改变系统状态(例如提交成堆垃圾到你的门口)。
尽管HTTP标准说的很清楚POSTs通常会产生副作用,GET请求不会产生副作用,但没有什么可以阻止GET请求产生副作用,同样POST请求也可能不产生副作用。Data同样可以通过在Get请求
的URL本身上面编码来传送。
可看如下例子

 >>> import urllib2 
 >>> import urllib 
 >>> data = {} 
 >>> data['name'] = 'Somebody Here' 
 >>> data['location'] = 'Northampton' 
 >>> data['language'] = 'Python' 
 >>> url_values = urllib.urlencode(data) 
 >>> print url_values 
 name=Somebody+Here&language=Python&location=Northampton 
 >>> url = 'https://3water.com' 
 >>> full_url = url + '?' + url_values 
 >>> data = urllib2.open(full_url)

Headers
我们将在这里讨论特定的HTTP头,来说明怎样添加headers到你的HTTP请求。
有一些站点不喜欢被程序(非人为访问)访问,或者发送不同版本的内容到不同的浏览器。默认的urllib2把自己作为“Python-urllib/x.y”(x和y是Python主版本和次版本号,例如Python-urllib/2.5),
这个身份可能会让站点迷惑,或者干脆不工作。浏览器确认自己身份是通过User-Agent头,当你创建了一个请求对象,你可以给他一个包含头数据的字典。下面的例子发送跟上面一样的内容,但把自身
模拟成Internet Explorer。

import urllib
import urllib2
url = 'https://3water.com'
user_agent = 'Mozilla/4.0 (compatible; MSIE 5.5; Windows NT)'
values = {'name' : 'Michael Foord',
          'location' : 'Northampton',
          'language' : 'Python' }
headers = { 'User-Agent' : user_agent }
data = urllib.urlencode(values)
req = urllib2.Request(url, data, headers)
response = urllib2.urlopen(req)
the_page = response.read()

response应答对象同样有两个很有用的方法。看下面的节info and geturl,我们将看到当发生错误时会发生什么。
Handle Exceptions处理异常
当urlopen不能够处理一个response时,产生urlError(不过通常的Python APIs异常如ValueError,TypeError等也会同时产生)。
HTTPError是urlError的子类,通常在特定HTTP URLs中产生。
URLError
通常,URLError在没有网络连接(没有路由到特定服务器),或者服务器不存在的情况下产生。这种情况下,异常同样会带有"reason"属性,它是一个tuple,包含了一个错误号和一个错误信息。
例如

>>> req = urllib2.Request('https://3water.com')
>>> try: urllib2.urlopen(req)
>>> except URLError, e:
>>>    print e.reason
>>>
(4, 'getaddrinfo failed')

HTTPError
服务器上每一个HTTP 应答对象response包含一个数字"状态码"。有时状态码指出服务器无法完成请求。默认的处理器会为你处理一部分这种应答(例如:假如response是一个"重定向",需要客户端从别的地址获取文档
,urllib2将为你处理)。其他不能处理的,urlopen会产生一个HTTPError。典型的错误包含"404"(页面无法找到),"403"(请求禁止),和"401"(带验证请求)。
请看RFC 2616 第十节有所有的HTTP错误码
HTTPError实例产生后会有一个整型'code'属性,是服务器发送的相关错误号。
Error Codes错误码
因为默认的处理器处理了重定向(300以外号码),并且100-299范围的号码指示成功,所以你只能看到400-599的错误号码。
BaseHTTPServer.BaseHTTPRequestHandler.response是一个很有用的应答号码字典,显示了RFC 2616使用的所有的应答号。这里为了方便重新展示该字典。(译者略)
当一个错误号产生后,服务器返回一个HTTP错误号,和一个错误页面。你可以使用HTTPError实例作为页面返回的应答对象response。这表示和错误属性一样,它同样包含了read,geturl,和info方法。

>>> req = urllib2.Request('http://www.python.org/fish.html')
>>> try:
>>>     urllib2.urlopen(req)
>>> except URLError, e:
>>>     print e.code
>>>     print e.read()
>>>
404
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
  "http://www.w3.org/TR/html4/loose.dtd">
<?xml-stylesheet href="./css/ht2html.css"
  type="text/css"?>
<html><head><title>Error 404: File Not Found</title>
...... etc...

Wrapping it Up包装
所以如果你想为HTTPError或URLError做准备,将有两个基本的办法。我则比较喜欢第二种。
第一个:
from urllib2 import Request, urlopen, URLError, HTTPError
req = Request(someurl)
try:
    response = urlopen(req)
except HTTPError, e:
    print 'The server couldn\'t fulfill the request.'
    print 'Error code: ', e.code
except URLError, e:
    print 'We failed to reach a server.'
    print 'Reason: ', e.reason
else:
    # everything is fine

注意:except HTTPError 必须在第一个,否则except URLError将同样接受到HTTPError。
第二个:

from urllib2 import Request, urlopen, URLError
req = Request(someurl)
try:
    response = urlopen(req)
except URLError, 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

info and geturl
urlopen返回的应答对象response(或者HTTPError实例)有两个很有用的方法info()和geturl()
geturl -- 这个返回获取的真实的URL,这个很有用,因为urlopen(或者opener对象使用的)或许
会有重定向。获取的URL或许跟请求URL不同。
info -- 这个返回对象的字典对象,该字典描述了获取的页面情况。通常是服务器发送的特定头headers。目前是httplib.HTTPMessage 实例。
经典的headers包含"Content-length","Content-type",和其他。查看Quick Reference to HTTP Headers(http://www.cs.tut.fi/~jkorpela/http.html)
获取有用的HTTP头列表,以及它们的解释意义。
Openers和Handlers
当你获取一个URL你使用一个opener(一个urllib2.OpenerDirector的实例,urllib2.OpenerDirector可能名字可能有点让人混淆。)正常情况下,我们
使用默认opener -- 通过urlopen,但你能够创建个性的openers,Openers使用处理器handlers,所有的“繁重”工作由handlers处理。每个handlers知道
如何通过特定协议打开URLs,或者如何处理URL打开时的各个方面,例如HTTP重定向或者HTTP cookies。
如果你希望用特定处理器获取URLs你会想创建一个openers,例如获取一个能处理cookie的opener,或者获取一个不重定向的opener。
要创建一个 opener,实例化一个OpenerDirector,然后调用不断调用.add_handler(some_handler_instance).
同样,可以使用build_opener,这是一个更加方便的函数,用来创建opener对象,他只需要一次函数调用。
build_opener默认添加几个处理器,但提供快捷的方法来添加或更新默认处理器。
其他的处理器handlers你或许会希望处理代理,验证,和其他常用但有点特殊的情况。
install_opener 用来创建(全局)默认opener。这个表示调用urlopen将使用你安装的opener。
Opener对象有一个open方法,该方法可以像urlopen函数那样直接用来获取urls:通常不必调用install_opener,除了为了方便。

Python 相关文章推荐
python使用新浪微博api上传图片到微博示例
Jan 10 Python
python 调用HBase的简单实例
Dec 18 Python
Python中工作日类库Busines Holiday的介绍与使用
Jul 06 Python
神经网络理论基础及Python实现详解
Dec 15 Python
详解Python 数据库的Connection、Cursor两大对象
Jun 25 Python
Python3 jupyter notebook 服务器搭建过程
Nov 30 Python
Python函数装饰器常见使用方法实例详解
Mar 30 Python
PyQt5笔记之弹出窗口大全
Jun 20 Python
Python机器学习算法库scikit-learn学习之决策树实现方法详解
Jul 04 Python
Python2比较当前图片跟图库哪个图片相似的方法示例
Sep 28 Python
用python拟合等角螺线的实现示例
Dec 27 Python
多个python文件调用logging模块报错误
Feb 12 Python
python读写文件操作示例程序
Dec 02 #Python
python通过ElementTree操作XML获取结点读取属性美化XML
Dec 02 #Python
一个简单的python程序实例(通讯录)
Nov 29 #Python
Python时间戳与时间字符串互相转换实例代码
Nov 28 #Python
python计算程序开始到程序结束的运行时间和程序运行的CPU时间
Nov 28 #Python
SublimeText 2编译python出错的解决方法(The system cannot find the file specified)
Nov 27 #Python
Pyramid添加Middleware的方法实例
Nov 27 #Python
You might like
PHP对象转换为数组函数(递归方法)
2012/02/04 PHP
PHP中图片等比缩放的实例
2013/03/24 PHP
解析thinkphp的左右值无限分类
2013/06/20 PHP
wamp服务器访问php非常缓慢的解决过程
2015/07/01 PHP
PHP使用Mysqli类库实现完美分页效果的方法
2016/04/07 PHP
比较完整的微信开发php代码
2016/08/02 PHP
浅谈tudou土豆网首页图片延迟加载的效果
2010/06/23 Javascript
Node.js中调用mysql存储过程示例
2014/12/20 Javascript
js+cookies实现悬浮购物车的方法
2015/05/25 Javascript
详解JavaScript UTC时间转换方法
2016/01/07 Javascript
探讨JavaScript标签位置的存放与功能有无关系
2016/01/15 Javascript
javascript面向对象程序设计高级特性经典教程(值得收藏)
2016/05/19 Javascript
jQuery通过deferred对象管理ajax异步
2016/05/20 Javascript
浅谈javascript中遇到的字符串对象处理
2016/11/18 Javascript
jQuery实现可兼容IE6的淡入淡出效果告警提示功能示例
2017/09/20 jQuery
jQuery.validate.js表单验证插件的使用代码详解
2018/10/22 jQuery
react-native聊天室|RN版聊天App仿微信实例|RN仿微信界面
2019/11/12 Javascript
JS获取当前时间的年月日时分秒及时间的格式化的方法
2019/12/18 Javascript
[51:36]Optic vs Newbee 2018国际邀请赛小组赛BO2 第一场 8.17
2018/08/18 DOTA
将图片文件嵌入到wxpython代码中的实现方法
2014/08/11 Python
Python复制目录结构脚本代码分享
2015/03/06 Python
Linux 发邮件磁盘空间监控(python)
2016/04/23 Python
对pandas的算术运算和数据对齐实例详解
2018/12/22 Python
Python3 实现减少可调用对象的参数个数
2019/12/20 Python
Python求两个字符串最长公共子序列代码实例
2020/03/05 Python
浅谈JupyterNotebook导出pdf解决中文的问题
2020/04/22 Python
Python基于pandas绘制散点图矩阵代码实例
2020/06/04 Python
Tensorflow与Keras自适应使用显存方式
2020/06/22 Python
Python实现图片查找轮廓、多边形拟合、最小外接矩形代码
2020/07/14 Python
New Balance加拿大官方网站:运动鞋和健身服装
2018/11/19 全球购物
Looking4Parking美国:全球排名第一的机场停车比较品牌
2019/08/26 全球购物
中国央视网签名寄语
2014/01/18 职场文书
巴西世界杯32强口号
2014/06/05 职场文书
社区反邪教工作方案
2014/06/16 职场文书
副乡长群众路线教育实践活动个人对照检查材料
2014/09/19 职场文书
python单向链表实例详解
2022/05/25 Python