爬虫与Python:(三)基本库的使用——1.网络请求库之urllib()

本文主要讲解Python3中的urllib库的用法。urllib是Python标准库中用于网络请求的库。该库有4个模块,分别是:urllib.request、urllib.error、urllib.parse和urllib.robotparser。其中urllib.request和urllib.error两个库在爬虫程序中使用比较频繁。

本文目录如下:

  1. urlopen()
  2. 简单抓取网页
  3. 设置请求超时
  4. 使用data参数提交数据
  5. Request
  6. 简单的使用Request
  7. Request高级用法
  8. 使用代理
  9. 认证登录
  10. Cookie设置
  11. HTTPResponse
  12. 错误解析

1. urlopen()

模拟浏览器发起一个HTTP请求,需要用到urllib.request模块。urllib.request的作用不仅是发起请求,还能获取请求返回结果。下面先看一下urlopen()的API。

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

参数和说明如下:

参数 说明
url string类型的地址,也就是要访问的url,例如:http://www.baidu.com。
data bytes类型的内容,可通过bytes()函数转换为字节流,它也是可选参数。使用data参数,请求方式变成以post方式提交表单。使用标准格式是:application/x-www-form-urlencoded。
timeout 参数用于设置请求超时时间,单位是秒。
cafile/capath 参数代表CA证书和CA证书路径,如果适用HTTPS则需要用到。
context 参数必须是ssl.SSLContext类型,用来指定SSL设置。
cadefault 参数已弃用,可以略去。
  • urlopen()可以单独传入urllib.request.Request对象。
  • urlopen()返回的结果是一个http.client.HTTPResponse对象。
  • 实际使用过程中, 用得最多的参数是url和data。

2. 简单抓取网页

下面来看一个简单的示例,使用urlib.request.urlopen()去请求百度贴吧,并获取它的页面源代码。运行代码如下:

1 import urllib.request
2 
3 url = 'https://tieba.baidu.com/'
4 response = urllib.request.urlopen(url)
5 html = response.read()     # 获取页码的源码
6 print(html.decode('gbk')) # 转化为GBK编码

运行结果如下:

  通过以上示例可以知道,使用 urlib.request.urlopen() 方法,传入网址,就可以成功获取到网页的页面源码。

3. 设置请求超时

有时,在访问网页是常常会遇到这样的情况——由于计算机网络或者对方服务器崩溃等原因,导致请求迟迟无法得到响应。同样地,程序去请求的时候,也会遇到这样的问题,因此,可以手动设置超时。当请求超时的时候,可以采取进一步的措施,或再次请求。因此,urlopen()中可以通过timeout设置超时响应时间。

以下代码在url参数后添加了一个timeout设置,如果超过1s就舍弃它或重新获取网页。

1 import urllib.request
2 
3 url = 'https://tieba.baidu.com/'
4 response = urllib.request.urlopen(url , timeout=1)
5 html = response.read()     # 获取页码的源码
6 print(html.decode('gbk')) # 转化为GBK编码

4. 使用data参数提交数据

有的页面可以通过data传递一些其他的内容。data参数是可选的,如果添加data,需要它是字节流编码格式的内容,即bytes类型,通过bytes()函数可以进行转换,另外,如果传递了data参数,那么它的请求方式就不再是GET方式,而是通过POST方式。那么,他们是如何传递参数的呢?

data需要被转换为字节流。而data是一个字典,需要使用 urllib.request.urlencode() 将字典转化为字符串,再使用bytes()函数转换为字节流。最后使用urlopen()发起请求,请求时模拟用POST方式提交数据。

1 import urllib.parse
2 import urllib.request
3 
4 url = 'http://httpbin.org/post'
5 data =bytes(urllib.parse.urlencode({'word':'hello'}).encode('utf-8'))
6 response = urllib.request.urlopen(url , data = data)
7 print(response.read())

运行后控制台会输出:

5. Request

通过urlopen()方法可以发起简单的请求,但它的几个简单的参数并不足以构建一个完整的请求。如果请求中需要加入headers(请求头)、指定请求方式等信息,那么久可以利用更强大的Request类来构建一个请求。下面来看一下Request请求的构造方法。

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

Request请求的参数和描述如下:

参数 数据类型 必填 描述
url string 请求链接
data bytes 与urlopen()的data的参数相同,请求表单的数据
hearders   指定发起的HTTP请求的头部信息。headers是一个字典,它除了在Request中添加外,还可以通过调用Request实例的add_header()方法来添加请求头
origin_req_host string 请求方法host的名称或IP地址
unverifiable
boolean 这个请求是否无法验证的,默认值False。意思是说用户没有足够的权限来选择接收这个请求的结果。例如,我们请求一个HTML文档中的图片,但是我们没有自动抓取图像的权限,我们就要将unverifiable的值设置成True。
method string 发起请求的方式,有GET、POST、DELETE和PUT等。

6. 简单使用Request

了解Request参数后,下面就来简单地使用他来请求百度贴吧这个网址。

需要注意的是,使用Request伪装成浏览器发起HTTP请求,如果不设置headers中的User-Agent,默认的User-Agent是Python-urlib/3.5。因为可能一些网站会将该请求拦截,所以需要伪装成浏览器发起的请求。例如,使用User-Agent为Chrome浏览器。

运行代码如下:

1 import urllib.request
2 
3 url = 'https://tieba.baidu.com/'
4 hearders = {
5     "User-Agent":'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/94.0.4606.71 Safari/537.36'
6 }
7 request = urllib.request.Request(url=url , headers= hearders)
8 response = urllib.request.urlopen(request)
9 print(response.read().decode('gbk'))

运行结果如下:

 这里涉及到 User-Agent 头部信息的获取,可以使用谷歌浏览器随便打开一个网站,然后按【F12】进行调试界面,切换到【Network】选项卡刷新页面,随意选择一个请求,如图所示,即可找到需要的“User-Agent”,将其复制过来就可以了。

7. Request高级用法

如果需要在请求中添加代理、处理请求的Cookie,那么就需要用到Handler 和OpenerDirector两个知识点。

7.1 Handler

Handler即处理者、处理器,能处理请求(HTTP、HTTPS、FTP等)中的各种事情。Handler的具体实现是 urlib.request.BaseHandler 类。 urlib.request.BaseHandler 类是所有其他Handler的基类,其提供了最基本的Handler的方法,如default_open()、protocol_request()等。继承BaseHandler类的Handler子类很多,这里列举了几个比较常见的类。

  1. ProxyHandler:为请求设置代理。
  2. HTTPCookieProcessor: 处理HTTP请求的Cookie。
  3. HTTPDefaultErrorHandler: 处理HTTP响应错误。
  4. HTTPRedirectHandler : 处理HTTP响应重定向。
  5. HTTPPasswordMgr:用于密码管理,它维护了用户名密码的表。
  6. HTTPBasicAuthHandler : 用于登录认证,一般和HTTPPasswordMgr结合使用。

7.2 OpenerDirector

OpenerDirector ,也可以成为Opener。之前用过的urlopen()方法,实际上就是urlib提供一个Opener。那么Opener和Handler又有什么关系呢?Opener对象有 build_opener(handler) 方法创建出来的。创建自定义的Opener,就需要使用install_opener(opener)方法。值得注意的是,install_opener实例化会得到一个全局的OpenerDirector对象。

8. 使用代理

为什么需要使用代理?有些网站做了浏览器频率限制,如果请求频率过高,该网站就会封IP,禁止我们访问,所以就需要使用代理来突破这个“枷锁”。

 

 1 # 使用代理
 2 import urllib.request
 3 
 4 url = 'https://tieba.baidu.com/'
 5 hearders = {
 6     "User-Agent":'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/94.0.4606.71 Safari/537.36'
 7 }
 8 proxy_header = urllib.request.ProxyHandler({
 9    'http':'212.200.246.24:80',
10    'https':'116.63.93.172:8081'
11 });
12 opener = urllib.request.build_opener(proxy_header)
13 urllib.request.install_opener(opener)
14 
15 request = urllib.request.Request(url=url , headers= hearders)
16 response = urllib.request.urlopen(request)
17 print(response.read().decode('gbk'))

通过以上代码可知,可以调用 ProxyHandler 方法设置代理,模拟成多个不同的客户端,成功“欺骗”网站,获取不同数据。

在实际项目中,如果需要大量使用代理IP,可到专门做代理的IP供应商处购买,虽然晚上有大量免费的,但是大都不稳定。

9. 认证登录

有些网站需要携带账号和密码进行登录之后才能继续浏览网页。遇到这样的网站,就需要用到认证登录。认证登录步骤思路如下:

  1. 使用HTTPPasswordMgrWithDefaultRealm()实例化一个账号密码管理对象;
  2. 使用add_password()函数添加账号和密码;
  3. 使用HTTPBasicAuthHandler()得到Handler;
  4. 使用build_opener()获取Opener对象;
  5. 使用Opener的open函数发起请求。

下面以携带账号和密码登录的百度贴吧为例,代码如下:

 1 # 认证登录
 2 import urllib.request
 3 
 4 url = 'https://tieba.baidu.com/'
 5 user = 'test_user'          # 运行时用了真实账号,这里指代一下
 6 password = 'test_password'  # 运行时用了真实账号,这里指代一下
 7 pwdmgr = urllib.request.HTTPPasswordMgrWithDefaultRealm()   # 实例化账号密码管理对象
 8 pwdmgr.add_password(None ,url, user , password) # 添加账号密码
 9 auth_handler = urllib.request.HTTPBasicAuthHandler(pwdmgr) # 获取handler
10 opener = urllib.request.build_opener((auth_handler))    # 得到Opener对象
11 
12 response = opener.open(url)
13 print(response.read().decode('gbk'))

 

 控制台的运行结果与上文一致,这里省略了它。

10. Cookie设置

如果请求页面每次都需要身份验证,那么就可以使用Cookie来自动登录,免去重复验证的操作。获取Cookie需要 http.cookiejar.CookieJar() 实例化一个Cookie对象,再用 urlib.request.HTTPCookieProcessor 构建出Handler对象,最后使用Opener的open()函数即可。下面以获取请求百度贴吧的Cookie为例,代码如下:

 1 # Cookie设置
 2 import http.cookiejar
 3 import urllib.request
 4 
 5 url = 'https://tieba.baidu.com/'
 6 fileName = 'cookie.txt'
 7 
 8 cookie = http.cookiejar.CookieJar()
 9 handler = urllib.request.HTTPCookieProcessor(cookie)
10 opener = urllib.request.build_opener(handler)
11 response = opener.open(url)
12 
13 f =  open(fileName ,'a')
14 for item in cookie:
15     f.write(item.name +"=" + item.value + '\n')
16 f.close()

运行完成后,文件的同级目录即可生成“cookie.txt”文件,记录保存的cookie。

11. HTTPResponse

从前面的例子可知,使用urlib.request.urlopen()或opener.open(url)返回结果是一个HTTPResponse对象。http.client.HTTPResponse对象包含msg、version、status、reasson、debuglevel、closed等属性及read()、readinto()、getheader(name)、getheaders()、fileno()等函数。

12. 错误解析

发起请求难免会出现各种异常,因此需要对异常进行处理,异常处理主要由两个类:urlib.error.URLErrorurlib.error.HTTPError。

12.1 URLError

URLError是urlib.error异常类的基类,可以用于捕获有urlib.request产生的异常。它具有一个属性reason,即返回错误的原因。捕获URL异常的代码示例如下:

1 import urllib.request
2 import urllib.error
3 
4 url = 'http://www.google.com'   # 正常国内网络下,谷歌无法连接
5 
6 try:
7     response = urllib.request.urlopen(url)
8 except urllib.error.URLError as e:
9     print(e.reason)

这里执行了捕获异常的代码,控制台运行结果如下:

12.2 HTTPError

 HTTPError是UEKRoor的子类,专门处理HTTP和HTTPS请求的结果。它具有以下3个属性:

  • code: HTTP请求返回的状态码:
  • renson:与基类用法一样,表示返回错误的原因:
  • headers:HTTP请求返回的响应信息。

获取HTTP异常的示例代码(输出类错误状态码、错误原因、服务器响应头)如下:

 1 # HTTPError
 2 import urllib.request
 3 import urllib.error
 4 
 5 url = 'http://www.google.com'   # 正常国内网络下,谷歌无法连接
 6 
 7 try :
 8     response = urllib.request.urlopen(url)
 9 except urllib.error.HTTPError as e:
10     print('code:' + e.code + '\n')
11     print('reason' + e.reason + '\n')
12     print('headers' + e.headers + '\n')

 

posted @ 2021-10-12 21:21  陆陆无为而治者  阅读(212)  评论(0编辑  收藏  举报