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

Selenium+Python中ActionChains/PyAutoGUI实现Ctrl+S保存网页PDF失败求助

问题描述

我正在用Python+Selenium编写程序,需要循环遍历网页,按城镇、月份、年份点击下拉菜单打开网页版PDF,之后尝试通过Selenium ActionChains或PyAutoGUI的Ctrl+S热键保存PDF,但多种方法都无法弹出保存窗口。已知Selenium无法直接与操作系统交互,原本期望用ActionChains模拟Ctrl+S保存到指定文件夹,但可能因Selenium/ChromeDriver更新导致方法失效。

编程经验仅6个月,可能存在方法使用疏漏,求解决。
使用环境:Selenium、Chrome、PyCharm

基础循环代码:

import pyautogui
import pyperclip
from sys import path
import pdfkit
import re
from bs4 import BeautifulSoup
import selenium
from selenium import webdriver
from selenium.webdriver.chrome.service import Service
from selenium.webdriver.chrome.options import Options
from webdriver_manager.chrome import ChromeDriverManager
from selenium.webdriver.common.keys import Keys
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.support.select import Select
from selenium.webdriver.common.action_chains import ActionChains

options = Options()
s = {"savefile.default_directory" : 'C:\\Users\\My_Name\\Desktop\\Selenium Temp Folder'}
options.add_experimental_option("detach", True)
options.add_experimental_option("prefs", s)
driver = webdriver.Chrome(service=Service(ChromeDriverManager().install()), options=options)
url = 'https://www.website.com'
driver.get(url)

# 其他类代码已省略,以下是循环核心逻辑
for town in self.__towns:
    dropdown1 = driver.find_element(By.XPATH, "//select[@id='lmuArea']")
    dropdown1.click()
    target_town = driver.find_element(By.XPATH, "//option[@value='"+ town + "']")
    target_town.click()
    for year in self.__years:
        for month_num, month in self.__months.items():
            dropdown2 = WebDriverWait(driver, 5).until(
                        EC.presence_of_element_located((By.XPATH, "//select[@id='lmuTime']"))
                                    )
            dropdown2.click()
            try:
                target_date = WebDriverWait(driver, 2).until(
                              EC.presence_of_element_located((By.XPATH, "//select[@id='lmuTime']//option[@value='" + year + "-" + month_num + "'][normalize-space()='" + month + ' ' + year + "']"))
)
                target_date.click()
                view_report = driver.find_element(By.XPATH,"//div[@rel='lmu']//button[contains(text(),'View Report')]")
                view_report.click()
                tabs = driver.window_handles
                driver.switch_to.window(tabs[1])

已尝试的方法:

  1. pdfkit转存PDF:不确定是否能实际保存到指定文件夹
pdfkit.from_url(driver.current_url, 'New_Name.pdf', configuration=self.__config)
driver.close()
driver.switch_to.window(tabs[0])                   
  1. ActionChains模拟Ctrl+S:未弹出保存窗口
ActionChains(driver)\
   .key_down(Keys.CONTROL)\
   .send_keys('s')\
   .key_up(Keys.CONTROL) \
   .perform()
driver.close()
driver.switch_to.window(tabs[0])
  1. PyAutoGUI模拟Ctrl+S:同样未弹出保存窗口
pyautogui.hotkey('ctrl', 's')
pyautogui.write(town + ' ' + month + ' ' + year)
pyautogui.press('enter')
driver.close()
driver.switch_to.window(tabs[0])
  1. Pyperclip复制PDF内容:无法复制到变量
ActionChains(driver)\
   .key_down(Keys.CONTROL)\
   .send_keys('a')\
   .key_up(Keys.CONTROL) \
   .perform()
text1 = ActionChains(driver)\
          .key_down(Keys.CONTROL) \
          .send_keys('c') \
          .key_up(Keys.CONTROL) \
          .perform()
text2 = pyperclip.copy(text1)
pyperclip.waitForPaste()
text2 = pyperclip.paste()
print(text2)
driver.close()
driver.switch_to.window(tabs[0])
  1. ActionChains复制粘贴PDF内容:无法获取内容
ActionChains(driver)\
  .key_down(Keys.CONTROL)\
  .send_keys('a')\
  .key_up(Keys.CONTROL) \
  .perform()
ActionChains(driver)\
  .key_down(Keys.CONTROL) \
  .send_keys('c') \
  .key_up(Keys.CONTROL) \
  .perform()
text = ActionChains(driver)\
         .key_down(Keys.CONTROL)\
         .send_keys('v')\
         .key_up(Keys.CONTROL)\
         .perform()
print(text)
driver.close()
driver.switch_to.window(tabs[0])

解决方案

方法1:配置Chrome自动下载PDF(推荐)

修改Chrome偏好设置,让浏览器直接下载PDF而非打开预览,无需模拟按键即可自动保存到指定目录:

options = Options()
prefs = {
    "savefile.default_directory": 'C:\\Users\\My_Name\\Desktop\\Selenium Temp Folder',
    "plugins.always_open_pdf_externally": True,  # 核心设置:跳过预览,直接下载
    "download.prompt_for_download": False,  # 不弹出下载确认框
    "download.directory_upgrade": True
}
options.add_experimental_option("detach", True)
options.add_experimental_option("prefs", prefs)
driver = webdriver.Chrome(service=Service(ChromeDriverManager().install()), options=options)

下载完成后可通过Python的os模块重命名文件,匹配town+month+year格式:

import os

# 假设网站默认下载的PDF文件名是report.pdf(需根据实际情况调整)
default_path = 'C:\\Users\\My_Name\\Desktop\\Selenium Temp Folder\\report.pdf'
new_path = f'C:\\Users\\My_Name\\Desktop\\Selenium Temp Folder\\{town} {month} {year}.pdf'
os.rename(default_path, new_path)

方法2:直接获取PDF URL用requests下载

切换到PDF窗口后,提取当前URL,用requests库直接下载(需保持会话一致性):

import requests

# 切换到PDF窗口后
pdf_url = driver.current_url
# 传递Selenium的Cookies保持登录态
cookies = {c['name']: c['value'] for c in driver.get_cookies()}
response = requests.get(pdf_url, cookies=cookies)

# 保存到指定路径
save_path = f'C:\\Users\\My_Name\\Desktop\\Selenium Temp Folder\\{town} {month} {year}.pdf'
with open(save_path, 'wb') as f:
    f.write(response.content)

driver.close()
driver.switch_to.window(tabs[0])

方法3:修复模拟Ctrl+S的问题

若坚持用模拟按键,需确保PDF窗口获得焦点并等待加载完成:

import time

# 切换到PDF窗口后
driver.switch_to.window(tabs[1])
driver.maximize_window()
driver.execute_script("window.focus();")  # 强制获取窗口焦点
time.sleep(3)  # 等待PDF完全加载

# ActionChains模拟Ctrl+S
ActionChains(driver).key_down(Keys.CONTROL).send_keys('s').key_up(Keys.CONTROL).perform()
time.sleep(1)  # 等待保存窗口弹出

# PyAutoGUI输入文件名并确认(需确保Chrome窗口在前台)
pyautogui.write(f'{town} {month} {year}')
pyautogui.press('enter')

driver.close()
driver.switch_to.window(tabs[0])

原尝试方法的问题说明

  • pdfkit:需正确配置wkhtmltopdf路径,且无法继承Selenium的登录会话,若PDF需权限访问则会失败。
  • ActionChains/PyAutoGUI:核心问题是PDF窗口未获得焦点、PDF未加载完成,或Chrome预览器拦截了快捷键。
  • 复制PDF内容:网页版PDF的内容并非普通文本,模拟复制无法正确获取完整内容,且易出现乱码。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.27 10:42:55