HTTP请求:requests的进阶使用方法浅析

打印 上一主题 下一主题

主题 669|帖子 669|积分 2009

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

请求携带文件,如果有的请求需要上传文件,可以用它来实现。
  1. import requests
  2. # 上传文件
  3. f= {"files": open("favicon.ico", "rb") }
  4. data = {"name": "上传文件"}
  5. requests.request(
  6.     method = 'POST',
  7.     url = 'http://127.0.0.1:8080/example/request',  
  8.     data = data,
  9.     files = f
  10. )
复制代码
需注意:favicon.ico文件需和当前脚本在同一目录下,如果不在,可以将文件名称修改为文件路径
  1. import requests
  2. from requests.auth import HTTPBasicAuth, HTTPDigestAuth
  3. # 1、Basic Auth认证
  4. res = requests.request(
  5.     method = 'GET',
  6.     url = 'http://127.0.0.1:8080/example/request',
  7.     auth = HTTPBasicAuth("username", "password")
  8. )
  9. res.encoding = "gbk"
  10. print(res.status)  # 200
  11. # 2、DIGEST 认证
  12. res = requests.request(
  13.     method = 'GET',
  14.     url = 'http://127.0.0.1:8080/example/request',
  15.     auth = HTTPDigestAuth("username", "password")
  16. )
  17. res.encoding = "gbk"
  18. 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

请求和响应的超时时间,在网络响应延迟或者无响应时,可以通过设置超时时间,避免等待。
  1. import requests
  2. # 设置请求超时1秒,1秒后无响应,将抛出异常,1秒为connect和read时间总和
  3. requests.request(
  4.     method = 'POST',
  5.     url = 'http://127.0.0.1:8080/example/request',
  6.     json = {'k1' : 'v1', 'k2' : 'v2'},
  7.     timeout = 1
  8. )
  9. # 分别设置connect和read的超时时间,传入一个数组
  10. requests.request(
  11.     method = 'POST',
  12.     url = 'http://127.0.0.1:8080/example/request',
  13.     json = {'k1' : 'v1', 'k2' : 'v2'},
  14.     timeout = (5, 15)
  15. )
  16. # 永久等待
  17. requests.request(
  18.     method = 'POST',
  19.     url = 'http://127.0.0.1:8080/example/request',
  20.     json = {'k1' : 'v1', 'k2' : 'v2'},
  21.     timeout = None
  22.     # 或者删除timeout参数
  23. )
  24. # 捕捉超时异常
  25. from requests.exceptions import ReadTimeout
  26. try:
  27.     res = requests.get('http://127.0.0.1:8080/example/request', timeout=0.1)
  28.     print(res.status_code)
  29. except ReadTimeout:
  30.     print("捕捉到超时异常")
复制代码
2.1.3 allow_redirects

设置重定向开关。
  1. >>> import requests
  2. >>> r = requests.get('http://github.com')
  3. >>> r.url
  4. 'https://github.com/'
  5. >>> r.status_code
  6. 200
  7. >>> r.history
  8. [<Response [301]>]
  9. # 如果使用GET、OPTIONS、POST、PUT、PATCH或DELETE,则可以使用allow_redirects参数禁用重定向
  10. >>> r = requests.get('http://github.com', allow_redirects=False)
  11. >>> r.status_code
  12. 301
  13. >>> r.history
  14. []
  15. # 用HEAD启动重定向
  16. >>> r = requests.head('http://github.com', allow_redirects=True)
  17. >>> r.url
  18. 'https://github.com/'
  19. >>> r.history
  20. [<Response [301]>]
  21. import requests
  22. import re
  23. # 第一次请求
  24. r1=requests.get('https://github.com/login')
  25. r1_cookie=r1.cookies.get_dict() #拿到初始cookie(未被授权)
  26. authenticity_token=re.findall(r'name="authenticity_token".*?value="(.*?)"',r1.text)[0] #从页面中拿到CSRF TOKEN
  27. # 第二次请求:带着初始cookie和TOKEN发送POST请求给登录页面,带上账号密码
  28. data={
  29.     'commit':'Sign in',
  30.     'utf8':'✓',
  31.     'authenticity_token':authenticity_token,
  32.     'login':'xxxxxx@qq.com',
  33.     'password':'password'
  34. }
  35. # 测试一:没有指定allow_redirects=False,则响应头中出现Location就跳转到新页面,
  36. # r2代表新页面的response
  37. r2=requests.post('https://github.com/session',
  38.              data=data,
  39.              cookies=r1_cookie
  40.              )
  41. print(r2.status_code) # 200
  42. print(r2.url) # 看到的是跳转后的页面
  43. print(r2.history) # 看到的是跳转前的response
  44. print(r2.history[0].text) # 看到的是跳转前的response.text
  45. # 测试二:指定allow_redirects=False,则响应头中即便出现Location也不会跳转到新页面,
  46. # r2代表的仍然是老页面的response
  47. r2=requests.post('https://github.com/session',
  48.              data=data,
  49.              cookies=r1_cookie,
  50.              allow_redirects=False
  51.              )
  52. print(r2.status_code) # 302
  53. print(r2.url) # 看到的是跳转前的页面https://github.com/session
  54. print(r2.history) # []
复制代码
2.1.4 proxies

同添加headers方法一样,代理参数是dict。
  1. import requests
  2. import re
  3. def get_html(url):
  4.     proxy = {
  5.         'http': '120.25.253.234:812',
  6.         'https' '163.125.222.244:8123'
  7.     }
  8.     heads = {}
  9.     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'
  10.     req = requests.get(url, headers=heads,proxies=proxy)
  11.     html = req.text
  12.     return html
  13. def get_ipport(html):
  14.     regex = r'<td data-title="IP">(.+)</td>'
  15.     iplist = re.findall(regex, html)
  16.     regex2 = '<td data-title="PORT">(.+)</td>'
  17.     portlist = re.findall(regex2, html)
  18.     regex3 = r'<td data-title="类型">(.+)</td>'
  19.     typelist = re.findall(regex3, html)
  20.     sumray = []
  21.     for i in iplist:
  22.         for p in portlist:
  23.             for t in typelist:
  24.                 pass
  25.             pass
  26.         a = t+','+i + ':' + p
  27.         sumray.append(a)
  28.     print('代理')
  29.     print(sumray)
  30. if __name__ == '__main__':
  31.     url = 'http://www.baidu.com'
  32.     get_ipport(get_html(url))
复制代码
某些接口增加了防骚扰模式,对于大规模且频繁的请求,可能会弹出验证码,或者跳转到登录验证页面,或者封禁IP地址,此时如果想要正常访问,可以通过设置代理来解决这个问题。
除了基本的HTTP代理外,requests还支持SOCKS协议的代理。
  1. # 安装socks库
  2. pip3 install "requests[socks]"
  3. # 进行代理
  4. import requests
  5. proxies = {
  6.     'http': 'socks5://user:password@host:port',
  7.     'https': 'socks5://user:password@host:port'
  8. }
  9. res = requests.get('http://www.baidu.com', proxies=proxies)
  10. print(res.status)  # 200
复制代码
2.1.5 hooks

即钩子方法,requests库只支持一个response的钩子,即在响应返回时,可以捎带执行自定义方法。可以用于打印一些信息、做一些响应检查、或者向响应中添加额外的信息。
  1. import requests
  2. url = 'http://www.baidu.com'
  3. def verify_res(res, *args, **kwargs):
  4.     print('url', res.url)
  5.     res.status='PASS' if res.status_code == 200 else 'FAIL'
  6. res = requests.get(url, hooks={'response': verify_res})
  7. print(res.text) # <!DOCTYPE html><html>
  8. print(res.status) # PASS
复制代码
2.1.6 stream

获取内容立即下载开关,response会将报文一次性全部加载到内存中,如果报文过大,可以使用此参数,迭代下载。
  1. import requests
  2. url="http://www.baidu.com"
  3. r = requests.get(url, stream=True)
  4. # 解析response_body,以\n分割
  5. for lines in r.iter_lines():
  6.     print("lines:", lines)
  7. # 解析response_body,以字节分割
  8. for chunk in r.iter_content(chunk_size=1024):
  9.     print("chunk:", chunk)
复制代码
2.1.7 verify

认证SSL证书开关,当发送HTTPS请求的时候,如果该网站的证书没有被CA机构信任,程序将报错,可以使用verify参数控制是否检查SSL证书。
  1. # 1、直接设置
  2. import requests
  3. response = requests.get('https://www.12306.cn', verify=False)
  4. print(response.status_code)
  5. # 2、请求时虽然设置了跳过检查,但是程序运行时仍然会产生警告,警告中包含建议给我们的指定证书
  6. # 可以通过设置,忽略屏蔽这个警告
  7. from requests.packages import urllib3  # 如果报错,则直接引入import urllib3
  8. # 3、屏蔽警告
  9. urllib3.disable_warnings()
  10. response = requests.get('https://www.12306.cn', verify=False)
  11. print(response.status_code) # 200
  12. # 4、通过cert直接声明证书
  13. # 本地需要有crt和key文件(key必须是解密状态,加密状态的key是不支持的),并指定它们的路径,
  14. response = requests.get('https://www.12306.cn',cert('/path/server.crt','/path/key'))
  15. print(response.status_code) # 200
复制代码
2.2 requests库的异常

如何判断是否出现异常呢?
2.2.1 raise_for_status()

该方法在内部判断res.status_code是否等于200,不是则产生异常HTTPError
示例:
  1. # 1、HTTPError异常示例
  2. import requests
  3. from requests.exceptions import HTTPError
  4. try:
  5.     res = requests.post("http://127.0.0.1:8080/example/post")
  6.     res.raise_for_status()
  7.     # 等同于
  8.     if res.status != 200:
  9.         raise HTTPError
  10.     return res
  11. except HTTPError:
  12.     return False
复制代码
2.2.2 ReadTimeout

该异常类型,将会捕捉到因请求/响应超时的请求。
  1. # Timeout超时异常
  2. import requests
  3. from requests.exceptions import ReadTimeout
  4. try:
  5.     res = requests.get('http://127.0.0.1:8080/example/post',timeout=0.5)
  6.     print(res.status_code)
  7.     return res
  8. except ReadTimeout:
  9.     print('timeout')
复制代码
2.2.3 RequestException

该异常类型,将会捕捉到因无请求引起的异常请求。
  1. # RquestError异常
  2. import requests
  3. from requests.exceptions import RequestException
  4. try:
  5.     res = requests.get('http://127.0.0.1:8080/example/post')
  6.     print(res.status_code)
  7.     return res
  8. except RequestException:
  9.     print('reqerror')
复制代码
3 总结

看到这里,大家应该明白了,requests库是一个比urilib2模块更加简洁的第三方库,它具有如下的特点:

  • 支持HTTP连接保持和连接池
  • 支持使用cookie、session保持会话
  • 支持文件上传
  • 支持自动响应内容的编码
  • 支持国际化的URL和Post数据自动编码
  • 支持自动实现持久连接keep-alive
因此,requests这个高度封装的模块,可以使我们的HTTP请求,变得更加人性化,使用它将可以轻而易举的完成浏览器请求的任何操作,充分诠释了它的口号:“HTTP for Humans”。
作者:京东物流 骆铜磊
来源:京东云开发者社区

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

刘俊凯

金牌会员
这个人很懒什么都没写!

标签云

快速回复 返回顶部 返回列表