写点什么

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

  • 2023-06-16
    北京
  • 本文字数:4810 字

    阅读完需:约 16 分钟

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

1 背景

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

2 进阶方法举例

2.1 requests.request()

method:提交方式(get|post);


url:提交地址;


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



常用的参数有: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 requestsfrom 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 ReadTimeouttry: 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_code200
>>> r.history[<Response [301]>]
# 如果使用GET、OPTIONS、POST、PUT、PATCH或DELETE,则可以使用allow_redirects参数禁用重定向>>> r = requests.get('http://github.com', allow_redirects=False)
>>> r.status_code301
>>> r.history[]
# 用HEAD启动重定向>>> r = requests.head('http://github.com', allow_redirects=True)
>>> r.url'https://github.com/'
>>> r.history[<Response [301]>]

import requestsimport 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代表新页面的responser2=requests.post('https://github.com/session', data=data, cookies=r1_cookie )
print(r2.status_code) # 200print(r2.url) # 看到的是跳转后的页面print(r2.history) # 看到的是跳转前的responseprint(r2.history[0].text) # 看到的是跳转前的response.text
# 测试二:指定allow_redirects=False,则响应头中即便出现Location也不会跳转到新页面,# r2代表的仍然是老页面的responser2=requests.post('https://github.com/session', data=data, cookies=r1_cookie, allow_redirects=False )
print(r2.status_code) # 302print(r2.url) # 看到的是跳转前的页面https://github.com/sessionprint(r2.history) # []
复制代码

2.1.4 proxies

同添加 headers 方法一样,代理参数是 dict。


import requestsimport redef 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 htmldef 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 requestsurl = '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 requestsfrom 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 requestsfrom 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 requestsfrom 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”。


作者:京东物流 骆铜磊

来源:京东云开发者社区

发布于: 刚刚阅读数: 4
用户头像

拥抱技术,与开发者携手创造未来! 2018-11-20 加入

我们将持续为人工智能、大数据、云计算、物联网等相关领域的开发者,提供技术干货、行业技术内容、技术落地实践等文章内容。京东云开发者社区官方网站【https://developer.jdcloud.com/】,欢迎大家来玩

评论

发布
暂无评论
HTTP请求:requests的进阶使用方法浅析 | 京东云技术团队_Python_京东科技开发者_InfoQ写作社区