我的知识记录

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使用。
  • 版权敏感,只下载你有权访问的文件,不要批量下载受版权保护的出版物。

Python requests下载PDF附件:二进制保存与批量导出

标签:

更新时间:2026-09-14 20:48:57

上一篇:Python requests发起GET请求教程:最简单的网页抓取入门

下一篇:Python requests下载图片文件:流式保存与文件命名