IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> Python知识库 -> Python爬虫编程思想(11):用urllib请求基础验证页面 -> 正文阅读

[Python知识库]Python爬虫编程思想(11):用urllib请求基础验证页面

????????有一些页面并不是我们想访问就能访问的,这些页面都会将各种验证,例如,在第一次访问网页之前,会先弹出如图1所示的登录对话框,只有正确输入用户名和密码才能访问页面,否则会直接跳到错误页面。

????????这种验证被称为基础验证,是HTTP验证的一种。输入的用户名和密码会通过Authorization请求头字段发送给服务端,在访问给页面时,如果服务端检测到HTTP请求头中没有Authorization字段时,会设置名为WWW-Authenticate的HTTP响应头字段,同时返回401响应码。WWW-Authenticate字段值的格式如下:

'Basic realm=需要验证的范围'

????????其中Basic表示基础验证,也就是需要输入用户名和密码。realm部分表示需要验证的范围,是一个字符串,详细的用法在本节后面的部分介绍。

????????当浏览器遇到401状态码,并检测到是基础验证时就会弹出如图3-8所示的验证对话框,正确输入用户名和密码后,浏览器会向服务端发送Authorization请求头字段,该字段的值是Basic encode,其中encode是用户名和密码的Base64编码。由于基础验证的用户名和密码都是以明文发送(尽管被进行了Base64编码,但Base64编码是可逆的)的,所以建议该页面使用HTTPS,这样传输的数据就会使用SSL加密,以保证数据传输过程的安全。

????????下面的例子使用Flask编写了一个Web服务器,用于模拟基础验证页面。并使用普通设置HTTP请求头的方式和Handler方式请求这个基础验证页面。

????????Flask是基于Python的Web框架,可以用于编写Web应用程序,在使用之前需要使用如下的命令安装。

pip install flask????????

本例编写的第一个程序是这个支持基础验证的Web服务器,代码如下:

from flask import Flask
from flask import request
import base64
app = Flask(__name__)
# 判断客户端是否提交了用户名和密码,如果未提交,设置状态码为401,并设置WWW-Authenticate响应头
# auth:Authorization请求头字段的值, response:响应对象
def hasAuth(auth,response):
    if auth == None or auth.strip() == "":
        # 设置响应状态码为401 
        response.status_code = 401
        # 设置响应头的WWW-Authenticate字段,其中localhost是需要验证的范围
        response.headers["WWW-Authenticate"] = 'Basic realm="localhost"'
        # 返回False,表示客户端未提交用户名和密码 
        return False
    return True
# 根路由
@app.route("/")
def index():
    # 创建响应对象,并指定未输入用户名和密码(单击”取消“按钮)或输入错误后的返回内容 
    response = app.make_response('username or password error')
    # 输出所有的HTTP请求头
    print(request.headers)
    # 得到Authorization请求头的值
    auth = request.headers.get('Authorization')
    # 输出Authorization请求头的值
    print('Authorization:',auth)
    # 如果客户端提交了用户名和密码,进行验证
    if hasAuth(auth, response):
        # 将用户名和密码按Base64编码格式解码,这里按空格拆分成两个值,第一个是Basic,第二个是
        # Base64编码后的用户名和密码
        auth = str(base64.b64decode(auth.split(' ')[1]),'utf-8')
        # 用户名和密码之间用冒号(:)分隔,所以需要将它们拆开
        values = auth.split(':')
        # 获取用户名
        username = values[0]
        # 获取密码
        password = values[1]
        print('username:',username)
        print('password:',password)
        # 判断用户名和密码是否正确,如果正确,返回success
        if username == 'bill' and password == '1234':
            return "success"
    return response

if __name__ == '__main__':
    app.run()

????????本例为了方便,将用户名和密码分别固定为bill和1234,现在运行AuthServer.py,然后在浏览器中输入http://127.0.0.1:5000,就会弹出如图3-8所示的验证对话框,正确输入用户名和密码后,浏览器会输出success。当再次访问http://127.0.0.1:5000时,浏览器会使用刚才输入的用户名和密码通过Authorization请求头字段发送给服务端,所以不管用户名和密码输入的是否正确,只要单击了“登录”按钮,下次再访问给页面时都不会再弹出如图3-8所示的登录验证对话框。由于用户名和密码都是通过临时Cookie保存的,所以一旦浏览器关闭,再次打开后,访问http://127.0.0.1:5000仍然会弹出如图3-8所示的登录验证对话框。

????????由于用户名和密码是通过HTTP请求头的Authorization字段发送给服务端的,所以在访问该页面时可以直接设置Authorization字段。

from urllib import request
import base64
url = 'http://localhost:5000'
headers = {
    'User-Agent':'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.109 Safari/537.36',
    'Host':'localhost:5000',
    # 设置Authorization请求字段头,并指定Base64编码的用户名和密码
    'Authorization': 'Basic ' +
                       str(base64.b64encode(bytes('bill:1234','utf-8')),'utf-8')

}
req = request.Request(url = url,headers=headers,method="GET")
response=request.urlopen(req)
print(response.read().decode('utf-8'))

????????执行这段代码后,会在Console中输出success。AuthServer在Console中也会输出如图2所示的信息。

????????urllib中提供了一些Handler类,这些类可以用来处理各种类型的页面请求,这些类通常都是BaseHandler的子类,例如,HTTPBasicAuthHandler用于处理管理认证,HTTPCookieProcessor用于处理Cookie。本例会使用HTTPBasicAuthHandler处理页面的基础验证。

????????使用HTTPBasicAuthHandler的关键是build_opener函数,该函数与urlopen类似,只是可以完成更复杂的工作。实际上,urlopen函数相当于类库为你封装好了及其常用的请求方法,利用它们可以完成基本的请求,但如果要完成更复杂的请求,就需要使用build_opener函数。除此之外,还需要使用HTTPPasswordMgrWithDefaultRealm对象封装请求字段数据,也就是用户名、密码和realm。

from urllib.request import
     HTTPPasswordMgrWithDefaultRealm,HTTPBasicAuthHandler,build_opener
from urllib.error import URLError
username = 'bill'
password = '1234'
url = 'http://localhost:5000'

p = HTTPPasswordMgrWithDefaultRealm()
# 封装realm,url、用户名和密码
p.add_password('localhost',url,username,password)
auth_handler = HTTPBasicAuthHandler(p)
# 发送HTTP请求
opener = build_opener(auth_handler)

result = opener.open(url)
# 获取服务端响应数据
html = result.read().decode('utf-8')
print(html)

运行程序,在Console中会输出success。在AuthServer的Console中会输出如图3所示的信息。

????????从图3的输出内容可以看出,客户端发送了两次HTTP请求,第1次没有Authorization字段,这是服务端会返回401错误,如果客户端是浏览器,那么就会弹出如图1所示的验证对话框,但现在客户端是爬虫,所以干脆直接提供现成的用户名和密码,这就是第2次HTTP请求的目的。

add_password函数的第1个参数是realm,如果指定这个参数,那么必须与服务端设置WWW-Authenticate字段时指定的realm相同,本例是localhost。如果add_password函数的第1个参数是None,那么服务端会忽略realm。如果指定的realm不一致,就会抛出如图4所示的异常。

????????所以为了安全起见,在发送HTTP请求时可以用try...except语句,以避免程序崩溃。?

try:
    result = opener.open(url)
?   html = result.read().decode('utf-8')
????print(html)
except URLError as e:
    print(e.reason)

  Python知识库 最新文章
Python中String模块
【Python】 14-CVS文件操作
python的panda库读写文件
使用Nordic的nrf52840实现蓝牙DFU过程
【Python学习记录】numpy数组用法整理
Python学习笔记
python字符串和列表
python如何从txt文件中解析出有效的数据
Python编程从入门到实践自学/3.1-3.2
python变量
上一篇文章      下一篇文章      查看所有文章
加:2021-07-22 14:07:30  更:2021-07-22 14:08:33 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/15 1:40:21-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码