使用selenium chrome驱动程序生成PDF

ipakzgxi  于 2023-04-03  发布在  Go
关注(0)|答案(4)|浏览(587)

要从HTML文件生成PDF,我想使用selenium Chrome驱动程序。
我试着用命令行:

chrome.exe --headless --disable-gpu --print-to-pdf   file:///C:invoiceTemplate2.html

它工作得很好,所以我想用JAVA来做,这是我的代码:

System.setProperty("webdriver.chrome.driver", "C:/work/chromedriver.exe");
ChromeOptions options = new ChromeOptions();
options.addArguments("--headless", "--disable-gpu", "--print-to-pdf",
            "file:///C:/invoiceTemplate2.html");
WebDriver driver = new ChromeDriver(options);
driver.quit();

服务器启动没有问题,但是chrome打开时有多个选项卡,参数是我在Options中指定的。
有什么办法吗?thx

zf9nrax1

zf9nrax11#

这确实可以通过Selenium和ChromeDriver来完成(在Chrome 85版上测试过),但是在从webdriver启动Chrome时使用“print-to-pdf”选项并不是解决方案。
要做的事情是使用ChromeDriver的命令执行功能:
https://www.selenium.dev/selenium/docs/api/java/org/openqa/selenium/remote/RemoteWebDriver.html#execute-java.lang.String-java.util.Map-
有一个名为Page.printToPDF的命令提供了PDF输出功能。返回一个包含项目“data”的字典,并以base-64编码格式生成PDF。
不幸的是,我没有完整的Java示例,但在这个答案中,有一个C#示例(与Java相比,C#中的Selenium方法命名不同,但原理应该是相同的):
https://stackoverflow.com/a/63970792/2416627
Chrome中的Page.printToPDF命令记录如下:
https://chromedevtools.github.io/devtools-protocol/tot/Page/#method-printToPDF

p3rjfoxz

p3rjfoxz2#

**更新31-03-2023:**在chrome的最后一次更新中,添加了一些额外的安全措施,下面的解决方案停止工作,因为WebSocket连接无法建立。为了解决这个问题,我们在ChromeDriver中添加了一个新参数:

options.addArgument("--remote-allow-origins=*");

**更新31-05-2021:**我们注意到原来的解决方案并不总是正常工作,我们选择了Selenium + ChromeDriver:

public void generatePdf(Path inputPath, Path outputPath) throws Exception
{
    try
    {

        ChromeOptions options = new ChromeOptions();
        options.addArguments("--headless", "--disable-gpu", "--run-all-compositor-stages-before-draw");
        ChromeDriver chromeDriver = new ChromeDriver(options);
        chromeDriver.get(inputPath.toString());
        Map<String, Object> params = new HashMap();
        
        String command = "Page.printToPDF";
        Map<String, Object> output = chromeDriver.executeCdpCommand(command, params);

        try
        {
            FileOutputStream fileOutputStream = new FileOutputStream(outputPath.toString());
            byte[] byteArray = java.util.Base64.getDecoder().decode((String) output.get("data"));
            fileOutputStream.write(byteArray);
            fileOutputStream.close();
        }
        catch (IOException e)
        {
            e.printStackTrace();
        }
    }
    catch (Exception e)
    {
        e.printStackTrace(System.err);
        throw e;
    }
}

如果经常调用,我建议重用驱动程序对象,因为初始化需要一段时间。
请记住关闭或退出驱动程序,以避免留下僵尸 chrome 进程,并记住在您的机器中安装ChromeDriver。

原始溶液:

由于无法使用ChromeDriver获得所需的结果,我的解决方法是在Java程序的命令行中调用无头chrome。
这在Windows上是有效的,但是仅仅改变命令变量中使用的路径的内容就应该使它在Linux中也有效。

public void generatePdf(Path inputPath, Path outputPath) throws Exception {

    try {
            
        String chromePath = "C:/Program Files (x86)/Google/Chrome/Application/chrome.exe";
        String command = chromePath + " --headless --disable-gpu --run-all-compositor-stages-before-draw --print-to-pdf=" + outputPath.toString() + " " + inputPath.toString();
                
        // Runs "chrome" Windows command
        Process process = Runtime.getRuntime().exec(command);
        process.waitFor(); // Waits for the command's execution to finish 
            
    }catch (Exception e){
        
        e.printStackTrace(System.err);
        throw e;

    }finally{
        
        // Deletes files on exit
        input.toFile().deleteOnExit();
        output.toFile().deleteOnExit();

    }
}

注意:输入和输出路径都是用NIO创建的临时文件。

yc0p9oo0

yc0p9oo03#

代码将帮助您在Selenium c#上以PDF保存页面

using OpenQA.Selenium;
using OpenQA.Selenium.Chrome;

    protected void PDFconversion(ChromeDriver driver, string root, string rootTemp)
    {
        //Grid.Rows.Add(TxtBxName.Text, TxtBxAddress.Text);
        try
        {
            IJavaScriptExecutor js = (IJavaScriptExecutor)driver;
            Thread.Sleep(500);
            js.ExecuteScript("setTimeout(function() { window.print(); }, 0);");
            Thread.Sleep(500);
            driver.SwitchTo().Window(driver.WindowHandles.Last());
            Thread.Sleep(500);
            string JSPath = "document.querySelector('body>print-preview-app').shadowRoot.querySelector('#sidebar').shadowRoot.querySelector('#destinationSettings').shadowRoot.querySelector('#destinationSelect').shadowRoot.querySelector('print-preview-settings-section:nth-child(9)>div>select>option:nth-child(3)')";
            Thread.Sleep(500);
            IWebElement PrintBtn = (IWebElement)js.ExecuteScript($"return {JSPath}");
            Thread.Sleep(500);
            PrintBtn.Click();
            string JSPath1 = "document.querySelector('body>print-preview-app').shadowRoot.querySelector('#sidebar').shadowRoot.querySelector('print-preview-button-strip').shadowRoot.querySelector('cr-button.action-button')";
            Thread.Sleep(1000);
            IWebElement PrintBtn1 = (IWebElement)js.ExecuteScript($"return {JSPath1}");
            PrintBtn1.Click();
            Thread.Sleep(1000);
            SendKeys.Send("{HOME}");
            SendKeys.Send(rootTemp + "\\" + "result.pdf"); // Path
            SendKeys.Send("{TAB}");
            SendKeys.Send("{TAB}");
            SendKeys.Send("{TAB}");
            SendKeys.Send("{ENTER}");
            Thread.Sleep(1000);
       
        }
        catch (Exception ex){}
    }
vhipe2zx

vhipe2zx4#

你必须做两件事。
第一步:用selenium截图。
第二:使用任何pdf工具转换屏幕截图,如itext。这里我展示了一个完整的例子。
步骤1:从here下载itext的jar文件,并将其添加到构建路径中。
步骤2:将此代码添加到项目中。

ChromeOptions options = new ChromeOptions();
options.addArguments("disable-infobars");
options.addArguments("--print-to-pdf");

WebDriver driver = new ChromeDriver(options);
driver.get("file:///C:/invoiceTemplate2.html");

try {
    File screenshot = ((TakesScreenshot)driver).getScreenshotAs(OutputType.FILE);
    FileUtils.copyFile(screenshot, new File("screenshot.png"));
    Document document = new Document(PageSize.A4, 20, 20, 20, 20);
    PdfWriter.getInstance(document, new FileOutputStream("webaspdf.pdf"));
    document.open();
    Image image = Image.getInstance("screenshot.png");
    document.add(image);
    document.close();
}
catch (Exception e2) {
    // TODO Auto-generated catch block
    e2.printStackTrace();
}

注意:要使用前面提到的itext包,请将所需的导入添加到代码中。

import com.itextpdf.text.Document;
import com.itextpdf.text.Image;
import com.itextpdf.text.PageSize;
import com.itextpdf.text.pdf.PdfWriter;
import org.apache.commons.io.FileUtils;
import org.openqa.selenium.OutputType;
import org.openqa.selenium.TakesScreenshot;

相关问题