ChromeDriver - 页面加载后打印到pdf文件

jan*_*ovd 10 selenium-chromedriver selenium-webdriver google-chrome-headless

根据文档,Chrome可以在无头模式下启动--print-to-pdf,以便导出网页的PDF.这适用于可通过GET请求访问的页面.

试图找到一个print-to-pdf解决方案,允许我在Chrome中执行多个导航请求后导出PDF.示例:打开google.com,输入搜索查询,单击第一个结果链接,导出为PDF.

查看[非常有限的可用]文档和示例,我在页面加载后找不到指示Chrome导出PDF的方法.我正在使用Java chrome-driver.

一种不涉及Chrome的可能解决方案是使用像wkhtmltopdf这样的工具.继续这条路径将迫使我 - 在将HTML发送到工具之前 - 执行以下操作:

  • 将HTML保存在本地文件中
  • 遍历DOM,并下载所有文件链接(图像,js,css等)

不喜欢这条路径,因为我需要进行大量的修改[我假设]以使下载文件路径正确以便wkhtmltopdf正确读取.

有没有办法指示Chrome打印到PDF,但只能在页面加载后?

Ott*_*o G 9

这确实可以通过 Selenium Chromedriver 的方法来完成ExecuteChromeCommandWithResult。执行命令时Page.printToPDF,结果字典的“data”项中返回一个base-64编码的PDF文档。

AC# 示例应该很容易翻译成 Java,可以在这个答案中找到:

/sf/answers/4108875851/

这是另一个 C# 示例,其中说明了一些有用的选项:

public static void Main(string[] args)
{
    var driverOptions = new ChromeOptions();
    // In headless mode, PDF writing is enabled by default (tested with driver major version 85)
    driverOptions.AddArgument("headless");
    using (var driver = new ChromeDriver(driverOptions))
    {
        driver.Navigate().GoToUrl("https://stackoverflow.com/questions");
        new WebDriverWait(driver, TimeSpan.FromSeconds(10)).Until(d => d.FindElements(By.CssSelector("#questions")).Count == 1);
        // Output a PDF of the first page in A4 size at 90% scale
        var printOptions = new Dictionary<string, object>
        {
            { "paperWidth", 210 / 25.4 },
            { "paperHeight", 297 / 25.4 },
            { "scale", 0.9 },
            { "pageRanges", "1" }
        };
        var printOutput = driver.ExecuteChromeCommandWithResult("Page.printToPDF", printOptions) as Dictionary<string, object>;
        var pdf = Convert.FromBase64String(printOutput["data"] as string);
        File.WriteAllBytes("stackoverflow-page-1.pdf", pdf);
    }
}
Run Code Online (Sandbox Code Playgroud)

Page.printToPDF此处记录了可用于调用的选项:

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


jan*_*ovd 4

由于没有答案,我将解释我的解决方法。我没有尝试找到如何从 Chrome 请求打印当前页面,而是走了另一条路。

对于此示例,我们将尝试从 Google 下载查询“example”的结果页面:

  1. 使用 导航driver.get("google.com"),输入查询“example”,点击“Google 搜索”
  2. 等待结果页面加载
  3. 检索页面源driver.getPageSource()
  4. 使用 Jsoup 等解析源,以便重新映射所有相关链接以指向为此目的定义的端点(如下所述) - 例如到localhost:8080. 链接“./style.css”将变为“localhost:8080/style.css”
  5. 将 HTML 保存到文件,例如命名为“query-example”
  6. 跑步chrome --print-to-pdf localhost:8080/search?id=query-example

将会发生的情况是,chrome 将从我们的控制器请求 HTML,对于我们返回的 HTML 中定义的资源,它将转到我们的控制器 - 因为我们重新映射了相关链接 - 反过来,控制器会将该请求转发到该请求的真实位置资源 - google.com。下面是一个 Spring 控制器示例,请注意,该示例不完整,仅作为指导。

@RestController
@RequestMapping
public class InternationalOffloadRestController {
  @RequestMapping(method = RequestMethod.GET, value = "/search/html")
  public String getHtml(@RequestParam("id") String id) {
    File file = new File("location of the HTML file", id);
    try (FileInputStream input = new FileInputStream(file)) {
      return IOUtils.toString(input, HTML_ENCODING);
    }
  }
  @RequestMapping("/**") // forward all remapped links to google.com
  public void forward(HttpServletResponse httpServletResponse, ...) {
    URI uri = new URI("https", null, "google.com", -1, 
      request.getRequestURI(), request.getQueryString(), null);
    httpServletResponse.setHeader("Location", uri.toString());
    httpServletResponse.setStatus(HttpServletResponse.SC_MOVED_PERMANENTLY);
  }
}
Run Code Online (Sandbox Code Playgroud)