无头浏览器Chrome如何打印PDF

15

我正在尝试使用 Chrome 的无头功能将 HTML 转换为 PDF。然而,我根本没有得到输出。控制台也没有显示任何错误。我在我的 Windows 机器上运行以下命令:

chrome --headless --disable-gpu --print-to-pdf

我已经尝试了所有不同的选项,但是没有生成任何内容。我使用的是 Chrome 版本 60。

8个回答

19

命令行 --print-to-pdf

默认情况下,--print-to-pdf 尝试在用户目录中创建 PDF。默认情况下,该用户目录是实际 Chrome 二进制文件存储的位置,即您正在运行的特定版本文件夹 - 例如,“C:\Program Files (x86)\Google\Chrome\Application\61.0.3163.100”。而且,默认情况下... Chrome 不允许写入此文件夹。您可以通过将 --enable-logging 添加到您的命令中来观察它尝试并失败。

所以不幸的是,默认情况下,此命令会失败。*

您可以通过在参数中提供 Chrome 可以写入的路径来解决此问题,例如:

--print-to-pdf="C:\Users\Jane\test.pdf"

或者,您可以更改用户目录:
--user-data-dir="C:\Users\Jane"

如果您希望PDF自动从网页接收名称,则更改用户目录的一个原因是:Chrome查看标题标记,然后将其转储为<title>My Page</title> => My-Page.pdf

*我认为这种默认行为非常令人困惑,并应该作为Chrome的错误进行报告。然而,显然Chrome团队的一部分坚决反对这个命令行选项的存在,而是认为强制每个使用它的人都要使用Puppeteer和完全删除该标志的node.js构建。

Windows命令行的限制

以这种方式调用Chrome在本地开发环境中(例如使用Visual Studio的IIS Express)可以正常工作,但是在运行IIS的服务器上,即使在无头模式下也会失败,因为IIS用户没有交互/桌面权限,而Chrome获取此PDF的方式实际上需要交互/桌面权限。有提供这些权限的复杂方法,但是任何您阅读的地方都以不要提供交互/桌面权限开始。此外,Chrome有一天取消命令行的风险,使得让它工作变得更加困难。

Chrome命令行的替代方案

wkhtmltopdf

从源代码来看,Chrome团队要么使用了wkhtmltopdf,要么基于它进行了工作。我没有尝试过,但很可能这个工具可以完成任务。唯一的小风险是,在Chrome中生成PDF时,测试是显而易见的:在Chrome中查看页面。如果你感到紧张,打开打印预览。在wkhtmltopdf中,实际上是一个不同版本的Chromium,这可能会产生渲染差异。也许。正如社区用户指出的那样,wkhtmltopdf已经被所有者存档于2023年1月2日。

Selenium

另一个选择是超前于寻找摆脱--print-to-pdf的人群,并使用浏览器dev API(通过Selenium)作为他们的首选。**

private static void pdfSeleniumImpl(string url, string pdfPath)
{
    var options = new OpenQA.Selenium.Chrome.ChromeOptions();
    options.AddArgument("headless");

    using (var chrome = new OpenQA.Selenium.Chrome.ChromeDriver(options))
    {
        chrome.Url = url;

        var printToPdfOpts = new Dictionary<string, object>();
        var resultDict = (Dictionary<string, object>)
            chrome.ExecuteChromeCommandWithResult(
                "Page.printToPDF", printToPdfOpts);
        dynamic result = new DDict(resultDict);
        string data = result.data;
        var pdfFile = Convert.FromBase64String(data);
        System.IO.File.WriteAllBytes(pdfPath, pdfFile);
    }
}

上面的DDict是我之前回答中提到的GracefulDynamicDictionary。

https://www.nuget.org/packages/GracefulDynamicDictionary/

https://github.com/b9chris/GracefulDynamicDictionary

https://dev59.com/ZnE85IYBdhLWcg3wUBsZ#24192518

理想情况下,这应该是异步的,因为所有对Selenium的调用实际上都是网络命令,并且编写该文件可能需要大量的磁盘IO。从Chrome返回的数据实际上也是一个流。然而,不幸的是,Selenium通常使用的库根本不使用异步,因此需要升级该库或识别一个可靠的.Net异步Selenium库才能真正做到这一点。
任何在服务器上使用Chrome的方法(包括Selenium)都将不得不处理Chrome自动更新以及Selenium驱动程序作为构建的一部分需要更新的问题。没有策略来应对这种情况的很少更新的代码将每三个月就会出现故障。

https://github.com/puppeteer/puppeteer/blob/master/lib/Page.js#L1007

https://chromedevtools.github.io/devtools-protocol/tot/Page/#method-printToPDF

**Page.pdf Chrome Dev API 命令已经过时,所以如果这个派别获得成功,那么命令行和 Dev API 都将无法使用。话虽如此,看起来那些试图破坏它的游说者在 2 年前就已经放弃了。


不明白为什么当前目录中的文件需要完整路径 - 例如:C:\Users\User\Documents\XstReader>"C:\Program Files (x86)\Google\Chrome\Application\chrome" --headless --disable-gpu --print-to-pdf=C:\Users\User\Documents\XstReader\DemoEmail.pdf --no-margins "C:\Users\User\Documents\XstReader\Demo Email.html" - flywire
因为Chrome忽略当前目录,而是使用用户数据目录。 - Chris Moschini
这是一个很棒的答案,应该至少获得100个投票。特别是Selenium函数。非常感谢@ChrisMoschini。 - Jeanno
4
幕后,Chrome 只是简单地使用 wkhtmltopdf。 - 需要引用来源。 - Bergi
1
非常感谢您提供的Selenium提示!请注意,“headless”选项非常重要,否则默认情况下Chrome将禁用必要的扩展程序,导致“PrintToPDF未实现”的错误。(或者,它可能可以在非headless模式下明确启用,但我没有尝试过。) - Otto G
@Bergi 当我很久以前深入研究这个问题时,wkhtmltopdf被引用在代码的注释中。但是,我已经4年没有看过这段代码了 - PDF生成器在此期间一直按预期工作。 - Chris Moschini

8

这是有效的:

chrome --headless --disable-gpu --print-to-pdf=file1.pdf https://www.google.co.in/

在文件夹中创建文件:C:\Program Files (x86)\Google\Chrome\Application\61.0.3163.100


2

在Suraj提供的简单答案基础上,我创建了一个小函数,它在我的源路径中工作,因此就像CLI工具一样:

function webtopdf(){
    chromium-browser --headless --disable-gpu --print-to-pdf=$2 $1
}

所以快速

webtopdf https://goo.com/some-article some-article.pdf

目前这个工具对我足够有用。

2

我在print-to-pdf命令后漏写了"="。

正确的命令为:

chrome --headless --disable-gpu --print-to-pdf="C:/temp/name.pdf" https://www.google.com/

现在它正在工作。

1
Don't use answers as comments - N-ate
1
这是正确的答案,它需要在打印到PDF时包含文件的完整路径,否则在2019年5月27日之后的Windows上无法正常工作。 - Max
当您指定完整路径时,它会失败。仅指定文件名可以正常工作。要达到指定完整路径的效果,您需要拆分路径并将工作目录设置为目标路径。 - TheRealChx101

2

这在Windows系统中适用:

启动chrome --headless --disable-gpu --print-to-pdf=C:\Users\username\pdfs\chrome.pdf --no-margins https://www.google.com


2
你可以在Powershell(以及GitBash中)使用--print-to-pdf="$(pwd)\output.pdf"将内容打印到当前文件夹中。对我来说,--no-margins没有效果。 - Kpym

1

不要忘记用管理员权限打开您的终端/cmd :) 否则它根本就不会保存文件。


1
只需从不需要管理员权限的目录中工作(例如,Chrome安装目录可能受到限制)。 - Paul Verest

0

对于Windows用户(以及其他使用MSEdge的用户),MSEdge提供了类似的功能--headless。此外,版本III+还具有“使用Acrobat”渲染。

注意:Google Chromium将headless更新为--headless=new和--headless=old,使用不同的--switches!! =new --no-pdf-header-footer=old --print-to-pdf-no-header

注意:截至版本112,Edge仍然不支持headless=new。
可以在https://peter.sh/experiments/chromium-command-line-switches/找到更新的--switches。

目前,MSEdge使用--headless命令就像--headless=old一样,因此仍然使用旧的-header语法,--headless --print-to-pdf-no-header也不会写入页脚。

无需设置配置文件,但您可以通过以下方式进行设置

"C:\Program Files (x86)\Microsoft\Edge\Application\msedge.exe" --profile-directory=c:\whateverUneed --headless blah blah

不应该需要使用任何GPU修复补丁,因为这些问题在5年前就已经得到解决了。

因此,正常的日常命令可以是CWD为当前工作目录的任何路径。

"C:\Program Files (x86)\Microsoft\Edge\Application\msedge.exe" --headless=old  --print-to-pdf-no-header --print-to-pdf="c:\CWD\google.pdf" "https://google.com"

enter image description here


-3

目前,此功能仅适用于Linux和Mac OS。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接