新闻中心

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

2025-11-24
浏览次数:
返回列表

使用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)。

SeoShop SeoShop

SeoShop网店系统全站纯静态html生成更符合搜索引擎优化,并修改了以前许多js代码,取消了连接地址的js代码更换为纯div+css格式,并且所有文件可自定义url和文件名,自定义内部连接,自定义外部连接,等多个符合SEO搜索引擎优化的设置,让您的网店更容易让搜索引擎收录. 简单易用 极速网店真正做到以人为本、以用户体验为中心,能使您快速搭建网上购物网站。后台管理操作简单,一目了然,没有夹杂多

SeoShop 0 查看详情 SeoShop
# 目标网站的基础URL
base_url = "https://www.svpo.nl/curriculum.asp"

# 模拟浏览器发送请求的User-Agent,以避免被网站识别为爬虫
headers = {
    'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/*if,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:ooks' # 使用原始字符串避免反斜杠转义问题

# 循环处理每个课程和科目
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="https://www.php.cn/link/263b1243ca2dbeb358777ceabc4a2e4c">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/*if,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文件https://www.php.cn/link/263b1243ca2dbeb358777ceabc4a2e4c")

    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"
--- 处理 {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("
所有PDF下载任务完成。")

# 配置参数并运行脚本
if __name__ == "__main__":
    target_base_url = "https://www.svpo.nl/curriculum.asp"
    output_directory = r'c:ooks' # 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. 注意事项与最佳实践

  • 错误处理: 在网络请求和文件操作中,错误是常见的。示例代码中包含了try-except块来捕获requests相关的异常(如网络连接问题、HTTP状态码非200)和IOError(如文件写入权限问题),这对于程序的健壮性至关重要。
  • User-Agent: 设置User-Agent请求头是模拟浏览器行为的关键。一些网站会检查此头信息,如果缺失或设置为默认值,可能会拒绝请求。
  • URL中的反斜杠: 在Windows路径中,反斜杠是分隔符。但在HTTP URL中,正斜杠/才是标准分隔符。某些网站的href属性可能会错误地使用反斜杠。在下载前,务必使用pdf_url.replace('\', '/')进行替换,以确保URL的正确性。
  • 文件名合法性: link.text可能包含特殊字符,在某些操作系统(尤其是Windows)中,这些字符不允许出现在文件名中(例如:"/|?*)。在保存文件前,建议对filename进行清理,替换或移除这些非法字符,以避免IOError。示例代码中提供了一个简单的清理方式。
  • 大文件下载: 对于大型PDF文件,使用requests.get(url, stream=True)并在iter_content中分块写入文件,可以避免一次性将整个文件加载到内存中,从而节省内存并提高效率。
  • 超时设置: 在requests.post和requests.get中设置timeout参数可以防止程序因网络无响应而无限期等待。
  • os.path.join: 使用os.path.join来拼接文件路径是跨平台兼容的最佳实践,它会自动根据操作系统的不同使用正确的路径分隔符。
  • os.makedirs(https://www.php.cn/link/263b1243ca2dbeb358777ceabc4a2e4c, exist_ok=True): 创建目录时,使用exist_ok=True可以避免在目录已存在时抛出错误,使代码更简洁。

总结

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

以上就是使用Python从网站下载PDF并根据HTML文本自定义文件名的详细内容,更多请关注其它相关文章!


# 网店  # seo优化的难题  # 玉林智能网站建设平台  # 酒店关于seo的案例  # seo优化按天扣费价格  # 房山区营销推广招标公示  # 网站建设的题目  # 姚村镇seo网站推广  # 浦口区网店营销推广  # 网站化妆品怎么做推广的  # 北京知乎营销推广服务费用  # 下载链接  # 分隔符  # 保存文件  # 大文件  # 尤其是  # linux  # 并保存  # 命令行  # 自定义  # w  # pdf  # ai  # safari  # app  # 浏览器  # 操作系统  # windows  # 正则表达式  # html  # python 


相关栏目: 【 科技资讯46185 】 【 网络学院92790


相关推荐: 蛙漫2台版漫画地址 Manwa2正版网页版链接  Python自定义类排序:解决lambda键值访问TypeError的实践指南  Sublime Text怎么设置垂直标尺_Sublime配置Rulers规范代码长度  铁路12306官网网页端快速入口 铁路12306官方首页登录教程  解决Flask中Quill编辑器内容提交失败及TypeError的指南  构建轻量级网站内部消息系统:Formspree 集成指南  没有大陆身份证/银行卡如何实名微信? 亲测有效的几种方法分享  Spyder启动失败:字体文件权限拒绝错误解决方案  Adobe PDF表单中利用J*aScript解析与格式化日期组件的教程  如何为你的Composer包编写自动化测试_集成PHPUnit到Composer的scripts工作流  蛙漫2日版入口 WAMAN2(日版)无删减漫画官网链接  CKEditor 5 自定义构建在React应用中渲染失败的调试与解决  学习通在线学习平台 学习通网页版直接进入课程中心  React Router v6 教程:构建认证保护的私有路由与重定向策略  Win11怎么设置开机NumLock亮 Win11修改注册表InitialKeyboardIndicators值  拷贝漫画电脑版官网入口 拷贝漫画(PC版)在线直达  Mac怎么锁定备忘录_Mac备忘录加密设置教程  Golang如何优化内存分配与垃圾回收_Golang内存管理与GC优化实践  在python-socketio事件处理器中安全访问Flask应用上下文  在J*a中如何开发简易博客标签推荐系统_博客标签推荐项目实战解析  支付宝如何管理隐私设置_支付宝隐私保护的配置技巧  Win11 USB传输速度慢怎么解决 Win11 USB驱动更新与设置  妖精漫画网页版登录入口免费_妖精漫画官网主页直接阅读漫画  html网页设计源代码怎么运行_运行html网页设计源代码步骤【指南】  vivo浏览器怎么扫描二维码 vivo浏览器内置扫一扫功能使用方法  蛙漫漫画免费阅读入口_蛙漫官方正版无广告纯净版  XML中包含HTML标签导致解析错误? 正确嵌入非XML数据的两种方法  Lar*el用户头像管理:实现图片缩放、存储与旧文件安全删除的最佳实践  极兔快递快件信息查询系统 极兔快递官网运单号追踪  QQ邮箱登录官网首页 腾讯QQ邮箱网页入口  c++ 获取系统当前时间 c++时间戳获取方法  Win10系统服务哪些可以禁用 Win10安全优化服务列表【干货】  PHP中获取MongoDB服务器运行时间(Uptime)的专业指南  Lar*el递归关系中排除子孙节点的策略  python3时间如何用calendar输出?  Go与Ruby之间实现AES加密互通:CFB模式下的密钥长度匹配策略  钉钉视频会议画面卡顿如何解决 钉钉会议画面优化方法  Win11怎么设置鼠标指针速度_Win11提高鼠标指针精确度选项  高德地图公交到站提醒失败如何解决 高德提醒权限设置  抖音极速版最新版本 抖音极速版官方下载地址  支付宝碰一碰设备是REDMI手机吗 博主拆机辟谣:处理器、内存都不一样  在J*a中如何使用BigDecimal进行高精度计算_BigDecimal类应用指南  在J*a项目里如何构建对象之间的契约_接口约束的实际落地  Lar*el的路由模型绑定怎么用_Lar*el Route Model Binding简化控制器逻辑  漫蛙2漫画入口 漫蛙正版网页漫画直达网址  Golang如何通过reflect操作map_Golang reflect map操作与遍历技巧  2026年发布! 美少女养成动作RPG《神剑少女战记》发布实机演示  C++如何连接MySQL数据库_C++使用Connector/C++操作MySQL数据库教程  如何使用spryker/configurable-bundles-products-resource-relationship模块解决复杂产品捆绑关系难题  必由学网页版入口 必由学官方平台直接访问 

搜索