Python爬虫(二)urllib库的使用

了解了爬虫的基本原理后,接下来我们就可以爬取网页内容。网页其实是由HTML代码和JS、CSS等组成的。urllib是python提供的HTTP请求库,它有许多模块供我们爬取使用。

urllib.request

首先使用urlopen打开一个url,可以获取页面的源代码。

import urllib.request

response=urllib.request.urlopen("https://www.baidu.com/")
print(response.read())  

结果如下所示:

urlopen函数的为

urllib.request.urlopen(url, data=None, [timeout, ]*, cafile=None, capath=None)  

其中url为访问的网址;data为访问时需要传输的数据;timeout为超时时间,当超过此时间服务器未响应时即为访问失败;cafile和capath为HTTP请求指定一组受信的CA证书,在此先不管它。除了第一个参数之外,后四个参数都可以不设置。

除此之外,urlopen函数可以直接接受一个Request对象:

class urllib.request.Request(url, data=None, headers={}, origin_req_host=None, unverifiable=False)   

同样地,只有第一个参数不可省略。因此上述代码可以换成:

import urllib.request

request=urllib.request.Request("https://www.baidu.com/")
response=urllib.request.urlopen(request)
print(response.read())  

然而有的网页是动态网页,需要根据传的数据做出相应的响应。HTTP请求传送数据时有POST和GET两种方式。GET方式是直接以链接形式访问,链接中包含了所有的参数,可以直观地查看自己提交的内容,但是当数据中包含密码时就涉及到了安全问题。POST相反,它不会在网址上显示所有的参数。

下面展示这两种数据传送的用法。

POST:

import urllib.request
import urllib.parse
params = urllib.parse.urlencode({'spam': 1, 'eggs': 2, 'bacon': 0})
f = urllib.request.urlopen("http://www.musi-cal.com/cgi-bin/query?%s" % params)
print(f.read().decode('utf-8'))

GET:

import urllib.request
import urllib.parse

params = urllib.parse.urlencode({'spam': 1, 'eggs': 2, 'bacon': 0})
params = params.encode('utf-8')
f = urllib.request.urlopen("http://www.musi-cal.com/cgi-bin/query", params)
print(f.read().decode('utf-8'))   

request headers

在前面讲到构建Request对象时可以设置headers。那么headers是干什么用的呢。

下面是我使用Chrome浏览器访问百度的一个request headers。

可以看到它包含但不仅限于这些内容:

-  Accept:浏览器端可以接受的媒体类型。
-  Accept-Encoding:浏览器申明自己接收的编码方法,通常指定压缩方法,是否支持压缩,支持什么压缩方法(gzip,deflate)  
-  Accept-Language:浏览器申明自己接收的语言。  
-  Host:请求报头域主要用于指定被请求资源的Internet主机和端口号,它通常从HTTP URL中提取出来的。  
-  Referer:告诉服务器我是从哪个页面链接过来的。  
-  User-Agent:告诉HTTP服务器, 客户端使用的操作系统和浏览器的名称和版本。

在使用python进行爬虫的时候,可以会遇到一些网站的反爬虫措施。一般服务器会根据User-Agent的值来判断请求是否从浏览器发出。如果没有对headers进行设置,User-Agent会声明自己为python脚本,对于有反爬虫措施的服务器,它就会拒绝爬虫程序访问。而通过设置headers就可以伪装成浏览器进行访问。

下面为设置headers的例子。

import urllib.request

def parse(url):
    headers = {'Accept': '*/*',
               'Accept-Language': 'en-US,en;q=0.8',
               'Cache-Control': 'max-age=0',
               'User-Agent': 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/48.0.2564.116 Safari/537.36',
               'Connection': 'keep-alive',
               'Referer': 'http://www.baidu.com/'
               }
    req = urllib.request.Request(url, None, headers)
    response = urllib.request.urlopen(req)
    page_source = (response.read())
    return page_source

设置代理

一些网站的反爬虫措施会检测一段时间内某个ip的访问次数,如果访问频率过高,它会禁止此ip的访问。所以我们可以设置一个代理服务器,隔一定的时间更换一个代理。

Python3中提供了ProxyHandler设置代理服务器,废话不多说,我们还是通过一个例子来看看如何使用代理。

import urllib.request

proxy_handler = urllib.request.ProxyHandler({"http" : "117.87.176.131"})
null_handler = urllib.request.ProxyHandler({})

tag = True 
if tag:  
    opener = urllib.request.build_opener(proxy_handler)
else:
    opener = urllib.request.build_opener(null_handler)

request = urllib.request.Request("http://www.baidu.com/")

response = opener.open(request)

# urllib.request.install_opener(opener)
# response = urllib.request.urlopen(request)

print(response.read())     

程序先构建了两个代理handler,一个有代理IP,一个没有代理IP。通过urllib2.build_opener()方法创建OpenerDirector实例,该对象按给定参数顺序处理这些Handler对象。然后使用OpenerDirector.open()方法发送请求才可以使用自定义的代理。这里要注意的一点是直接使用urlopen是不使用自定义代理的,必须先使用install_opener()方法将OpenerDirector对象作为默认的全局opener,之后不管是使用opener.open()还是urlopen() 发送请求,都将使用自定义代理。

urllib.error

urllib.error定义了由urllib.request引起的异常的异常类。基本异常类是URLError,它是继承自IOError。

  1. exception urllib.error.URLError

这个产生的原因可能是网络无连接、连接不到服务器或者是服务器不存在,我们可以使用try-except捕获异常并且分析异常原因。

from urllib import request
from urllib import error

req=request.Request("https://www.xxx.com/")
try:
    response=request.urlopen(req)
except error.URLError as e:
    print(e.reason)   

我们访问了一个不存在的网址,输出结果为:

  1. exception urllib.error.HTTPError

URLError的一个子类,当使用urlopen()发送请求时,服务器会有一个应答对象response,同时包含着一个状态码。当不能对请求进行处理时,它会产生一个HTTPError,对应一个状态码表示响应的状态。

from urllib import request
from urllib import error

req=request.Request("http://blog.csdn.net/dxk.html")
try:
    response=request.urlopen(req)
except error.HTTPError as e:
    print(e.code)   

结果如下:

这表示请求的资源没有在服务器上找到。

由于HTTPError是URLError的子类,所以当我们需要同时捕捉这两个异常时,我们要特别注意将父类异常URLError写在子类异常HTTPError的后面。如果URLError放在前面,出现HTTP异常会先响应URLError,这样HTTPError就捕获不到错误信息了。

我们看下面这个例子:

from urllib import request
from urllib import error

req=request.Request("http://blog.csdn.net/dxk.html")
try:
    response=request.urlopen(req)
except error.HTTPError as e:
    print(e.code)
    print("HTTPError")
except error.URLError as e:
    print(e.reason)
    print("URLError")

如果捕捉到了HTTPError,则输出code,不再处理URLError。若没有发生HTTPError,则捕捉URLError异常,并输出原因。

结果如下:

猜你喜欢

转载自blog.csdn.net/dxk_093812/article/details/82556338