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

如何用Beautiful Soup或Selenium(Py)下载ASPX动态PDF链接?

解决ASPX动态网站批量下载Misdemeanor日历PDF的问题

你的问题很典型——ASPX动态页面的链接不是静态URL,而是通过__doPostBack JavaScript函数触发服务器生成PDF,所以直接用requests访问HTML里的href只会得到无效内容。下面给你两种可行的解决方案,优先推荐Selenium方案,因为更直观易实现:

方案一:用Selenium批量点击并自动下载PDF

这个方案会配置Firefox自动下载PDF到指定文件夹,然后循环打开每个"Misdemeanor"链接,完成下载后关闭标签回到原页面:

from selenium import webdriver
from selenium.webdriver.firefox.options import Options
from selenium.webdriver.common.by import By
from selenium.webdriver.common.keys import Keys
import time
import os

# 配置下载路径和浏览器偏好
download_folder = os.path.join(os.getcwd(), "Calendars")
os.makedirs(download_folder, exist_ok=True)

firefox_options = Options()
# 设置自定义下载文件夹
firefox_options.set_preference("browser.download.folderList", 2)
firefox_options.set_preference("browser.download.dir", download_folder)
# 指定PDF类型自动下载,不弹出询问框
firefox_options.set_preference("browser.helperApps.neverAsk.saveToDisk", "application/pdf")
# 禁用Firefox内置PDF查看器,直接下载文件
firefox_options.set_preference("pdfjs.disabled", True)

# 启动浏览器并打开目标页面
browser = webdriver.Firefox(options=firefox_options)
browser.get("http://www.imperial.courts.ca.gov/CourtCalendars/Public/MCalendars.aspx")

# 获取所有"Misdemeanor"链接元素
misdemeanor_links = browser.find_elements(By.LINK_TEXT, "Misdemeanor")
total_links = len(misdemeanor_links)
print(f"已找到 {total_links} 个Misdemeanor日历链接")

# 保存原页面窗口句柄,方便后续切换回去
original_window = browser.current_window_handle

for index, link in enumerate(misdemeanor_links):
    print(f"正在处理第 {index + 1}/{total_links} 个链接...")
    # 按住Ctrl+点击链接,在新标签页打开(避免跳转原页面导致元素失效)
    link.send_keys(Keys.CONTROL + Keys.RETURN)
    # 等待新标签页加载
    time.sleep(1)
    # 切换到新打开的标签页
    for window in browser.window_handles:
        if window != original_window:
            browser.switch_to.window(window)
            break
    # 等待PDF下载完成(根据网络速度调整等待时间)
    time.sleep(3)
    # 关闭当前标签页,回到原页面
    browser.close()
    browser.switch_to.window(original_window)

print("所有PDF下载完成!")
browser.quit()

关键说明:

  • 配置浏览器偏好是核心:让Firefox自动下载PDF,不用手动确认弹窗
  • 用Ctrl+RETURN打开新标签,避免原页面DOM被破坏,导致后续链接找不到
  • 切换窗口句柄是管理多标签页的关键,记得处理完一个标签后切回原页面

方案二:用requests模拟ASPX表单提交(无需浏览器)

如果想避免使用浏览器,效率更高,可以直接模拟ASPX的__doPostBack请求,需要先获取页面的ViewState和EventValidation等参数:

import requests
from bs4 import BeautifulSoup
import os
import re

download_folder = os.path.join(os.getcwd(), "Calendars")
os.makedirs(download_folder, exist_ok=True)

session = requests.Session()
base_url = "http://www.imperial.courts.ca.gov/CourtCalendars/Public/MCalendars.aspx"

# 第一步:获取初始页面,提取ViewState、EventValidation和__EVENTTARGET等参数
response = session.get(base_url)
response.raise_for_status()
soup = BeautifulSoup(response.text, "html.parser")

# 提取ASPX必需的表单参数
view_state = soup.find("input", {"id": "__VIEWSTATE"}).get("value")
view_state_generator = soup.find("input", {"id": "__VIEWSTATEGENERATOR"}).get("value")
event_validation = soup.find("input", {"id": "__EVENTVALIDATION"}).get("value")

# 找到所有Misdemeanor链接对应的__doPostBack参数
links = soup.find_all("a", string="Misdemeanor")
post_back_pattern = re.compile(r"__doPostBack\('(.*?)','(.*?)'\)")

for index, link in enumerate(links):
    print(f"正在下载第 {index + 1}/{len(links)} 个PDF...")
    # 解析__doPostBack的参数
    match = post_back_pattern.search(link.get("href"))
    event_target = match.group(1)
    event_argument = match.group(2)

    # 构造POST请求数据
    form_data = {
        "__VIEWSTATE": view_state,
        "__VIEWSTATEGENERATOR": view_state_generator,
        "__EVENTVALIDATION": event_validation,
        "__EVENTTARGET": event_target,
        "__EVENTARGUMENT": event_argument
    }

    # 发送POST请求获取PDF内容
    pdf_response = session.post(base_url, data=form_data)
    pdf_response.raise_for_status()

    # 提取PDF文件名(从响应头或链接推导)
    content_disposition = pdf_response.headers.get("Content-Disposition")
    if content_disposition:
        filename = re.findall(r"filename=(.+)", content_disposition)[0].strip('"')
    else:
        filename = f"misdemeanor_calendar_{index + 1}.pdf"

    # 保存PDF文件
    with open(os.path.join(download_folder, filename), "wb") as f:
        f.write(pdf_response.content)

print("所有PDF下载完成!")

关键说明:

  • 必须使用requests.Session()保持会话,因为ASPX页面依赖Cookie维持状态
  • 要准确提取__VIEWSTATE等隐藏表单参数,这些是服务器验证请求合法性的关键
  • 通过正则表达式解析__doPostBack的参数,构造正确的POST请求

两种方案都能解决你的问题,Selenium更适合新手,不用处理复杂的表单参数;requests方案更高效,适合批量处理大量链接。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.12 04:38:47