Python 之下载文件
Starting
最近,站长正在学习使用 Python 进行网络爬虫。大概学会了:
-
利用 客户端渲染 网页中的网络接口为己所用
-
学会使用 requests 进行页面的简单爬取
-
正则表达式 及 re 模块的使用
-
BeautifulSoup 4 和 xpath 解析方式
站长看的是 Bilibili 上的这套《课程》。
学到 bs4 解析时,视频录制者也就是那个老师引入了批量爬取图片后对图片进行下载的知识。
Principle
老师讲得很清楚,主要就是获取文件的 字节数据 ,然后用 open()
方法打开文件后将字节内容写入即可。
我亲手试验下载 wallhaven 上的一张图片,成功。
但是我将整个内容模块化了,急需者请翻到文末直接复制代码。
Problems
在使用过程中,我发现一个神奇的东西,\
可以对 Windows 中的路径中的 “\” 进行转义,也可以用 r 字符串 进行全文反转义。
其中 r 字符串有个限制:反斜杠 \ 不能出现在字符串的最后,因为此时 \ 转义了引号,都已经识别不成字符串了还转个屁义。
但是使用双反斜杠也有 Bug ,终端输出没有找到路径 folder\\file
。
好家伙,由于没搞清楚,我直接以为它把双反斜杠直接识别成了双反斜杠,那这样问题不就无解了吗(后来才知道这是所有编程语言返回内容输出的一个习惯)?
折腾了一个上午,终于让我找到问题:
open() 方法的写入模式最多只能创建文件,不能创建文件夹。
所以搞那么多原来 FileNotFoundError
里说的是没有找到路径而不是找不到文件!晕 ~
那么解决这个问题咋整?Follow me:
Practice
首先,导入 os 模块和 requests 包。
import os
import requests
其中:requests 属于第三方库,作为 Python 第三方库集合平台中著名的项目,你可以在安装好 Python 的情况下在命令行终端使用 pip install requests
命令进行安装,出错或不会可以上网搜。
首先要获取要下载文件的二进制字符串,即字节。
# Get bytes of file.
f = requests.get(链接).content
引用一个老师给的获取文件名的方法:
Attention
用到的下载链接必须是文件的直链。
获取的方法就是将文件直链以“/”为分割单位将内容分成列表,然后取列表最后一项。
# Extract the file name from the file chain.
file_name = 链接.split('/')[-1]
然后就是那个纠缠我一个上午的难题了:
判断文件夹是否存在,不存在则创建,存在则继续:
# Create if folder does not exist.
# The open() method can create files but folder.
if not os.path.exists(文件夹名):
os.makedirs(文件夹名)
else:
# Don't do anything.
pass
以写入(重写)二进制内容的方式(即 mode = "wb"
),打开指定路径的一个以 file_name
内容为名的文件,将二进制的字节写入文件,然后关闭文件:
# Write the bytes of the file into the file.
with open(路径 + 文件名, 'wb') as f_obj:
f_obj.write(f)
f_obj.close() # Close files to reduce memory usage.
Summary
我把整个项目的代码罗列出来,方便大家使用(可以作模块,也可以复制到代码文件,都方便调用):
import os
import requests
def download(src, path="data\\"):
f = requests.get(src).content # Get bytes of file.
# Extract the file name from the file chain.
file_name = src.split('/')[-1]
# Create if folder does not exist.
# The open() method can create files but folder.
if not os.path.exists(path):
os.makedirs(path)
else:
# Don't do anything.
pass
# Write the bytes of the file into the file.
with open(path + file_name, 'wb') as f_obj:
f_obj.write(f)
f_obj.close() # Close files to reduce memory usage.