6

Как сохранить страничку сайта в pdf?

Исходные данные: есть сайт, фронт которого написан на реакте. Нужно сделать для пользователя кнопку, которая бы формировала pdf с текущей страницей и отдавала его пользователю. Почему это просто так не получается:

  1. Была мысль заходить на сайт со стороны бэка, получать html и конвертировать его любым из доступных способов. Не получилось, т.к. сайт на реакте отдаёт не тот html, его сначала нужно рендерить.

  2. Есть способ заходить на сайт браузером google-chrome, который сам умеет формировать pdf, но, вот незадача, для него отданный фронтом html вполне подходящий и он сразу начинает сохранение в пдф, не дожидаясь окончания рендеринга.

  3. Вроде бы есть способы делать это из самого реакта на фронте, но сейчас хочется научиться делать это со стороны бэка.

  4. Попытка задать этот вопрос на хабре привела к надуванию щёк и получению ответа, что всё возможно, но ни один из советов не сработал. Вопрос чатуГПТ тоже привёл к нескольким нерабочим вариантам. Больше знакомых в этой сфере у меня нет. Может, тут кто подскажет?

Лига программистов

2.3K пост12K подписчиков

Правила сообщества

- Будьте взаимовежливы, аргументируйте критику

- Приветствуются любые посты по тематике программирования

- Если ваш пост содержит ссылки на внешние ресурсы - он должен быть самодостаточным. Вариации на тему "далее читайте в моей телеге" будут удаляться из сообщества

0
Автор поста оценил этот комментарий

на php есть либа mpdf, что-то подобное делал, через запрос на сервер и генерацию через этот mpdf.

раскрыть ветку (1)
0
Автор поста оценил этот комментарий

Спасибо, решили, что юзер сам будет цтрл-п жать.

0
146%
Автор поста оценил этот комментарий

Ctrl+P из браузера. Единственный вариант.

Иллюстрация к комментарию
раскрыть ветку (1)
0
Автор поста оценил этот комментарий

Спасибо!

0
146%
Автор поста оценил этот комментарий

потому что у тебя вопросы не программиста, а манагера


для манагера:

в проект положить скачанные файлы

print.min.js

print.min.css


в футере после </body> написать:

<script src="путь/print.min.js"></script>

<link type="text/css" rel="stylesheet" href="путь/print.min.сss">


плиз не спрашивай где взять путь

раскрыть ветку (1)
0
Автор поста оценил этот комментарий

У меня нет возможности модифицировать фронтовый код. Я же до него вообще добраться не могу.

показать ответы
0
DELETED
Автор поста оценил этот комментарий
Возможно не нужно сохранять текущую страницу в пдф, а нужно вывести некоторые данные со страницы. Не могу представить реальной необходимости сохранять именно страницу. Так что скорее нужна нормальная генерация pdf на стороне сервера по тем же данным, которые есть на странице, а не "сохранение страницы".
раскрыть ветку (1)
0
Автор поста оценил этот комментарий

На фронте генерируется очень хитрый отчёт. Была мысль не дублировать его генерацию на сервере, а сохранять сгенерированное фронтом. Но, кажется, это нерешаемо.

0
146%
Автор поста оценил этот комментарий

сорри, я думал ты программист

я не смогу объяснить

раскрыть ветку (1)
0
Автор поста оценил этот комментарий

Я программист. Почему не сможешь объяснить?

показать ответы
0
146%
Автор поста оценил этот комментарий

ну в смысле подключи эту библиотеку каким-нть способом без участия фронтовиков

раскрыть ветку (1)
0
Автор поста оценил этот комментарий

К чему?

показать ответы
0
Автор поста оценил этот комментарий
Ну так поставь селениум для перла, закинь хромдрайвер и вытягивай пдф. Если чет не получается, работай с параметрами запуска вебдрайвера.
раскрыть ветку (1)
0
Автор поста оценил этот комментарий

Да, начал читать, что это такое, раньше никогда не сталкивался.

показать ответы
0
146%
Автор поста оценил этот комментарий

сорри, через реакт

раскрыть ветку (1)
0
Автор поста оценил этот комментарий

Я в этом ничего не понимаю. Что такое - импортируй через реакт?

показать ответы
1
146%
Автор поста оценил этот комментарий

пиздят

импортируй его сам через ноду и вызывай тоже сам после document.ready / window.onload

раскрыть ветку (1)
0
Автор поста оценил этот комментарий

У нас нет ноды.

показать ответы
1
146%
Автор поста оценил этот комментарий

если ссайт на реакте, то при рендеринге происходит множество разной мути, которую ДО рендера (на стороне сервера) ты никогда не предугадаешь


таким образом сперва нужно дать стр отрендериться полностью и только затем что-то с ней делать


это значит что при всем богатстве выбора ты ограничен клиентским жабоскриптом


самое простое и быстрое — после полного рендеринга стр вызвать системный диалог печати и пусть юзерь поставит в нем галочкку типа "печатать в файл PDF". но если хочется поебаться, попробуй начать с этого: https://printjs.crabbly.com/

раскрыть ветку (1)
0
Автор поста оценил этот комментарий

Про printjs мне уже где-то говорили, я его показывал фронтовикам, они ответили, что по каким-то причинам юзать его не могут.

показать ответы
2
Автор поста оценил этот комментарий
На бэке генерировать надёжнее всего. Через эмулятор браузера. На вскидку можешь погуглить селениум, vkhtmltopdf, google web driver.
раскрыть ветку (1)
0
Автор поста оценил этот комментарий

vkhtmltopdf не подходит из-за реакта.

показать ответы
0
Автор поста оценил этот комментарий

У меня в принтерах есть виртуальный принтер, который сохраняет "напечатанное" в ПДФ.

Надо просто нажать CTRL+P и отправить на этот принтер. Вуаля ))

раскрыть ветку (1)
0
Автор поста оценил этот комментарий

Да, спасибо, это один из вариантов. Но интересно, можно ли решить задачу именно нажатием специальной кнопки?

показать ответы
0
Автор поста оценил этот комментарий

Фронт отдает не реактовый код. Фронт исполняет js. Обычно chromium дожидается ивента document.onload и после этого делает сохранение в pdf. В твоем случае похоже что фронт какой-то кривой и уже после отрисовки начинает выполнять какие-то действия. Как самый кривой костыль - можно поиграться с таймаутами, в ином случае лучше смотреть конкретный кейс и решение будет чисто под него. Без конкретных проблем помочь больше ничем никто тебе не сможет

раскрыть ветку (1)
Автор поста оценил этот комментарий

"Фронт отдает не реактовый код." - пустой хтмл с 1-им css и 1-им .js - не реактовый код?

показать ответы
0
Автор поста оценил этот комментарий

Давай скрин или какие-то наводки. Попробую помочь, но я не ванга)

раскрыть ветку (1)
Автор поста оценил этот комментарий

Скрин дать не могу, это корпоративная инфа. А все наводки написаны выше: хром идёт на страницу, фронт отдаёт реактовый код. В нормальном варианте хром его рендерит и показывает пользователю. В случае команды на сохранение в пдф, он отдаёт сохранялке то, что готово на текущий момент, не дожидаясь полного рендеринга. В моём случае успевает показаться заголовок и сообщение юзеру, что страница отрисовывается.

показать ответы
1
Автор поста оценил этот комментарий
Сколько он у вас стартовать будет. А туда просто по сети http запрос сделал, pdf как ответ получил
раскрыть ветку (1)
Автор поста оценил этот комментарий

Быстро. Это будет редкая операция.

0
Автор поста оценил этот комментарий

что именно не пашет?

раскрыть ветку (1)
Автор поста оценил этот комментарий

Вот конкретно эта команда сохраняет не готовую страницу, а ту, которую отдаёт реакт.

показать ответы
0
Автор поста оценил этот комментарий
Подними контейнер с headless-chrome
раскрыть ветку (1)
Автор поста оценил этот комментарий

Хром можно просто процессом запустить, зачем для этого контейнер?

показать ответы
2
Автор поста оценил этот комментарий

chromium --headless --disable-gpu --print-to-pdf http://your_page
все пашет из коробки

раскрыть ветку (1)
Автор поста оценил этот комментарий

Нет.

показать ответы
0
Автор поста оценил этот комментарий

Если задача именно в формировании pdf текущей страницы, которую видит пользователь то есть варианты:
1. Ctrl+P с печатью в PDF - делать вообще ничего не требуется, на кнопке достаточно вызвать https://developer.mozilla.org/ru/docs/Web/API/Window/print и диалог сам откроется, а вот выбирать печать в pdf придется вручную.


2. Так как страница уже открыта и все нужное отображается, то по кнопке можно получить текущее состояние через document.documentElement.innerHTML (react и вся прочая по любому формируют html, который можно вытащить таким образом) после чего полученный html можно отправить post запросом на бэк и там его сконвертить в pdf. Тут есть засада со стилями/картинками - нужно в html указать абсолютные пути к ресурсам, а теги script убрать, но это меньшая из проблем.

Когда разбирался с вопросом конвертации html -> pdf на бэке оказалось, что практически все множество способов/доступных либ сводится к использованию headless chromium/chrome и любого другого браузера через специальное api ChromeDevTools или другого браузера с соответствующим api.

В итоге на сервере поднят экземпляр headless chromium/chrome, который обернут микросервисом генерации pdf по полученному html:
1. Подключается к экземпляру по ChromeDevTools api
2. "Открывает" новую вкладку
3. Передает туда html  через SetDocumentContentCommand

4. Браузер загружает все ресурсы и готовит документ к отображению
5. Посылается команда PrintToPDFCommand с  нужными параметрами (можно даже задать содержимое header/footer)
6. В ответ приходит массив байт - готовый pdf

7. "Закрываем" вкладку

8. Делаем с pdf все что нужно.

раскрыть ветку (1)
Автор поста оценил этот комментарий
1. Подключается к экземпляру по ChromeDevTools api
2. "Открывает" новую вкладку
3. Передает туда html через SetDocumentContentCommand
Кто подключается/передаёт?
показать ответы
0
Автор поста оценил этот комментарий
react-pdf... Не?
раскрыть ветку (1)
Автор поста оценил этот комментарий

Как я понимаю, это должно делаться где-то на стороне фронта? Просто я про реакт знаю только название, ну и вот в процессе решения задачи узнал, что он отдаёт не совсем обычный html :) Я тут бэкэндщик, на пёрле пишу.

0
Автор поста оценил этот комментарий

Через хромиум у меня отлично работает. Смотри - ты что то делаешь не так, мб выключил исполнение js

раскрыть ветку (1)
Автор поста оценил этот комментарий

Рад, что у тебя работает. А что именно работает? Как можно выключить исполнение js?

показать ответы
1
Автор поста оценил этот комментарий

Если уж на Хабре обосрались, здесь точно будет хуже.

раскрыть ветку (1)
Автор поста оценил этот комментарий

Не факт.

Автор поста оценил этот комментарий

добавлю, раз уж Perl:
https://metacpan.org/pod/Selenium::Remote::Driver

раскрыть ветку (1)
Автор поста оценил этот комментарий

Спасибо, пошёл гуглить, что такое селениум.

0
Автор поста оценил этот комментарий

Ну это же элементарно. Нужно сделать функцию на js с задержкой, которая срабатывает при открытии сайта с нужным параметром, задержка эта позволяет закончиться рендерингу, а потом идет сохранение в PDF. Ну а далее так как написано в пункте 2.

раскрыть ветку (1)
Автор поста оценил этот комментарий

А можете подробнее объяснить? Где эта функция должна быть?

0
Автор поста оценил этот комментарий

А в чем проблема по соседству поднять? Если уж хочется все в монолите, то я думаю и на перле нет проблем поднять chromium и отрендерить в нем pdf. По факту можно все на shell script сделать.


https://wkhtmltopdf.org


Вам на беке нужно рендер делать или на фронте?

раскрыть ветку (1)
Автор поста оценил этот комментарий

Поднимать лишние сервисы не очень желательно. Рендерить через chromium не работает, т.к. реакт. Решение по ссылке не работает вообще. Лично мне лучше на бэке, у меня только к нему доступ есть.

показать ответы
0
Автор поста оценил этот комментарий

пример на ноде, должно сработать:


const puppeteer = require('puppeteer');(async() => { const browser = await puppeteer.launch() ; const page = await browser.newPage(); await page.goto('https://www.gq.com/story/tokelau-teenagers-lost-ocean?printable=true') ; //await page.emulateMedia('screen') ; await page.pdf({ path: "story.pdf", printBackground: true });await browser.close() ;})();
раскрыть ветку (1)
Автор поста оценил этот комментарий

Есть проблема, что поднимать сервисы на ноде затруднительно, у нас бэк на пёрле.

показать ответы

Темы

Политика

Теги

Популярные авторы

Сообщества

18+

Теги

Популярные авторы

Сообщества

Игры

Теги

Популярные авторы

Сообщества

Юмор

Теги

Популярные авторы

Сообщества

Отношения

Теги

Популярные авторы

Сообщества

Здоровье

Теги

Популярные авторы

Сообщества

Путешествия

Теги

Популярные авторы

Сообщества

Спорт

Теги

Популярные авторы

Сообщества

Хобби

Теги

Популярные авторы

Сообщества

Сервис

Теги

Популярные авторы

Сообщества

Природа

Теги

Популярные авторы

Сообщества

Бизнес

Теги

Популярные авторы

Сообщества

Транспорт

Теги

Популярные авторы

Сообщества

Общение

Теги

Популярные авторы

Сообщества

Юриспруденция

Теги

Популярные авторы

Сообщества

Наука

Теги

Популярные авторы

Сообщества

IT

Теги

Популярные авторы

Сообщества

Животные

Теги

Популярные авторы

Сообщества

Кино и сериалы

Теги

Популярные авторы

Сообщества

Экономика

Теги

Популярные авторы

Сообщества

Кулинария

Теги

Популярные авторы

Сообщества

История

Теги

Популярные авторы

Сообщества