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开发的nosql数据库CodernityDB介绍和使用实例
Oct 23 Python
在Python的Django框架中实现Hacker News的一些功能
Apr 17 Python
Python探索之URL Dispatcher实例详解
Oct 28 Python
python实现装饰器、描述符
Feb 28 Python
基于python list对象中嵌套元组使用sort时的排序方法
Apr 18 Python
python实现美团订单推送到测试环境,提供便利操作示例
Aug 09 Python
Django框架创建项目的方法入门教程
Nov 04 Python
Python基础之字符串操作常用函数集合
Feb 09 Python
pandas中的数据去重处理的实现方法
Feb 10 Python
python中温度单位转换的实例方法
Dec 27 Python
Python3的进程和线程你了解吗
Mar 16 Python
python热力图实现的完整实例
Jun 25 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
phpmyadmin的#1251问题
2006/11/25 PHP
php下检测字符串是否是utf8编码的代码
2008/06/28 PHP
YII路径的用法总结
2014/07/09 PHP
用JavaScript脚本实现Web页面信息交互
2006/10/11 Javascript
js实现鼠标悬浮给图片加边框的方法
2015/01/30 Javascript
Highcharts入门之基本属性
2016/08/02 Javascript
收藏AngularJS中最重要的核心功能
2017/07/09 Javascript
BootStrap模态框和select2合用时input无法获取焦点的解决方法
2017/09/01 Javascript
nodejs中安装ghost出错的原因及解决方法
2017/10/23 NodeJs
Node对CommonJS的模块规范
2019/11/06 Javascript
react国际化化插件react-i18n-auto使用详解
2020/03/31 Javascript
JS实现购物车基本功能
2020/11/08 Javascript
vue登录页实现使用cookie记住7天密码功能的方法
2021/02/18 Vue.js
[02:34]DOTA2英雄基础教程 幽鬼
2014/01/02 DOTA
[01:29]2014DOTA2展望TI 剑指西雅图DK战队专访
2014/06/30 DOTA
浅析Python中的多进程与多线程的使用
2015/04/07 Python
Python基于回溯法子集树模板解决取物搭配问题实例
2017/09/02 Python
详解PyCharm配置Anaconda的艰难心路历程
2018/08/13 Python
对Python 3.2 迭代器的next函数实例讲解
2018/10/18 Python
Python面向对象之类的封装操作示例
2019/06/08 Python
django admin组件使用方法详解
2019/07/19 Python
PyCharm2019 安装和配置教程详解附激活码
2020/07/31 Python
python根据用户需求输入想爬取的内容及页数爬取图片方法详解
2020/08/03 Python
马来西亚网上购物:Youbeli
2018/03/30 全球购物
荷兰的时尚市场:To Be Dressed
2019/05/06 全球购物
意大利比基尼品牌:MISS BIKINI
2019/11/02 全球购物
如何用Java实现列出某个目录下的所有子目录
2015/07/20 面试题
有趣的广告词
2014/03/18 职场文书
小学优秀班主任事迹材料
2014/05/17 职场文书
六查六看剖析材料
2014/10/06 职场文书
2014年采购员工作总结
2014/11/18 职场文书
街道社区活动报告
2015/02/05 职场文书
小学工作总结2015
2015/05/04 职场文书
房地产项目合作意向书
2015/05/08 职场文书
作文之亲情600字
2019/09/23 职场文书
微软Win11 全新照片应用面向 Dev预览版推出 新版本上手体验图集
2022/09/23 数码科技