You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用requests/BeautifulSoup爬取HTTPS登录站点PDF损坏及仅下载最后一个文件问题

问题根因

  1. 最初PDF文件损坏的原因:
  • 调用request.urlretrieve()时传入的是首页地址Sampleurl,而非真实的PDF文件地址,保存的内容本身就不是PDF格式。
  • urllib的下载请求没有携带requests.session中存储的登录态凭证,网站身份校验失败返回的是错误页面内容,自然无法打开。
  1. 调整后仅下载最后一个文件的原因:
    循环变量定义为for PDF in url_list,但拼接本地文件名时误用了前一段代码残留的url变量,该变量最后一次赋值就是列表最后一个PDF的地址,导致每次循环都使用同一个文件名,前面下载的文件被后续循环覆盖,最终仅保留最后一个文件。

修复后完整代码

# Import libraries
import requests
from bs4 import BeautifulSoup
import os
from pprint import pprint
import time
import re
from urllib.parse import urljoin

# Fetch username
username = os.getlogin()

# Set folder location to local users desktop
folder_location = r'C:\Users\{0}\desktop\Vodafone_Invoices'.format(username)
# 提前创建目标文件夹,避免循环内重复判断
if not os.path.exists(folder_location):
    os.mkdir(folder_location)

Sampleurl = 'https://www.tict.io'
loginurl = 'https://www.tict.io/auth/login'
secure_url = 'https://www.tict.io/tool/87dd1218-f632-4ddb-b4d2-1f195bb4a5ca'

payload = {
    'username': 'xxxx',
    'password': 'xxx',
    'ltfejs': 'xx'
}

with requests.session() as s:
    print("Connecting to website")
    # 校验登录请求是否成功
    login_resp = s.post(loginurl, data=payload)
    if login_resp.status_code not in [200, 302]:
        print("登录失败,请检查payload参数")
        exit()

    r = s.get(secure_url)
    soup = BeautifulSoup(r.content, 'html.parser')
    links = soup.find_all('a', href=re.compile(r'(.pdf)'))

    print("Gathering .PDF files")
    url_list = []
    for el in links:
        # 用urljoin拼接更稳妥,避免斜杠缺失/重复问题
        full_pdf_url = urljoin(Sampleurl, el['href'])
        url_list.append(full_pdf_url)
    
    pprint(url_list)

    print("Downloading .PDF files")
    for pdf_url in url_list:
        # 提取纯文件名
        file_name = pdf_url.split("/")[-1]
        full_file_path = os.path.join(folder_location, file_name)
        # 已存在的文件跳过下载
        if os.path.exists(full_file_path):
            print(f"{file_name} 已存在,跳过下载")
            continue
        # 用已登录的session发起请求,携带登录凭证
        pdf_resp = s.get(pdf_url)
        if pdf_resp.status_code == 200:
            with open(full_file_path, 'wb') as f:
                f.write(pdf_resp.content)
            print(f"{file_name} 下载完成")
        else:
            print(f"{file_name} 下载失败,状态码:{pdf_resp.status_code}")
            
print("This program will automatically close in 5 seconds ")
time.sleep(5)

优化说明

  • 统一使用已登录的session对象发起所有请求,确保PDF下载请求通过网站身份校验
  • 提前创建目标文件夹,移除循环内的重复判断逻辑
  • 新增本地文件存在校验,已存在的文件自动跳过,符合需求
  • 使用urljoin拼接PDF链接,规避手动字符串拼接可能出现的路径错误
  • 新增请求状态码校验,方便定位异常问题

内容的提问来源于stack exchange,提问作者MATH

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.27 19:15:05