Python requests下载PDF附件:二进制保存与批量导出
讲解用requests以二进制流式方式下载PDF文件,处理Content-Disposition自动取文件名,批量下载网页中的PDF附件,适合合同、报告、资料归档。
场景痛点
工作中经常要从OA系统、公告页面、合同库里下载一堆PDF:项目报告、招标文件、对账单。手动一个个点下载,几十个文件点到手酸。用requests把PDF链接抓出来,自动下载、自动命名,跑完喝杯水回来文件都在硬盘上了。
用到的库
pip install requests beautifulsoup4 lxml
完整代码
# 导入库
import os
import re
import requests
from urllib.parse import urljoin
from bs4 import BeautifulSoup
HEADERS = {
"User-Agent": ("Mozilla/5.0 (Windows NT 10.0; Win64; x64) "
"AppleWebKit/537.36 Chrome/124.0.0.0 Safari/537.36"),
}
def download_pdf(url, save_dir="pdfs"):
"""下载单个PDF,优先用服务器给的文件名"""
os.makedirs(save_dir, exist_ok=True)
with requests.get(url, headers=HEADERS, stream=True, timeout=30) as resp:
resp.raise_for_status()
# 尝试从响应头里取文件名(Content-Disposition)
filename = None
cd = resp.headers.get("Content-Disposition", "")
match = re.search(r'filename="?([^";]+)"?', cd)
if match:
filename = match.group(1)
# 没拿到就从URL最后一段取
if not filename:
filename = url.rstrip("/").split("/")[-1].split("?")[0]
if not filename.lower().endswith(".pdf"):
filename += ".pdf"
save_path = os.path.join(save_dir, filename)
with open(save_path, "wb") as f:
for chunk in resp.iter_content(8192):
if chunk:
f.write(chunk)
size_kb = os.path.getsize(save_path) // 1024
print(f"已下载:{filename}({size_kb} KB)")
return save_path
def find_pdf_links(page_url):
"""从一个网页里找出所有PDF链接"""
resp = requests.get(page_url, headers=HEADERS, timeout=10)
resp.encoding = resp.apparent_encoding
soup = BeautifulSoup(resp.text, "lxml")
pdf_urls = []
for a in soup.find_all("a", href=True):
href = a["href"]
if ".pdf" in href.lower():
absolute = urljoin(page_url, href)
pdf_urls.append(absolute)
return list(set(pdf_urls))
def main():
# 先从一个列表页找PDF链接
page_url = "https://example.com"
try:
pdf_urls = find_pdf_links(page_url)
print(f"找到 {len(pdf_urls)} 个PDF链接")
for u in pdf_urls:
try:
download_pdf(u)
except Exception as e:
print(f"下载失败 {u}:{e}")
except Exception as e:
print("抓取页面失败:", e)
if __name__ == "__main__":
main()
代码讲解
- 下载PDF和下载图片本质一样:二进制流式保存,
stream=True+iter_content边下边写。 - 文件名优先从
Content-Disposition响应头里解析,很多下载接口会在这个头里指定filename=xxx.pdf,用正则抓出来最准确。 - 响应头里没有文件名就从URL最后一段取,确保以
.pdf结尾。 find_pdf_links用BeautifulSoup找所有<a>标签,href里包含.pdf的就收集起来,再用urljoin补全成绝对路径。os.makedirs(save_dir, exist_ok=True)自动建pdfs目录,重复运行不报错。
运行结果
运行后先打印找到多少个PDF链接,然后逐个下载到 pdfs/ 目录,每个文件打印文件名和大小。用PDF阅读器打开能正常查看。
注意事项
- PDF文件可能很大(几十MB),务必用流式下载,不要
resp.content一次性读进内存。 - 从Content-Disposition解析文件名时可能遇到中文文件名URL编码问题,需要额外
urllib.parse.unquote解码。 - 有些PDF链接需要登录态,要配合Session和Cookie使用。
- 版权敏感,只下载你有权访问的文件,不要批量下载受版权保护的出版物。

更新时间:2026-09-14 20:48:57
上一篇:Python requests发起GET请求教程:最简单的网页抓取入门