命令行 --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 团队的一部分人完全反对仅仅存在这个命令行选项,而是认为最好强迫每个人使用它来获得一个 node.js 构建与 Puppeteer 一起使用并彻底删除标志。
Windows 命令行的限制
以这种方式调用 chrome 可以正常工作,例如在带有 Visual Studio 的 IIS Express 上的本地开发环境中,但它会在运行 IIS 的服务器上失败,即使在无头模式下,因为没有为 IIS 用户提供交互式/桌面权限,而 chrome 获取此 PDF 的方式实际上需要交互/桌面权限。提供这些权限的方法很复杂,但是您在任何地方阅读到如何以不提供交互式/桌面权限开头。此外,Chrome 有朝一日摆脱命令行的上述风险使得工作变得更加困难以使其工作成为一个不确定的提议。
chrome 命令行的替代方案
wkhtmltopdf
在幕后,Chrome 只使用了wkhtmltopdf。我还没有尝试过,但这很可能会完成工作。一个小风险是,在 Chrome 中生成 PDF 时,测试很明显:在 Chrome 中查看页面。如果您感到紧张,请打开打印预览。在 wkhtmltopdf 中,它实际上是 Chromium 的不同版本,这可能会产生渲染差异。也许吧。
硒
另一种选择是领先于希望摆脱 --print-to-pdf 并按照他们的喜好使用浏览器开发 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://stackoverflow.com/a/24192518/176877
理想情况下,这将是异步的,因为对 Selenium 的所有调用实际上都是网络命令,并且写入该文件可能会占用大量磁盘 IO。从 Chrome 返回的数据实际上也是一个 Stream。然而,不幸的是,Selenium 的传统使用库根本不使用异步,因此需要升级该库或为 .Net 确定一个可靠的异步 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 年前就放弃了。