当前位置:首页 > 文章列表 > 文章 > 前端 > Python爬取PDF并按HTML命名保存

Python爬取PDF并按HTML命名保存

2025-12-17 20:09:35 0浏览 收藏
推广推荐
免费电影APP ➜
支持 PC / 移动端,安全直达

哈喽!大家好,很高兴又见面了,我是golang学习网的一名作者,今天由我给大家带来一篇《Python爬取PDF并按HTML文本命名保存》,本文主要会讲到等等知识点,希望大家一起学习进步,也欢迎大家关注、点赞、收藏、转发! 下面就一起来看看吧!

使用Python从网站下载PDF并根据HTML文本自定义文件名

本教程详细介绍了如何使用Python从ASP网站下载PDF文件,并根据HTML `` 标签的显示文本来命名本地文件。通过`requests`库处理HTTP请求和`BeautifulSoup`解析HTML,我们能够准确提取下载链接和用户友好的文件名,解决了直接使用URL文件名不直观的问题。文章涵盖了环境设置、HTML解析、URL处理、文件下载与保存等关键步骤,并提供了完整的示例代码和注意事项。

在自动化数据抓取和文件下载的场景中,我们经常需要从网站上下载文件,并以一种更具描述性或用户友好的方式来命名这些文件,而不是简单地沿用URL中自带的文件名。特别是在处理动态生成的页面或链接时,HTML 标签的文本内容往往能提供比URL本身更清晰的文件描述。本教程将以从ASP网站下载PDF文件为例,详细讲解如何利用Python实现这一目标。

1. 准备工作

在开始之前,我们需要安装一些必要的Python库。requests库用于处理HTTP请求,而BeautifulSoup(通常与解析器如lxml或html.parser配合使用)则用于解析HTML内容。

pip install requests beautifulsoup4 lxml

接下来,导入所需的模块:

import os
import requests
from bs4 import BeautifulSoup

2. 发送HTTP POST请求获取页面内容

许多网站,尤其是ASP站点,会通过POST请求来动态加载内容。我们需要模拟这种请求以获取包含PDF链接的HTML页面。这通常涉及构建请求的URL、headers以及请求体(payload)。

# 目标网站的基础URL
base_url = "https://www.svpo.nl/curriculum.asp"

# 模拟浏览器发送请求的User-Agent,以避免被网站识别为爬虫
headers = {
    'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9',
    'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/103.0.0.0 Safari/537.36'
}

# 示例:定义需要请求的课程和科目
klassen = ['1e klas']
vakken = ['Wiskunde']

# 定义文件保存的根目录
output_root_path = r'c:\books' # 使用原始字符串避免反斜杠转义问题

# 循环处理每个课程和科目
for klas in klassen:
    for vak in vakken:
        # 构建当前科目和课程的输出路径
        current_output_path = os.path.join(output_root_path, klas, vak)
        # 如果目录不存在,则创建它。exist_ok=True 避免目录已存在时报错
        os.makedirs(current_output_path, exist_ok=True)

        # 构建POST请求的payload
        payload = {'vak': vak, 'klas_en_schoolsoort': klas}

        # 发送POST请求获取页面内容
        try:
            response = requests.post(base_url, data=payload, headers=headers, timeout=10)
            response.raise_for_status() # 检查HTTP请求是否成功 (200 OK)
            print(f"成功获取 {klas} - {vak} 的页面内容。")
        except requests.exceptions.RequestException as e:
            print(f"获取 {klas} - {vak} 页面内容失败: {e}")
            continue # 跳过当前科目,处理下一个

3. 解析HTML内容提取PDF链接和名称

获取到页面HTML内容后,我们需要使用BeautifulSoup来解析它,找到所有指向PDF文件的链接,并提取其文本内容作为文件名。

        # 使用lxml解析器解析HTML内容
        soup = BeautifulSoup(response.text, "lxml")

        # 查找所有带有'href'属性的<a>标签
        all_links = soup.find_all('a', {'href': True})

        for link_tag in all_links:
            pdf_url = link_tag.get('href')

            # 检查链接是否以'.pdf'结尾(不区分大小写)
            if pdf_url and pdf_url.lower().endswith('.pdf'):
                # 提取<a>标签的文本内容作为文件名
                # 例如:<a href="...">Chapter 3 - Weird science</a> -> "Chapter 3 - Weird science"
                display_name = link_tag.text.strip()

                # 处理URL路径和文件名
                # 网站URL中可能使用反斜杠,HTTP URL应使用正斜杠
                pdf_url = pdf_url.replace('\\', '/')

                # 构造本地保存的文件名。注意添加'.pdf'后缀
                # 示例: "Chapter 3 - Weird science" -> "Chapter 3 - Weird science.pdf"
                filename = f"{display_name}.pdf"

                # 构建完整的本地文件路径
                full_file_path = os.path.join(current_output_path, filename)

                print(f"发现PDF: {display_url},将保存为: {full_file_path}")

                # 下载并保存PDF文件
                try:
                    pdf_response = requests.get(pdf_url, stream=True, timeout=15) # 使用stream=True处理大文件
                    pdf_response.raise_for_status()

                    with open(full_file_path, 'wb') as f:
                        for chunk in pdf_response.iter_content(chunk_size=8192):
                            f.write(chunk)
                    print(f"成功下载并保存: {filename}")
                except requests.exceptions.RequestException as e:
                    print(f"下载 {pdf_url} 失败: {e}")
                except IOError as e:
                    print(f"保存文件 {full_file_path} 失败: {e}")
                print('---')

4. 完整示例代码

以下是整合了所有步骤的完整Python脚本,用于从ASP网站下载PDF文件并根据链接文本自定义文件名。

import os
import requests
from bs4 import BeautifulSoup

def download_pdfs_with_custom_names(base_url, output_root_path, klassen, vakken):
    """
    从指定ASP网站下载PDF文件,并根据HTML链接文本自定义文件名。

    Args:
        base_url (str): 目标网站的URL。
        output_root_path (str): 文件保存的根目录。
        klassen (list): 包含课程名称的列表。
        vakken (list): 包含科目名称的列表。
    """
    headers = {
        'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9',
        'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/103.0.0.0 Safari/537.36'
    }

    print(f"开始从 {base_url} 下载PDF文件...")

    for klas in klassen:
        for vak in vakken:
            current_output_path = os.path.join(output_root_path, klas, vak)
            os.makedirs(current_output_path, exist_ok=True)
            print(f"\n--- 处理 {klas} - {vak} ---")

            payload = {'vak': vak, 'klas_en_schoolsoort': klas}

            # 1. 发送POST请求获取页面内容
            try:
                response = requests.post(base_url, data=payload, headers=headers, timeout=10)
                response.raise_for_status() # 检查HTTP请求是否成功
                print(f"成功获取 {klas} - {vak} 的页面内容。")
            except requests.exceptions.RequestException as e:
                print(f"获取 {klas} - {vak} 页面内容失败: {e}")
                continue

            # 2. 解析HTML内容提取PDF链接和名称
            soup = BeautifulSoup(response.text, "lxml")
            all_links = soup.find_all('a', {'href': True})

            pdfs_found = False
            for link_tag in all_links:
                pdf_url = link_tag.get('href')

                if pdf_url and pdf_url.lower().endswith('.pdf'):
                    pdfs_found = True
                    display_name = link_tag.text.strip()

                    # 统一URL中的斜杠,确保HTTP请求正确
                    pdf_url = pdf_url.replace('\\', '/')

                    # 构造本地保存的文件名
                    filename = f"{display_name}.pdf"

                    # 清理文件名中可能存在的非法字符(Windows/Linux路径限制)
                    # 这是一个简单的清理,更健壮的方案可能需要正则表达式
                    # 这里假设 display_name 已经相对干净
                    invalid_chars = '<>:"/\\|?*'
                    for char in invalid_chars:
                        filename = filename.replace(char, '_')

                    full_file_path = os.path.join(current_output_path, filename)

                    print(f"  - 发现PDF: {pdf_url}")
                    print(f"    将保存为: {full_file_path}")

                    # 3. 下载并保存PDF文件
                    try:
                        # 使用 stream=True 和 iter_content 处理大文件,节省内存
                        pdf_response = requests.get(pdf_url, stream=True, timeout=15)
                        pdf_response.raise_for_status()

                        with open(full_file_path, 'wb') as f:
                            for chunk in pdf_response.iter_content(chunk_size=8192):
                                f.write(chunk)
                        print(f"    成功下载并保存: {filename}")
                    except requests.exceptions.RequestException as e:
                        print(f"    下载 {pdf_url} 失败: {e}")
                    except IOError as e:
                        print(f"    保存文件 {full_file_path} 失败: {e}")

            if not pdfs_found:
                print(f"  - 未在 {klas} - {vak} 页面中找到任何PDF链接。")

    print("\n所有PDF下载任务完成。")

# 配置参数并运行脚本
if __name__ == "__main__":
    target_base_url = "https://www.svpo.nl/curriculum.asp"
    output_directory = r'c:\books' # Windows路径建议使用原始字符串

    # 示例课程和科目列表,可以根据需要扩展
    target_klassen = ['1e klas']
    target_vakken = ['Wiskunde']
    # target_vakken = ['Engels','Aardrijkskunde','Economie', 'Filosofie','Frans', 'Geschiedenis', \
    #                  'Nask', 'Natuurkunde', 'Nederlands', 'Scheikunde', 'Spaans', 'Wiskunde',\
    #                  'Biologie', 'Duits', 'Grieks','Latijn','Leesmateriaal', \
    #                  'Loopbaanorientatie','NLT']

    download_pdfs_with_custom_names(target_base_url, output_directory, target_klassen, target_vakken)

5. 注意事项与最佳实践

总结

本教程详细演示了如何使用Python的requests和BeautifulSoup库,从动态生成的网页中提取PDF下载链接和用户友好的显示名称,并将其保存到本地文件系统。通过自定义文件名,我们不仅提高了下载文件的可读性,也展示了Python在网页内容自动化处理方面的强大能力。掌握这些技术,您可以更高效地进行网络数据抓取和文件管理。

文中关于的知识介绍,希望对你的学习有所帮助!若是受益匪浅,那就动动鼠标收藏这篇《Python爬取PDF并按HTML命名保存》文章吧,也可关注golang学习网公众号了解相关技术文章。

多主题切换中的CSS动画实用技巧多主题切换中的CSS动画实用技巧
上一篇
多主题切换中的CSS动画实用技巧
Windows10磁盘整理方法及技巧
下一篇
Windows10磁盘整理方法及技巧
查看更多
最新文章
查看更多
课程推荐
  • 前端进阶之JavaScript设计模式
    前端进阶之JavaScript设计模式
    设计模式是开发人员在软件开发过程中面临一般问题时的解决方案,代表了最佳的实践。本课程的主打内容包括JS常见设计模式以及具体应用场景,打造一站式知识长龙服务,适合有JS基础的同学学习。
    543次学习
  • GO语言核心编程课程
    GO语言核心编程课程
    本课程采用真实案例,全面具体可落地,从理论到实践,一步一步将GO核心编程技术、编程思想、底层实现融会贯通,使学习者贴近时代脉搏,做IT互联网时代的弄潮儿。
    516次学习
  • 简单聊聊mysql8与网络通信
    简单聊聊mysql8与网络通信
    如有问题加微信:Le-studyg;在课程中,我们将首先介绍MySQL8的新特性,包括性能优化、安全增强、新数据类型等,帮助学生快速熟悉MySQL8的最新功能。接着,我们将深入解析MySQL的网络通信机制,包括协议、连接管理、数据传输等,让
    500次学习
  • JavaScript正则表达式基础与实战
    JavaScript正则表达式基础与实战
    在任何一门编程语言中,正则表达式,都是一项重要的知识,它提供了高效的字符串匹配与捕获机制,可以极大的简化程序设计。
    487次学习
  • 从零制作响应式网站—Grid布局
    从零制作响应式网站—Grid布局
    本系列教程将展示从零制作一个假想的网络科技公司官网,分为导航,轮播,关于我们,成功案例,服务流程,团队介绍,数据部分,公司动态,底部信息等内容区块。网站整体采用CSSGrid布局,支持响应式,有流畅过渡和展现动画。
    485次学习
查看更多
AI推荐
  • ChatExcel酷表:告别Excel难题,北大团队AI助手助您轻松处理数据
    ChatExcel酷表
    ChatExcel酷表是由北京大学团队打造的Excel聊天机器人,用自然语言操控表格,简化数据处理,告别繁琐操作,提升工作效率!适用于学生、上班族及政府人员。
    3336次使用
  • Any绘本:开源免费AI绘本创作工具深度解析
    Any绘本
    探索Any绘本(anypicturebook.com/zh),一款开源免费的AI绘本创作工具,基于Google Gemini与Flux AI模型,让您轻松创作个性化绘本。适用于家庭、教育、创作等多种场景,零门槛,高自由度,技术透明,本地可控。
    3548次使用
  • 可赞AI:AI驱动办公可视化智能工具,一键高效生成文档图表脑图
    可赞AI
    可赞AI,AI驱动的办公可视化智能工具,助您轻松实现文本与可视化元素高效转化。无论是智能文档生成、多格式文本解析,还是一键生成专业图表、脑图、知识卡片,可赞AI都能让信息处理更清晰高效。覆盖数据汇报、会议纪要、内容营销等全场景,大幅提升办公效率,降低专业门槛,是您提升工作效率的得力助手。
    3579次使用
  • 星月写作:AI网文创作神器,助力爆款小说速成
    星月写作
    星月写作是国内首款聚焦中文网络小说创作的AI辅助工具,解决网文作者从构思到变现的全流程痛点。AI扫榜、专属模板、全链路适配,助力新人快速上手,资深作者效率倍增。
    4704次使用
  • MagicLight.ai:叙事驱动AI动画视频创作平台 | 高效生成专业级故事动画
    MagicLight
    MagicLight.ai是全球首款叙事驱动型AI动画视频创作平台,专注于解决从故事想法到完整动画的全流程痛点。它通过自研AI模型,保障角色、风格、场景高度一致性,让零动画经验者也能高效产出专业级叙事内容。广泛适用于独立创作者、动画工作室、教育机构及企业营销,助您轻松实现创意落地与商业化。
    3951次使用
微信登录更方便
  • 密码登录
  • 注册账号
登录即同意 用户协议隐私政策
返回登录
  • 重置密码