005 requests的基础使用-下载文件

1、常规下载

用requests模块的get方法获取URL,并将结果存储到一个名为“file”的变量中。然后,将这个变量的内容写入目标文件。

#coding = utf-8
import requests

url = "https://www.python.org/static/img/python-logo@2x.png"
file = requests.get(url)
open('C:\\Users\\Downloads\\python\\img.png', 'wb').write(file.content)

执行成功后,在文件夹下能够查看到已下载的图片

 

 注意:open函数用于打开一个文件,创建一个 file 对象,相关的方法才可以调用它进行读写

open(name[, mode[, buffering]])
  • name : 一个包含了你要访问的文件名称的字符串值。

如果不写文件名只填写目录,执行时会报错的,如下

C:\Users\PycharmProjects\myProject\venv\Scripts\python.exe C:/Users/PycharmProjects/myProject/main.py
Traceback (most recent call last):
  File "C:\Users\PycharmProjects\myProject\main.py", line 6, in <module>
    open('C:\\Users\\Downloads\\python', 'wb').write(file.content)
FileNotFoundError: [Errno 2] No such file or directory: 'C:\\Users\\Downloads\\python'

Process finished with exit code 1

2、下载大文件(分块/流下载)

如何用requests.get()请求一个太大的文件?

若下载到一半暂停了,想继续下载怎么办?

若有个大文件有多人同时请求,对服务器造成大压力怎么办?

采用分块下载文件,每次从服务器中读取固定大小的文件,会大大的缓解了多人访问时给服务器带来的压力。

我们可以这样做,在get()方法里面加一个参数stream=True,即:

requests.get(url,stream=True)

如果不加stream=True,那么你的硬盘很可能就不停被写入,文件会变得无比巨大,最后磁盘空间不够死机。不要问我为什么知道。

当stream=True时,后边需要自己执行Response.close()操作进行关闭结束,否则只有所有的响应体数据被读取完毕连接才会被释放,用with即可以不用close()。

当stream=True时,get请求会先建立连接,而不会把content内容或text内容下载到内存里,等开始对content操作的时候,get请求这个时候才开始下载数据。

当stream=True时,如果是下载大的文件时,用True可以先对请求的类型进行判断,如果是大文件,可以中止请求,而不用浪费大流量开销。

接着,我们在当前工作目录中创建一个名为python1.pdf的文件,并打开它进行写入。

然后,我们指定每次要下载的块大小。我们已经将其设置为1024000字节(即1MB),接着遍历每个块,并在文件中写入这些块,直到块结束。

#coding = utf-8
import requests

url = "https://readthedocs.org/projects/python-guide/downloads/pdf/latest/"
file = requests.get(url, stream=True)
with open('C:\\Users\\Downloads\\python\\python1.pdf', 'wb') as fp:
    for item in file.iter_content(1024000):
    print("1")
    fp.write(item)

通过执行完的结果可以看出,文件是分批下载的

C:\Users\PycharmProjects\myProject\venv\Scripts\python.exe C:/Users/PycharmProjects/myProject/main.py
1
1
1
1
1

Process finished with exit code 0

3、分段请求数据

#coding = utf-8
import json

import requests
"""
    目标数据分两段
    每次使用多次取回
    注意:每次写入数据的时候,设置光标的位置,防止文件损坏
"""

url = "https://readthedocs.org/projects/python-guide/downloads/pdf/latest/"
file_name = 'C:\\Users\\Downloads\\python\\python1.pdf'
file = open(file_name, 'wb')

def download_size(start, end): #按照文件大小下载
    headers = {
        "Range": f'bytes={start}-{end}'
    }
    r = requests.get(url, stream=True, headers=headers)
    print(r.headers)
    pos = start
    for i in r.iter_content(chunk_size=1024):
        if i:
            file.seek(pos)
            file.write(i)
            pos += 1024

def download_line(): #按照文件行数下载
    r = requests.get(url, stream=True)
    lines = r.iter_lines()
    for line in lines:
        if line:
            file.write(line)


#获取资源大小
r2 = requests.get(url, stream=True)
max = r2.headers['content-length']
#分两段来下载download_size(0, 1024000)download_size(1024000, int(max))
# download_line()

file.close()

4、下载多个文件(并行/批量下载)

 即多线程下载,代码如下

#coding = utf-8
import json
import threading

import requests
"""
    目标数据分两段
    每次使用多次取回
    注意:每次写入数据的时候,设置光标的位置,防止文件损坏
"""

url = "https://readthedocs.org/projects/python-guide/downloads/pdf/latest/"
file_name = 'C:\\Users\\Downloads\\python\\python1.pdf'
file = open(file_name, 'wb')

def download_size(start, end):
    print("start", start)
    print("end", end)
    headers = {
        "Range": f'bytes={start}-{end}'
    }
    r = requests.get(url, stream=True, headers=headers)
    # print(r.headers)
    pos = start
    for i in r.iter_content(chunk_size=1024):#指定文件大小
        if i:
            file.seek(pos) #可以将文件游标移动到文件的任意位置
            file.write(i)
            pos += 1024#获取资源大小
r2 = requests.get(url, stream=True)
size = int(r2.headers['content-length'])
#分两段来下载
download_size(0, 1024000)
download_size(1024000, int(size))
thread_num = 4
for i in range(thread_num):
    if i == thread_num-1:
        t1 = threading.Thread(target=download_size, args=(i * (size//thread_num), size))
        t1.start()
    else:
        t1 = threading.Thread(target=download_size, args=(i * (size//thread_num), (i + 1) * (size//thread_num)))
        t1.start()
#file.close()

报错1

TypeError: unsupported operand type(s) for //: 'str' and 'int'

通过打印发现size是str类型的,做了类型转换后正常

size = int(r2.headers['content-length'])

报错2

Exception in thread Thread-4 (download_size):
Traceback (most recent call last):
  File "C:\Users\caobaoling\Python310\lib\threading.py", line 1016, in _bootstrap_inner
    self.run()
  File "C:\Users\caobaoling\Python310\lib\threading.py", line 953, in run
    self._target(*self._args, **self._kwargs)
  File "C:\Users\caobaoling\PycharmProjects\myProject\requests_stream.py", line 27, in download_size
    file.seek(pos) #可以将文件游标移动到文件的任意位置
ValueError: seek of closed file

查看代码,file文件被close掉了,注释后正常

5、下载重定向的文件

若要下载的文件,会被重定向到另一个带有一个.pdf文件的URL,如:https://readthedocs.org/projects/python-guide/downloads/pdf/latest/

同第一种下载文件的方式相同,在get方法中添加参数allow_redirects并设置为True,重定向后的内容将被分配给变量myfile。

最后,我们打开一个文件来写入获取的内容。

#coding = utf-8
import requests

url = "https://readthedocs.org/projects/python-guide/downloads/pdf/latest/"
file = requests.get(url, allow_redirects=True)
open('C:\\Users\\Downloads\\python\\python.pdf', 'wb').write(file.content)

下载完成

参考:https://blog.csdn.net/tscaxx/article/details/123219346

https://blog.csdn.net/weixin_39626927/article/details/110515317https://www.jb51.net/article/237260.htm

posted @ 2022-09-23 19:36  baoling  阅读(780)  评论(0)    收藏  举报