Python Requests模块的扩展使用笔记

本文详细介绍了Python Requests模块的响应体内容工作流及其优势,包括如何控制响应下载和利用工作流实现实时下载进度更新及避免大文件内存问题。此外,还探讨了Requests模块的其他用法,如检查URL重定向和验证网页存在,提供了相关代码示例和HTTP状态码的知识。
部署运行你感兴趣的模型镜像

1、requests模块的响应体内容工作流的运用

API引述

默认情况下,当你进行网络请求后,响应体会立即被下载。你可以通过 stream 参数覆盖这个行为,
推迟下载响应体直到访问 Response.content 属性:

		tarball_url = 'https://github.com/kennethreitz/requests/tarball/master'
		r = requests.get(tarball_url, stream=True)

此时仅有响应头被下载下来了,连接保持打开状态,因此允许我们根据条件获取内容:

	if int(r.headers['content-length']) < TOO_LONG:
	  content = r.content
	  ...

你可以进一步使用 Response.iter_content 和 Response.iter_lines 方法来控制工作流,或者以 Response.raw 从底层 urllib3 的 urllib3.HTTPResponse <urllib3.response.HTTPResponse 读取未解码的响应体。

如果你在请求中把 stream 设为 True,Requests 无法将连接释放回连接池,除非你 消耗了所有的数据,或者调用了 Response.close。 这样会带来连接效率低下的问题。如果你发现你在使用 stream=True 的同时还在部分读取请求的 body(或者完全没有读取 body),那么你就应该考虑使用 with 语句发送请求,这样可以保证请求一定会被关闭:

	with requests.get('http://httpbin.org/get', stream=True) as r:
	    # 在此处理响应。

评注

这种方法与过去我们直接使用requests.get(url)方法的区别在于:一般的请求上,我们都是直接将数据一次性拿回来,而使用工作流的方式,我们可以先取响应头。再对数据进行后续操作。
这让我们可以根据响应头的信息(响应内容长度、响应的形式等),决定是否需要获取数据(下载操作)
因此传统的操作,被我们分拆成如下的操作:

import requests
url = 'target_url'
response = requests.get(url,stream=True) # 此时我们已经下载了响应头和响应内容

#-------------------------------------	
#-------------------------------------

import requests
url = 'target_url'
response = requests.get(url,stream=True) # 此时我们只下载了响应头
if response.headers['字段信息'] 满足 条件x:
	print(response.content) # 此时才开始下载响应内容
response.close() #这一步不要遗漏

这种使用方法的运用还不仅于此,我们如果再结合API提供的函数requests.response.iter_content()对工作流进行操作,就可以实现两种目的:

  1. 实时下载进度的更新
  2. 避免目标数据过大一次性读入内存处理的问题

代码实例:

# -*- coding: utf-8 -*-
"""
Created on Mon Oct 15 14:05:06 2018
Description:
Version:
@author: HJY
"""

import time
import requests

try: 
    length_star = 50 # 总的星星数
    start = time.time()
    filename = 'python_guide.zip'
    url = 'https://codeload.github.com/kennethreitz/python-guide/zip/master'
    response = requests.get(url,stream=True)
    print(response.headers)
    content_length = int(response.headers['content-length'])
    size = 0
    switch = int(content_length/50)
    
    print('[文件大小]:{:.2f}MB'.format(content_length/(1024*1024)))    
    with open(filename,'wb') as f:       
        for data in response.iter_content(chunk_size=1024):
            f.write(data)
            size += len(data)
            star_num = size//switch
            percent = size/content_length
            progress = "\r[" + '>'* star_num + ' '*(length_star-star_num) +']' +'--下载进度:{:.0f}%'.format(percent * 100)
            print(progress,end='')
    
except Exception as e:
    print(e)
else:
    print('\n[下载耗时]:%ss' % (time.time()-start))    

finally:        
    response.close()
            

效果图:

在这里插入图片描述在这里插入图片描述

2、requests模块的其他用法

两篇Rytis Sileika的博客:

1、Quick way to check for URL redirects

这篇博客主要讲了一个关于如何判断一个网页链接是否会引发重定向的python脚本实现。代码如下:

import sys
import requests

def check_for_redirects(url):
    try:
        r = requests.get(url,allow_redirects=False,
                         timeout=0.5)
        if 300 <= r.status_code < 400:
            return r.headers['location']
        else:
            return '[no redirect]'
    except requests.exceptions.Timeout:
        return '[timeout]'
    except requests.exceptions.ConnectionError:
        return '[connection error]'
    
def check_domain(urls):
    for url in urls:
        url_to_check = url if url.startswith('http') else "http://%s" % url
        redirect_url = check_for_redirects(url_to_check)
        print("%s => %s" % (url_to_check,redirect_url))
    
if __name__ == '__main__':
    fname = 'domains.txt'
    try:
        fname = sys.argv[1]
    except IndexError:
        pass
    urls = (l.strip() for l in open(fname).readlines()) 
    check_domain(urls)

domains.txt文件

google.com
http://gmail.com
www.ibm.com
redhat.com
example.com
i-believe-this-domain-does-not-exist-123abc.com

显示结果
在这里插入图片描述

实现思路
  1. 用requests模块发起GET请求,利用get方法的allow_redirect属性阻止重定向
  2. 利用状态码判断
  3. 利用响应头中的location属性获取重定向链接
第一点

关于如何知道allow_redirect这个属性,查看Requests API并没看到有关于这个属性的用法,因而只能查看源码。

查看模块requests模块文档路径

	import requests
	help(requets)

查看requests.get的源代码路径:

	import requests
	help(requests.get)

显示结果:

Help on function get in module requests.api:

故而在requests包中的api.py文件.

def get(url, params=None, **kwargs):
    """Sends a GET request.

    :param url: URL for the new :class:`Request` object.
    :param params: (optional) Dictionary or bytes to be sent in the query string for the :class:`Request`.
    :param \*\*kwargs: Optional arguments that ``request`` takes.
    :return: :class:`Response <Response>` object
    :rtype: requests.Response
    """

其中**kwargs参数:

 Optional arguments that ``request`` takes

转而查看文件中的request函数,可以看到参数说明:

:param allow_redirects: (optional) Boolean.
Set to True if POST/PUT/DELETE redirect following is allowed.

这个参数设置是否允许重定向。同时我们也可以学习到还有很多文档中没有指出的参数。

第二点

查阅响应码:

300——请求的资源可在多处得到
301——删除请求数据
302——在其他地址发现了请求数据
303——建议客户访问其他URL或访问方式
304——客户端已经执行了GET,但文件未变化
305——请求的资源必须从服务器指定的地址得到
306——前一版本HTTP中使用的代码,现行版本中不再使用
307——申明请求的资源临时性删除

可以看出这个3xx的响应码基本与重定向有关

2、How to check if a web page exists

这篇博客主要讲了如何判断网页是否存在,代码上没什么稀奇,实际上我们会说直接用网络状态码是200还是404就可以了,但这提供的信息并不详细,作者的方式让我注意到HEAD请求的存在。博主使用python 2.7的httlplib包实现,在这个基础上我补充了3.x版本的httplib包的实现以及Requests模块的简单实现。

# -*- coding: utf-8 -*-
"""
Created on Wed Jan 16 16:00:48 2019

@author: HJY
"""

#python2.7 version
#----------------------------------
import httplib

conn = httplib.HTTPConnection('www.w3.org')
conn.request('HEAD','/Protocols/rfc2616/rfc2616-sec9.html')
resp = conn.getresponse()
data = resp.read()
#   as you can see, there is no data, 
#   this is because we've used HEAD method
for h in resp.getheaders():
    print h
    
print resp.status

#-----------------------------------

# python 3.x http.client
import http.client

conn = http.client.HTTPConnection('www.w3.org')
conn.request('HEAD',"/Protocols/rfc2616/rfc2616-sec9.html")
resp = conn.getresponse()
data = resp.read()
for h in resp.getheaders():
    print(h)
    
print(resp.status)
#-----------------------------------

# Python 3.x Requests
import requests
url = 'http://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html'
r = requests.head(url)
print(r.content)
print(r.headers)
print(r.status_code)

以往我使用Request模块只注意到有.get().post()方法,全然不知有.head方法,在只想要响应头时,使用.head而不用.get获取全部,我想这其中是有效率和内存之分的,关于这点暂没深究。

另外也让我学习了下httplib模块的API,这应该也是一种收获吧。

您可能感兴趣的与本文相关的镜像

Python3.11

Python3.11

Conda
Python

Python 是一种高级、解释型、通用的编程语言,以其简洁易读的语法而闻名,适用于广泛的应用,包括Web开发、数据分析、人工智能和自动化脚本

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值