如何在 Selenium (Python) 中将打开的页面保存为 pdf

Posted

技术标签:

【中文标题】如何在 Selenium (Python) 中将打开的页面保存为 pdf【英文标题】:how to save opened page as pdf in Selenium (Python) 【发布时间】:2019-11-15 17:35:17 【问题描述】:

我已经尝试了所有可以在 Internet 上找到的解决方案,以便能够在 Python 中打印在 Selenium 中打开的页面。但是,当打印弹出窗口出现时,一两秒后它消失了,没有保存任何 PDF。

这是正在尝试的代码。基于这里的代码 - https://***.com/a/43752129/3973491

使用 Mojave 10.14.5 在 Mac 上编码。

from selenium import webdriver
from selenium.webdriver.support.select import Select
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.common.exceptions import NoSuchElementException
from selenium.common.exceptions import TimeoutException
from selenium.webdriver.chrome.options import Options
from selenium.common.exceptions import WebDriverException
import time
import json

options = Options()
appState = 
    "recentDestinations": [
        
            "id": "Save as PDF",
            "origin": "local"
        
    ],
    "selectedDestinationId": "Save as PDF",
    "version": 2


profile = 'printing.print_preview_sticky_settings.appState': json.dumps(appState)
# profile = 'printing.print_preview_sticky_settings.appState':json.dumps(appState),'savefile.default_directory':downloadPath
options.add_experimental_option('prefs', profile)
options.add_argument('--kiosk-printing')
CHROMEDRIVER_PATH = '/usr/local/bin/chromedriver'

driver = webdriver.Chrome(options=options, executable_path=CHROMEDRIVER_PATH)
driver.implicitly_wait(5)
driver.get(url)
driver.execute_script('window.print();')
$chromedriver --v
ChromeDriver 75.0.3770.90 (a6dcaf7e3ec6f70a194cc25e8149475c6590e025-refs/branch-heads/3770@#1003)

关于如何将打开的 html 页面打印为 PDF 的任何提示或解决方案。花了几个小时试图完成这项工作。谢谢!


2019-07-11 更新:

我的问题已被确定为重复,但 a) 另一个问题似乎是使用 javascript 代码,并且 b) 答案并没有解决这个问题中提出的问题 - 这可能与更新的软件有关版本。正在使用的 Chrome 版本是版本 75.0.3770.100 (Official Build) (64-bit),chromedriver 是 ChromeDriver 75.0.3770.90。在 Mac OS Mojave 上。脚本在 Python 3.7.3 上运行。

2019-07-11 更新:

把代码改成

from selenium import webdriver
import json

chrome_options = webdriver.ChromeOptions()
settings = 
    "appState": 
        "recentDestinations": [
            "id": "Save as PDF",
            "origin": "local",
            "account": "",
        ],
        "selectedDestinationId": "Save as PDF",
        "version": 2
    

prefs = 'printing.print_preview_sticky_settings': json.dumps(settings)
chrome_options.add_experimental_option('prefs', prefs)
chrome_options.add_argument('--kiosk-printing')
CHROMEDRIVER_PATH = '/usr/local/bin/chromedriver'
driver = webdriver.Chrome(chrome_options=chrome_options, executable_path=CHROMEDRIVER_PATH)
driver.get("https://google.com")
driver.execute_script('window.print();')
driver.quit()

而现在,什么也没有发生。 Chrome 启动,加载 url,出现打印对话框,但似乎什么都没有发生 - 默认打印机队列中没有任何内容,也没有 pdf - 我什至通过在 Mac 上查找“最近的文件”来搜索 PDF 文件。

【问题讨论】:

没有保存 PDF,你在哪里查的?它应该保存在您的用户下载文件夹中。 @Kamal - 我又试了一次,发现 Chrome 在我的默认打印机上触发了一个实际的打印输出,但我不在同一个位置,所以我没有注意到实际发生了什么。从我尝试打印到 pdf/ 的无数次中删除了打印队列,似乎什么也没发生。所以我怀疑“另存为 PDF”选项没有被选中并且不知道如何选择它。 请参考这个answer。在您的代码中,您调用的是webdriver.Chrome(options=options..,但正确的语法是webdriver.Chrome(chrome_options=options..。不知何故,webdriver.ChromeOptions print 的工作速度比webdriver.chrome.options.Options 快,所以我建议你尝试一下。 Set Selenium ChromeDriver UserPreferences to Save as PDF的可能重复 @GregW.F.R 很高兴它成功了。我已经很久没有使用这个了。但是是的,这就是实例化 chrome 驱动程序实例的方式。 【参考方案1】:

当我的操作系统中没有任何其他打印机设置时,答案 here 有效。但是当我有另一个默认打印机时,这不起作用。

我不明白怎么做,但是以这种方式进行小的更改似乎可行。

from selenium import webdriver
import json

chrome_options = webdriver.ChromeOptions()
settings = 
       "recentDestinations": [
            "id": "Save as PDF",
            "origin": "local",
            "account": "",
        ],
        "selectedDestinationId": "Save as PDF",
        "version": 2
    
prefs = 'printing.print_preview_sticky_settings.appState': json.dumps(settings)
chrome_options.add_experimental_option('prefs', prefs)
chrome_options.add_argument('--kiosk-printing')
CHROMEDRIVER_PATH = '/usr/local/bin/chromedriver'
driver = webdriver.Chrome(chrome_options=chrome_options, executable_path=CHROMEDRIVER_PATH)
driver.get("https://google.com")
driver.execute_script('window.print();')
driver.quit()

【讨论】:

谢谢@Kamal。这种方法确实有效,但它打印到最后使用的打印机。刚刚做了一些搜索,我想知道 cups-pdf 是否作为打印机安装,如果 cups-pdf 是最后使用的打印机,是否会产生预期的结果 - 使用 python 打印到 pdf。 抱歉,我无法在 Linux 上测试我的解决方案,它适用于我的 Windows 10。 知道了。会在这方面做更多的工作,看看我能不能想出点什么。 为我在 Linux 上工作过。不过,如果我们能控制下载位置就好了。 @RobHall 解决方案***.com/a/60548793/1485853【参考方案2】:

您可以使用以下代码在启用背景 css 的情况下打印 A5 大小的 PDF:

import os
from selenium import webdriver
from selenium.webdriver.common.keys import Keys
import json
import time

chrome_options = webdriver.ChromeOptions()

settings = 
    "recentDestinations": [
        "id": "Save as PDF",
        "origin": "local",
        "account": ""
    ],
    "selectedDestinationId": "Save as PDF",
    "version": 2,
    "isHeaderFooterEnabled": False,
    "mediaSize": 
        "height_microns": 210000,
        "name": "ISO_A5",
        "width_microns": 148000,
        "custom_display_name": "A5"
    ,
    "customMargins": ,
    "marginsType": 2,
    "scaling": 175,
    "scalingType": 3,
    "scalingTypePdf": 3,
    "isCssBackgroundEnabled": True


mobile_emulation =  "deviceName": "Nexus 5" 
chrome_options.add_experimental_option("mobileEmulation", mobile_emulation)
chrome_options.add_argument('--enable-print-browser')
#chrome_options.add_argument('--headless')

prefs = 
    'printing.print_preview_sticky_settings.appState': json.dumps(settings),
    'savefile.default_directory': '<path>'

chrome_options.add_argument('--kiosk-printing')
chrome_options.add_experimental_option('prefs', prefs)

for dirpath, dirnames, filenames in os.walk('<source path>'):
    for fileName in filenames:
        print(fileName)
        driver = webdriver.Chrome("./chromedriver", options=chrome_options)
        driver.get(f'file://os.path.join(dirpath, fileName)')
        time.sleep(7)
        driver.execute_script('window.print();')
        driver.close()

【讨论】:

这个解决方案对我很有效。 savefile.default_directory 采用正斜杠和反斜杠路径(在 Windows 10 上)。但是,这对我来说失败的次数比成功的次数要多,因为浏览器在文件完全写入之前就关闭了。这可以通过在driver.close() 之前添加sleep(5) 或更智能的结构来解决。【参考方案3】:

解决方法不是很好,但是可以截图,通过Pillow转换成pdf...

from selenium import webdriver
from io import BytesIO
from PIL import Image

driver = webdriver.Chrome(executable_path='path to your driver')
driver.get('your url here')
img = Image.open(BytesIO(driver.find_element_by_tag_name('body').screenshot_as_png))
img.save('filename.pdf', "PDF", quality=100)

【讨论】:

感谢您的回答。这种方法的问题在于它不适用于多页网页。仅捕获一部分信息。但这对于短页面来说是一个很好的解决方案,并且不需要弹出窗口。 你说的多页网页是什么意思? 表示网页需要滚动才能看到完整的网页,并且当打印为 PDF 时适合 3-4 张纸。 您可以使用此代码:***.com/a/57608276/10661593,最后另存为 pdf。附:有点没看懂,不好意思。您想在打印时将整个页面放在一张纸上吗?或如何 所以我最希望能够做的就是将页面打印为 pdf。在 Mac 上,当您这样做时,生成的 PDF 可能会出现在许多页面中 - 假设 PDF 是为字母或 A4 大小的打印创建的。如果我缩小页面并截取不符合目的的屏幕截图。虽然,现在我知道 Selenium 不控制浏览器的对话框,因此无法将页面打印为 PDF。显然,python 中的 puppeteer 或 pyppeteer 可以做到这一点,但我还不知道如何使用该软件。您分享的链接,似乎在谈论屏幕截图而不是 pdf...【参考方案4】:

这是我在 Windows 中使用的解决方案:

首先在此处下载 ChromeDriver:http://chromedriver.chromium.org/downloads 并安装 Selenium

然后运行此代码(基于接受的答案,稍作修改以在 Windows 上工作):

import json
from selenium import webdriver
chrome_options = webdriver.ChromeOptions()
settings = "recentDestinations": ["id": "Save as PDF", "origin": "local", "account": ""], "selectedDestinationId": "Save as PDF", "version": 2
prefs = 'printing.print_preview_sticky_settings.appState': json.dumps(settings)
chrome_options.add_experimental_option('prefs', prefs)
chrome_options.add_argument('--kiosk-printing')
browser = webdriver.Chrome(r"chromedriver.exe", options=chrome_options)
browser.get("https://google.com/")
browser.execute_script('window.print();')
browser.close()    

【讨论】:

这是一个最小的修订版(“根据 selenium 文档,指定 Windows 驱动程序位置(例如,chromedriver.exe)而不是在 Windows 上运行时的 linux 驱动程序位置”)它应该只是对已接受答案的评论。此外,您似乎只是 minified the accepted answer 使代码看起来不同。 @RobHall 评论有时会在多年后被清除;有时也很难从多个 cmets 中提取信息,因此这个答案。我正确地引用了来源(“基于接受的答案”);魔鬼真的在细节中,我花了很多时间尝试和失败,才最终成功,所以我的目标真的是为 Windows 提供一个现成的代码作为答案。 我尝试搜索保存的文件,但在任何地方都找不到。知道文件保存为 pdf 后的去向。 保存的文件将在下载中,有谁知道我是否可以添加延迟以使网络正常加载或是否可以更改默认下载位置?【参考方案5】:

我建议下载页面源代码 html 可以这样做 在 vb.net 中: Dim Html As String = webdriver.PageSource 不确定它是如何在 python 中完成的,但我确信它非常相似 完成此操作后,您可以使用 html 解析器或使用字符串解析代码手动解析来选择要保存的页面部分。一旦您将要保存的部分的 html 存储在字符串中,然后使用 html 到 pdf 转换器库或程序。对于 C# 和 vb.net 等编程语言,有很多这样的。我对python一无所知,但我相信有些存在。只是做一些研究。 (有些是免费的,有些是昂贵的)

【讨论】:

以上是关于如何在 Selenium (Python) 中将打开的页面保存为 pdf的主要内容,如果未能解决你的问题,请参考以下文章

使用 python + selenium 进行测试时如何包含电子二进制文件

如何使用 Python 和 Selenium 在 Chrome 中打开具有不同 URL 的新标签页? [复制]

在 selenium 中将文本发送到剪贴板

如何在 jmeter 中将其他软件包安装到 jython jar?

selenium+python

在python中将html表转换为csv