ChromeDriver - print-to-pdf после загрузки страницы

Согласно документам, Chrome можно запустить в автономном режиме с помощью --print-to-pdf, чтобы экспортировать веб-страницу в формате PDF. Это хорошо работает для страниц, доступных по запросу GET.

Пытаюсь найти решение для печати в PDF, которое позволило бы мне экспортировать PDF после выполнения нескольких запросов навигации из Chrome. Пример: откройте google.com, введите поисковый запрос, щелкните ссылку первого результата, экспортируйте в PDF.

Глядя на [очень ограниченное количество доступных] документов и примеров, я не смог найти способ указать Chrome экспортировать PDF-файл после загрузки страницы. Я использую Java chrome-driver.

Одним из возможных решений, не связанных с Chrome, является использование такого инструмента, как wkhtmltopdf. Если я пойду по этому пути, то перед отправкой HTML в инструмент мне придется сделать следующее:

  • сохранить HTML в локальном файле
  • перемещаться по DOM и загружать все ссылки на файлы (изображения, js, css и т. д.)

Не предпочитаю этот путь, поскольку для правильного чтения wkhtmltopdf потребуется много усилий [я полагаю] с моей стороны.

Есть ли способ указать Chrome печатать в PDF, но только после загрузки страницы?


person jankovd    schedule 20.11.2017    source источник
comment
Можете ли вы поделиться своими пробными версиями кода?   -  person DebanjanB    schedule 21.11.2017
comment
Нечего делиться, так как мои попытки ни к чему не привели. Но могу объяснить мой процесс. Это включало в себя в основном попытку любых настроек Chrome это имело для меня смысл в то время, чтобы заставить Chrome печатать в PDF после выполнения window.print(). Посмотрел также на переключатели командной строки, но они мне не помогли также.   -  person jankovd    schedule 21.11.2017


Ответы (4)


Поскольку ответов нет, я объясню свой обходной путь. Вместо того, чтобы искать способ запросить у Chrome печать текущей страницы, я пошел другим путем.

В этом примере мы попытаемся загрузить страницу результатов из Google по запросу 'example':

  1. Перейдите с помощью driver.get("google.com"), введите запрос "пример" и нажмите "Поиск в 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

Что произойдет, так это то, что хром запросит 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);
  }
}

person jankovd    schedule 23.01.2018
comment
Есть новости по этому поводу? Кажется странным, что эта команда доступна не для каждой навигации. - person N-ate; 18.07.2018
comment
Я сделал это с помощью сценария оболочки ... загрузите page_source, найдите ссылки на css и изображения, загрузите их в каталог, sed, чтобы указать ссылки на локальные файлы, затем wkhtmltopdf - person J. Win.; 21.08.2018
comment
@ J.Win. пожалуйста, подумайте о том, чтобы поделиться своим сценарием, кто-то из посетителей может найти его полезным. - person jankovd; 23.08.2018
comment
Что, если на сервере есть сомнительный style.css размером примерно 20 ГБ? Ха-ха, ты быстро проиграешь. - person TheRealChx101; 16.09.2020

Это действительно возможно сделать с помощью Selenium Chromedriver с помощью метода ExecuteChromeCommandWithResult. При выполнении команды Page.printToPDF документ PDF в кодировке base-64 возвращается в элементе данных словаря результатов.

В этом ответе доступен пример C #, который должно быть легко перевести на Java:

https://stackoverflow.com/a/58698226/2416627

Вот еще один пример 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);
    }
}

Опции, доступные для вызова Page.printToPDF, описаны здесь:

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

person Otto G    schedule 19.09.2020

Чтобы сделать это из командной строки, нужно немного поработать со страницей html и sed:

LOGIN='myuserid'
PASSW='mypasswd'
AUTH='pin=$LOGIN&accessCode=$PASSW&Submit=Submit'
TIMESTAMP=`TZ=HST date -d "today" +"%m/%d/%y %I:%M %p HST"`
wget -q --save-cookies cookies.txt --keep-session-cookies \
    --post-data $AUTH \
    https://csea.ehawaii.gov/iwa/index.html
sed -i 's#href="/iwa/css#href="./bin#g' index.html
sed -i 's#src="/iwa/images#src="./bin#g' index.html
wkhtmltopdf -q --print-media-type \
            --header-left "$d" --header-font-size 10 \
            --header-line --header-spacing 10 \
            --footer-left "Page [page] of [toPage]" --footer-font-size 10 \
            --footer-line --footer-spacing 10 \
            --footer-right "$TIMESTAMP" \
            --margin-bottom 20 --margin-left 15 \
            --margin-top 20 --margin-right 15 \
            index.html index.pdf

Предполагая, что файлы cookie действительны, доступ к другим страницам, доступным после входа в систему, будет следующим:

wget -q --load-cookies cookies.txt https://csea.ehawaii.gov/otherpage.html
wkhtmltopdf <all the options> otherpage.html otherpage.pdf

Кроме того, я ранее выгружал все CSS и изображения в локальный каталог bin, примерно так:

wget -r -A.jpg -A.gif -A.css -nd -Pbin \
    https://csea.ehawaii.gov/iwa/index.html
person J. Win.    schedule 23.08.2018

Использование ChromiumDriver из выпуска Java Selenium 4.xx, это может быть достигнуто.

String command = "Page.printToPDF";
Map<String, Object> params = new HashMap<>();
params.put("landscape", false);
Map<String, Object> output = driver.executeCdpCommand(command, params);
try {
    FileOutputStream fileOutputStream = new FileOutputStream("export.pdf");
    byte[] byteArray = Base64.getDecoder().decode((String)output.get("data"));
    fileOutputStream.write(byteArray);
} catch (IOException e) {
    e.printStackTrace();
}

Источник: Selenium_CDP

person Smile    schedule 26.10.2020