Noções básicas sobre o Google Chrome Converter recursos HTML para PDF


Recentemente, em uma startup, resolvi o problema de gerar tickets em formato PDF. Naquela época, um site com uma pilha estabelecida de tecnologias já estava pronto, então eu estava procurando uma abordagem que não exigisse o uso de ferramentas adicionais. No final, propus criar primeiro tickets no formato HTML e depois converter em PDF usando o navegador Chrome. Como se viu, dessa forma, você pode gerar não apenas tickets ricamente decorados com CSS, mas também uma variedade de relatórios com gráficos em JavaScript. Neste artigo, falarei sobre como iniciar o Chrome para esses fins, darei algumas dicas para personalizar o CSS e também discutirei as desvantagens dessa solução.


Opções alternativas não serão discutidas aqui, porque já foram escritas o suficiente sobre elas, são fáceis de encontrar e são ferramentas prontas, informações sobre as quais é melhor procurar nas fontes principais - na documentação em sites oficiais. O método proposto não é uma ferramenta independente e é mais um subproduto do desenvolvimento de várias tecnologias. No segmento da Internet em língua russa, há poucas informações coletadas, então decidi preencher a lacuna.


Por que essa opção é escolhida?


A maior vantagem é que o Chrome não precisa expandir a pilha de tecnologias para gerar PDF pelo navegador Chrome. Os desenvolvedores de front-end criam HTML com ferramentas de desenvolvimento conhecidas e veem imediatamente os resultados intermediários do trabalho no navegador. Ao mesmo tempo, o Chrome provavelmente está rodando nos testes e transferi-lo para o back-end não é difícil. Também deve ser observado que o codificador é capaz de acessar todo o arsenal de propriedades do CSS, incluindo Flexbox e Grid.
Vou falar sobre as deficiências e maneiras de contorná-las durante o curso do artigo.


Resolvemos o problema em uma linha


Na linha de comando, chamamos o Chrome no modo decapitado, salvando a página em pdf:


chrome --headless --disable-gpu --print-to-pdf https://google.com 

Os usuários do Linux podem precisar executar chromium-browser vez do chrome .
Os usuários de MAC podem achar útil pré-criar o alias:


 alias chrome="/Applications/Google\\ \\Chrome.app/Contents/MacOS/Google\\ \\Chrome" 

ATUALIZAÇÃO: Os comentários esclareceram que os usuários do Windows precisam definir explicitamente o nome do arquivo PDF --print-to-pdf=output.pdf


Se você já possui um gerador de documentos HTML, em vez de https://google.com especifique o URL para receber este documento.


Abra o arquivo output.pdf no diretório local e observe o resultado.
A primeira coisa que chama sua atenção é a presença de um cabeçalho com uma data de impressão e um rodapé com um URL e paginação. Para removê-los, você precisa adicionar algumas regras CSS. É improvável que essas regras sejam adicionadas ao google.com , portanto, para mais trabalhos, é melhor criar seu próprio documento HTML.


Adicionar CSS


O CSS possui uma consulta de mídia especial @page , que é usada para impressão; definiremos o recuo para que o Cabeçalho e o Rodapé simplesmente não se ajustem:


 @page { size: A4; margin: 0mm; } 

Esse método funcionará apenas para documentos de página única. Ao imprimir duas ou mais páginas, o Rodapé com o URL e a numeração de páginas permanecerão na parte inferior inferior. Você pode pedir explicitamente ao Chrome para desativar a exibição de Cabeçalho e Rodapé, definindo o parâmetro de impressão displayHeaderFooter = False , mas no momento ele não é movido para a interface da linha de comandos. Para isso, você precisará de ferramentas para automatizar o trabalho com o navegador: Selenium ou titereiro. A seguir, considerarei a primeira opção, porque meu projeto usou Python.


Inicie o Chrome via Selenium


Portanto, instale o Selenium com o comando pip install selenium , faça o download do driver chrome que corresponde à sua versão do Chrome em http://chromedriver.chromium.org/ e use a função get_pdf_from_html do exemplo abaixo:


 import sys from selenium import webdriver from selenium.webdriver.chrome.options import Options import json, base64 def get_pdf_from_html(path, chromedriver='./chromedriver', print_options = {}): #  Chrome webdriver_options = Options() webdriver_options.add_argument('--headless') webdriver_options.add_argument('--disable-gpu') driver = webdriver.Chrome(chromedriver, options=webdriver_options) #   url driver.get(path) #    calculated_print_options = { 'landscape': False, 'displayHeaderFooter': False, 'printBackground': True, 'preferCSSPageSize': True, } calculated_print_options.update(print_options) #    pdf  result = send_devtools(driver, "Page.printToPDF", calculated_print_options) driver.quit() #    base64 -  return base64.b64decode(result['data']) def send_devtools(driver, cmd, params={}): resource = "/session/%s/chromium/send_command_and_get_result" % driver.session_id url = driver.command_executor._url + resource body = json.dumps({'cmd': cmd, 'params': params}) response = driver.command_executor._request('POST', url, body) if response['status']: raise Exception(response.get('value')) return response.get('value') if __name__ == "__main__": if len(sys.argv) != 3: print ("usage: converter.py <html_page_sourse> <filename_to_save>") exit() result = get_pdf_from_html(sys.argv[1]) with open(sys.argv[2], 'wb') as file: file.write(result) 

Para obter um arquivo PDF, você pode executar este exemplo na linha de comando, especificando o URL e o nome do arquivo para salvar o PDF, ou chame a função get_pdf_from_html e passe três argumentos para ele:


  1. caminho - URL do documento html;
  2. chromedriver - o caminho na máquina local para o driver chrome (por padrão, ele deve estar no diretório local);
  3. print_options - atributos de impressão adicionais.

Deve-se observar que o Selenium não possui uma interface padrão para imprimir uma página em PDF, e somente o Chrome pode fazer isso; portanto, é necessário ligar diretamente para driver.command_executor._request .


Agora vamos ver quais ferramentas estão disponíveis para controlar o posicionamento do conteúdo em documentos de várias páginas.


Tipografia CSS


Ao imprimir em frente e verso, você pode definir margens diferentes da borda para as páginas direita e esquerda individualmente se planeja costurá-las no futuro:


 @page :left { margin-left: 4cm; margin-right: 2cm; } @page :right { margin-left: 4cm; margin-right: 2cm; } 

Para a primeira página, você pode especificar seu próprio design, por exemplo, um recuo aumentado da borda superior:


 @page :first { margin-top: 10cm /* Top margin on first page 10cm */ } 

É possível definir a quebra de página antes do cabeçalho do primeiro nível para que comece em uma página ímpar:


 h1 { page-break-before : right } 

Usando a propriedade page-break-after , você pode impedir uma quebra de página imediatamente após algum elemento, por exemplo, um cabeçalho de segundo nível:


 h2 { page-break-after : avoid } 

A propriedade page-break-inside ajuda a evitar quebras de página onde é indesejável fazer isso, por exemplo, no meio de uma tabela


 table { page-break-inside : avoid } 

As orphans e orphans ajudarão a evitar quebras de página no início e no final de um parágrafo:


 @page { orphans:4; widows:2; } 

E o desempenho?


Em um Core i5-8600K 3600MHz em um fluxo, uma simples conversão de documento leva 0,6 segundos. Na minha máquina de escrever portátil de final de 2013, 2,4 GHz - 1,5 segundos.
Obviamente, os principais recursos são gastos no lançamento do navegador. Você pode reduzir o tempo de conversão para um grande número de arquivos se executar o Chrome uma vez como microsserviço e enviar a ele um URL para conversão. A implementação deste método está além do escopo deste artigo.


O que mais está errado?


Eu vejo dois problemas principais:


  1. A impossibilidade de simplesmente determinar a posição dos elementos em um documento. Isso dificulta a criação de um índice com indicação automática dos números de página, especialmente se o tamanho do conteúdo não for conhecido antecipadamente.
  2. A conversão do Chrome é o produto do Google, que coleta diversas informações sobre os usuários. Se o vazamento de dados do documento for inaceitável, você deve ter cuidado com a solução proposta - feche o navegador com acesso a recursos externos ou procure outra solução. O uso de código aberto Chromium não resolve o problema - já foram encontrados erros do Google.

Conclusões


Proponho tirar conclusões sobre a admissibilidade de usar essa abordagem por conta própria. Cada projeto é único à sua maneira. Se você decide se esse método é adequado em seu projeto.

Source: https://habr.com/ru/post/pt459112/


All Articles