1. 网页抓取:就是将URL地址中指定的网络资源从网络流中读取出来,保存到本地,类似于使用程序模拟IE浏览器的功能,把URL作为HTTP请求的内容发送到服务器端,然后读取服务器端的响应资源;
2. 在python中,使用urllib2组件实现来抓取网页,其以urlopen函数的形式提供了一个非常简单的接口,简单的urllib2的代码如下:
import urllib2
response = urllib2.urlopen('http://www.baidu.com/')
html = response.read()
print html
以上四行代码实现的是将百度浏览器收到的代码全都打印出来了
注意:在传送HTTP请求时允许做的两件事请如下:
(1) 发送data表单数据
有时希望发送一些数据到URL,在HTTP中通常使用熟知的POST请求来发送,但一般的HTTP表单,data需要编码成标准形式,然后作为data参数传送到Request对象,编码工作采用urllib的函数而非urllib2,可采用以下编码方式:
方式一、data 数据的POST传送方式
import urllib
import urllib2
url = 'http://www.baidu.com/'
values ={'name':'WHY',
'location':'SDU',
'language':'Python'}
data =urllib.urlencode(values) """编码工作"""
req = urllib2.Request(url,data)"""发送请求的同时传data"""
response =urllib2.urlopen(req) """接受反馈的信息"""
the_page =response.read() """读取反馈的内容"""
注意:如果没有传送data参数,urllib2使用GET方式的请求,但在方式一中采用的是POST发送请求。GET和POST请求的不同之处在于POST请求通常有“副作用”,它们会由于某种途径改变系统状态(例如提交成堆垃圾到你门口)。Data同样可以通过在Get请求的URL本身上面编码来传送,见方式二
方式二、data 数据的Get传送
import urllib
import urllib2
data = {}
data['name']= 'WHY'
data['location']= 'SDU',
data['language']== 'Python'
url_values =urllib.urlencode(data)
print url_values
name =Somebidy+Here&language=Python&location=Northampton
url ='http://www.baidu.com/'
full_url = url +'?' + url_values
data =urllib2.open(full_url)
(2) 设置Headers到HTTP请求---通过设置Headers可以实现python的程序像浏览器发送相同的报文格式
默认的urllib2把自己作为“Python-urllib/x.y”(x和y是python主版本和次版本号,例如:Python-urllib/2.7)这个身份可能会让站点迷惑,或者干脆不工作,浏览器确认自己身份是通过User-Agent头,当创建了一个请求对象,可以给它一个包含头数据的字典,代码如下:
import urllib
import urllib2
url ='http://www.baidu.com'
user_agent ='Mozilla/4.0(compatible;MSIE 5.5;Windows NT)'
values ={'name':'WHY',
'location':'SDU',
'language':'Python'}
headers ={'User-Agent':user_agent} “””设置header中的User-Agent的字段”””
data =urllib.urlencode(values)
req =urllib2.Request(url,data,headers)
response =urllib2.urlopen(req)
the_page =response.read()
3. 异常的处理和HTTP状态码的分类
当urlopen不能处理一个response时,产生urlError。不过通常的Python APIs异常诸如:ValueError,TypeError等也会同时产生。HTTPError是urlError的子类,通常在HTTP URLs中产生
(1) URLError
通常,该异常实在没有网络连接(没有路由到特定服务器),或者服务器不存在的情况下产生,这种情况下,异常同样会带有“reason”属性,它是一个tuple(可以理解为不可变的数组),包含了一个错误号和一个错误信息,代码如下:
import urllib2
req =urllib2.Request('http://www.baibai.com')
try:
urllib2.urlopen(req)
except urllib2.URLError,e:
print e.reason
输出结果:
[Errno 11002] getaddrinfo failed
(2) HTTPError
服务器上每一个HTTP应答对象reponse包含一个数字“状态吗”,有时状态码之处服务器无法完成请求,默认的处理器会为你处理一部分这种应答。例如:加入response是一个“重定向”,需要客户端从别的地址获取文档,urllib2将为你处理。其他不能处理的,urlopen会产生一个HTTPError。典型的错误包含“404(页面无法找到),403(请求禁止),和401(待验证请求)”。HTTP状态码表示HTTP协议所返回的响应的状态。比如客户端向服务器发送请求,如果成功地获得请求的资源,则返回状态码:200,表示相应成功,如果请求的资源不存在,则通常返回404错误。HTTP的状态码通常分为5中类型,分别以1-5五个数字开头,由三位整数组成,HTTP的各状态码如下所示:
200:请求成功处理方式:获得响应的内容,进行处理
201:请求成功,结果是创建了资源。新创建资源的URL可在响应的实体中得到处理方式:爬虫中不会遇到
202:请求被接受,但处理尚未完成处理方式:阻塞等待
204:服务器端已经实现了请求,但是没有返回心得信息。如果客户是用户代理,则无须为此更新自身的文档视图。处理方式:丢弃
302:请求到的资源在一个不同的URL处临时保存处理方式:重定向到临时的URL
400:非法请求处理方式:丢弃
404:没有找到处理方式:丢弃
5XX:回应代码以“5”开头的状态码表示服务器端发现自己出现错误,不能继续执行请求处理方式:丢弃
等等
注意:
第一、 默认的处理器重定向(300以外号码),并且100-299范围的号码指示成功,所以用户只能看到400-599的错误号码;
第二、 BaseHTTPServer.BaseHTTPRequestHandler.response是一个很有用的应答号码字典,显示了HTTP协议使用的所有应答号;
第三、 当一个错误号产生后,服务器返回一个HTTP错误号,和一个错误页面,可以使用HTTPError实例作为页面返回的应答对象response。这表示和错误属性一样,同样包含了read,geturl和info方法,代码如下:
importurllib2
req =urllib2.Request('')
try:
urllib2.urlopen(req)
excepturllib2.URLError,e:
print e.code
输出:403
(3) Wrapping:捕获HTTPError或URLError异常的方法
推荐使用第二种方法
方法一、
from urllib2 importRequest,urlopen,URLError,HTTPError
req =Request('')
try:
response = urlopen(seq)
except HTTPError,e: """注意此处exceptHTTPError必须在第一个,否则URLError将同样接收到HTTPError,因为HTTPERoor是URLError的子类,故如果URLError在前面能接受到所有的URLError,包括HTTPError"""
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:
print 'No exception was raised.'
方法二、
from urllib2 importRequest,urlopen,URLError,HTTPError
req =Request('')
try:
response = urlopen(seq)
except URLError,e:
if hasatrr(e,'reason'):
print 'We failed to reach a server.'
print 'Reason: ',e.reason
elif hasatrr(e,'code'):
print 'The server couldn\'t fulfill the request.'
print 'Error code:',e.code
else:
print 'Noexception was raised.'
注意:
判断object中是否有name属性,返回一个布尔值
4. Opener与Handler的介绍和实例应用
(1) urlopen返回的应答对象response(或者HTTPError实例)有两个很有用的方法info()和geturl()
①geturl()
返回获取真正的URL,鉴于urlopen(或者opener对象使用的)或许会有重定向。获取的URL或许跟请求的URL不同。
代码:
from urllib2 importRequest,urlopen,URLError,HTTPError
old_url = 'http://rrurl.cn/b1UZup11111'
req = Request(old_url)
response = urlopen(req)
print 'Old url: ' + old_url
print 'Real url: '+ response.geturl()
运行结果:
Old url: http://rrurl.cn/b1UZup
Real url: http://rrurl.cn/b1UZup
此处并未产生重定向
②info()
返回对象的字典对象,该字典描述了获取的页面情况。通常是服务器发送的特定头headers。目前是httplib.HTTPMessage实例。经典的headers包含“Content-length”,“Content-type”,和其他内容
代码:
from urllib2 importRequest,urlopen,URLError,HTTPError
old_url = 'http://www.baidu.com'
req = Request(old_url)
response = urlopen(req)
print 'Info():'
print response.info()
运行结果:
(2) Openers
当获取一个URL使用一个opener(一个urllib2.OpenerDirector的实例),正常情况下,使用默认opener:通过urlopen,当可创建个性的openers
(3) Handles
Openers使用处理器handlers处理所有”繁重“的工作,每个handlers知道如何通过特定协议打开URLs,或者处理URL打开时的各个方面,例如:HTTP重定向,HTTP cookies
(4) 创建opener的方法
方法一、创建一个opener,可以实例化一个OpenerDirector,然后用.add_handle(some_handler_instance)
方法二、使用函数build_opener来创建opener对象,build_opener默认添加几个处理器,但提供快捷的方法来添加或更新默认处理器
注意:
第一、 install_opener用来创建(全局)默认opener,这表示调用urlopen将使用你安装的opener
第二、 opener对象的方法—open
该方法可以像urlopen函数那样直接用来获取urls,通常不必调用install_opener,除了为了方便
(5) 基本认证的内容(即opener和handler的应用)
Basic Authentication基本验证
第一、 创建和安装一个handler,以下将使用:HTTPBasicAuthHandler
第二、 当需要基础验证时,服务器发送一个header(401错误码)请求验证,这个指定scheme和一个“realm“,看起来如同:Www-authenticate:SCHEME realm=”REALM”,例如:Www-authenticate:Basicrealm=”cPanel Users”
第三、 客户端必须使用新的请求,并在请求里包含正确的姓名和密码
(6) HTTPBasicAuthHandler使用一个密码管理的对象来处理URLs和realms来映射用户名和密码,如果知道realm(从服务器而来的头里)是什么,就能使用HTTPPasswordMgr。通常不关心realm是什么,就能用方便的HTTPPasswordMgrWithDefaultRealm。这个将为我们指定一个你默认的用户名和密码。
(7) 实例代码
# -*- coding: utf-8 -*-
import urllib2
"""创建一个密码管理者"""
password_mgr = urllib2.HTTPPasswordMgrWithDefaultRealm()
"""添加用户名和密码"""
top_level_url ="http://example.com/foo/" """可以是完整URL(包含"http",以及主机名和端口号,如:http://example.com/),也可以是一个"authority"(即主机名和可选的包含端口号,例如:"example.com"或者"example.com:8080")"""
"""如果知道realm,可以使用其代替None"""
"""password_mgr.add_password(None,top_level_url,username,password)"""
password_mgr.add_password(None,top_level_url,'why','123')
""""创建一个新的handler"""
handler =urllib2.HTTPBasicAuthHandler(password_mgr)
"""创建opener(OpenerDirector实例)"""
opener = urllib2.build_opener(handler)
a_url = 'http://www.baidu.com/'
"""使用opener获取一个url"""
opener.open(a_url)
"""安装opener"""
"""现在所调用urllib2.urlopen将用我们的opener""""
urllib2.install_opener(opener)