1 布景

上篇文章讲解了requests模块的基础运用,其中有get、put、post等多种恳求办法,运用data、json等格局做为恳求参数,在恳求体中增加恳求头部信息的常见信息,如:headers、cookies,以及对恳求呼应的处理办法。接下来讲解一下requests的高档用法。

2 进阶办法举例

2.1 requests.request()

method:提交办法(get|post);

url:提交地址;

kwargs:14个操控访问的参数;

HTTP请求:requests的进阶使用方法浅析 | 京东云技术团队

常用的参数有:params、data、json、headers、cookies,已在上篇文章中介绍过了,感兴趣的朋友,能够到上篇文章再回忆一下。以下将讲解与示例其他参数的运用。

示例:

2.1.1 files

恳求带着文件,假如有的恳求需求上传文件,能够用它来实现。

import requests
# 上传文件
f= {"files": open("favicon.ico", "rb") }
data = {"name": "上传文件"}
requests.request(
    method = 'POST', 
    url = 'http://127.0.0.1:8080/example/request',  
    data = data,
    files = f
)

需注意:favicon.ico文件需和当前脚本在同一目录下,假如不在,能够将文件名称修改为文件途径

import requests
from requests.auth import HTTPBasicAuth, HTTPDigestAuth
# 1、Basic Auth认证
res = requests.request(
    method = 'GET',
    url = 'http://127.0.0.1:8080/example/request',
    auth = HTTPBasicAuth("username", "password")
)
res.encoding = "gbk"
print(res.status)  # 200
# 2、DIGEST 认证
res = requests.request(
    method = 'GET',
    url = 'http://127.0.0.1:8080/example/request',
    auth = HTTPDigestAuth("username", "password")
)
res.encoding = "gbk"
print(res.status)  # 200

http auth认证的两种办法,分别为Basic办法和Digest认证,其中:Basic Auth的优点是供给简单的用户验证功能,其认证进程简单明了,适合于对安全性要求不高的系统或设备中;同样存在缺陷:输入的用户名,暗码 base64编码后会出现在Authorization里,很简单被解析出来。

那么Digest对比Basic认证有什么不同呢?

  • Digest思维,是运用一种随机数字符串,两边约定好对哪些信息进行哈希运算,即可完成两边身份的验证。Digest形式防止了暗码在网络上明文传输,提高了安全性,但它仍然存在缺陷,例如认证报文被攻击者阻拦到攻击者能够获取到资源。
  • DIGEST 认证供给了高于 BASIC 认证的安全等级,可是和 HTTPS 的客户端认证相比仍旧很弱。
  • DIGEST 认证供给防止暗码被偷听的保护机制,但并不存在防止用户伪装的保护机制。
  • DIGEST 认证和 BASIC 认证相同,运用上不那么便捷灵活,且仍达不到多数 Web 网站对高度安全等级的寻求标准。因而它的适用范围也有所受限。

2.1.2 timeout

恳求和呼应的超时时刻,在网络呼应延迟或许无呼应时,能够经过设置超时时刻,防止等候。

import requests
# 设置恳求超时1秒,1秒后无呼应,将抛出反常,1秒为connect和read时刻总和
requests.request(
    method = 'POST',
    url = 'http://127.0.0.1:8080/example/request',
    json = {'k1' : 'v1', 'k2' : 'v2'},
    timeout = 1
)
# 分别设置connect和read的超时时刻,传入一个数组
requests.request(
    method = 'POST',
    url = 'http://127.0.0.1:8080/example/request',
    json = {'k1' : 'v1', 'k2' : 'v2'},
    timeout = (5, 15)
)
# 永久等候
requests.request(
    method = 'POST',
    url = 'http://127.0.0.1:8080/example/request',
    json = {'k1' : 'v1', 'k2' : 'v2'},
    timeout = None
    # 或许删去timeout参数
)
# 捕捉超时反常
from requests.exceptions import ReadTimeout
try:
    res = requests.get('http://127.0.0.1:8080/example/request', timeout=0.1)
    print(res.status_code)
except ReadTimeout:
    print("捕捉到超时反常")

2.1.3 allow_redirects

设置重定向开关。

>>> import requests
>>> r = requests.get('http://github.com')
>>> r.url
'https://github.com/'
>>> r.status_code
200
>>> r.history
[<Response [301]>]
# 假如运用GET、OPTIONS、POST、PUT、PATCH或DELETE,则能够运用allow_redirects参数禁用重定向
>>> r = requests.get('http://github.com', allow_redirects=False)
>>> r.status_code
301
>>> r.history
[]
# 用HEAD发动重定向
>>> r = requests.head('http://github.com', allow_redirects=True)
>>> r.url
'https://github.com/'
>>> r.history
[<Response [301]>]
import requests
import re
# 第一次恳求
r1=requests.get('https://github.com/login')
r1_cookie=r1.cookies.get_dict() #拿到初始cookie(未被授权)
authenticity_token=re.findall(r'name="authenticity_token".*?value="(.*?)"',r1.text)[0] #从页面中拿到CSRF TOKEN
# 第二次恳求:带着初始cookie和TOKEN发送POST恳求给登录页面,带上账号暗码
data={
    'commit':'Sign in',
    'utf8':'✓',
    'authenticity_token':authenticity_token,
    'login':'xxxxxx@qq.com',
    'password':'password'
}
# 测验一:没有指定allow_redirects=False,则呼应头中出现Location就跳转到新页面,
# r2代表新页面的response
r2=requests.post('https://github.com/session',
             data=data,
             cookies=r1_cookie
             )
print(r2.status_code) # 200
print(r2.url) # 看到的是跳转后的页面
print(r2.history) # 看到的是跳转前的response
print(r2.history[0].text) # 看到的是跳转前的response.text
# 测验二:指定allow_redirects=False,则呼应头中即使出现Location也不会跳转到新页面,
# r2代表的仍然是老页面的response
r2=requests.post('https://github.com/session',
             data=data,
             cookies=r1_cookie,
             allow_redirects=False
             )
print(r2.status_code) # 302
print(r2.url) # 看到的是跳转前的页面https://github.com/session
print(r2.history) # []

2.1.4 proxies

同增加headers办法相同,署理参数是dict。

import requests
import re
def get_html(url):
    proxy = {
        'http': '120.25.253.234:812',
        'https' '163.125.222.244:8123'
    }
    heads = {}
    heads['User-Agent'] = 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/49.0.2623.221 Safari/537.36 SE 2.X MetaSr 1.0'
    req = requests.get(url, headers=heads,proxies=proxy)
    html = req.text
    return html
def get_ipport(html):
    regex = r'<td data-title="IP">(.+)</td>'
    iplist = re.findall(regex, html)
    regex2 = '<td data-title="PORT">(.+)</td>'
    portlist = re.findall(regex2, html)
    regex3 = r'<td data-title="类型">(.+)</td>'
    typelist = re.findall(regex3, html)
    sumray = []
    for i in iplist:
        for p in portlist:
            for t in typelist:
                pass
            pass
        a = t+','+i + ':' + p
        sumray.append(a)
    print('署理')
    print(sumray)
if __name__ == '__main__':
    url = 'http://www.baidu.com'
    get_ipport(get_html(url))

某些接口增加了防打扰形式,关于大规模且频繁的恳求,可能会弹出验证码,或许跳转到登录验证页面,或许封禁IP地址,此刻假如想要正常访问,能够经过设置署理来解决这个问题。
除了基本的HTTP署理外,requests还支撑SOCKS协议的署理。

# 装置socks库
pip3 install "requests[socks]"
# 进行署理
import requests
proxies = {
    'http': 'socks5://user:password@host:port',
    'https': 'socks5://user:password@host:port'
}
res = requests.get('http://www.baidu.com', proxies=proxies)
print(res.status)  # 200

2.1.5 hooks

即钩子办法,requests库只支撑一个response的钩子,即在呼应返回时,能够捎带执行自定义办法。能够用于打印一些信息、做一些呼应查看、或许向呼应中增加额定的信息。

import requests
url = 'http://www.baidu.com'
def verify_res(res, *args, **kwargs):
    print('url', res.url)
    res.status='PASS' if res.status_code == 200 else 'FAIL'
res = requests.get(url, hooks={'response': verify_res})
print(res.text) # <!DOCTYPE html><!--STATUS OK--><html> 
print(res.status) # PASS

2.1.6 stream

获取内容立即下载开关,response会将报文一次性全部加载到内存中,假如报文过大,能够运用此参数,迭代下载。

import requests
url="http://www.baidu.com"
r = requests.get(url, stream=True)
# 解析response_body,以\n切割
for lines in r.iter_lines():
    print("lines:", lines)
# 解析response_body,以字节切割
for chunk in r.iter_content(chunk_size=1024):
    print("chunk:", chunk)

2.1.7 verify

认证SSL证书开关,当发送HTTPS恳求的时候,假如该网站的证书没有被CA机构信赖,程序将报错,能够运用verify参数操控是否查看SSL证书。

# 1、直接设置
import requests
response = requests.get('https://www.12306.cn', verify=False)
print(response.status_code)
# 2、恳求时尽管设置了越过查看,可是程序运行时仍然会发生正告,正告中包括建议给我们的指定证书
# 能够经过设置,忽略屏蔽这个正告
from requests.packages import urllib3  # 假如报错,则直接引进import urllib3
# 3、屏蔽正告
urllib3.disable_warnings()
response = requests.get('https://www.12306.cn', verify=False)
print(response.status_code) # 200
# 4、经过cert直接声明证书
# 本地需求有crt和key文件(key有必要是解密状况,加密状况的key是不支撑的),并指定它们的途径,
response = requests.get('https://www.12306.cn',cert('/path/server.crt','/path/key'))
print(response.status_code) # 200

2.2 requests库的反常

怎么判别是否出现反常呢?

2.2.1 raise_for_status()

该办法在内部判别res.status_code是否等于200,不是则发生反常HTTPError

示例:

# 1、HTTPError反常示例
import requests
from requests.exceptions import HTTPError
try:
    res = requests.post("http://127.0.0.1:8080/example/post")
    res.raise_for_status()
    # 等同于
    if res.status != 200:
        raise HTTPError
    return res
except HTTPError:
    return False

2.2.2 ReadTimeout

该反常类型,将会捕捉到因恳求/呼应超时的恳求。

# Timeout超时反常
import requests
from requests.exceptions import ReadTimeout
try:
    res = requests.get('http://127.0.0.1:8080/example/post',timeout=0.5)
    print(res.status_code)
    return res
except ReadTimeout:
    print('timeout')

2.2.3 RequestException

该反常类型,将会捕捉到因无恳求引起的反常恳求。

# RquestError反常
import requests
from requests.exceptions import RequestException
try:
    res = requests.get('http://127.0.0.1:8080/example/post')
    print(res.status_code)
    return res
except RequestException:
    print('reqerror')

3 总结

看到这儿,我们应该明白了,requests库是一个比urilib2模块愈加简练的第三方库,它具有如下的特色:

  • 支撑HTTP衔接保持和衔接池
  • 支撑运用cookie、session保持会话
  • 支撑文件上传
  • 支撑主动呼应内容的编码
  • 支撑国际化的URL和Post数据主动编码
  • 支撑主动实现耐久衔接keep-alive

因而,requests这个高度封装的模块,能够使我们的HTTP恳求,变得愈加人性化,运用它将能够垂手可得的完成浏览器恳求的任何操作,充分诠释了它的口号:“HTTP for Humans”。

作者:京东物流 骆铜磊

来源:京东云开发者社区