5
votes

comment enregistrer la page ouverte au format pdf dans Selenium (Python)

J'ai essayé toutes les solutions que j'ai pu trouver sur Internet pour pouvoir imprimer une page ouverte dans Selenium en Python. Cependant, alors que la fenêtre contextuelle d'impression apparaît, après une ou deux secondes, elle disparaît, sans PDF enregistré.

Voici le code essayé. Basé sur le code ici - https://stackoverflow.com/a/43752129/3973491

Codage sur un Mac avec Mojave 10.14.5.

from selenium import webdriver
import json

chrome_options = webdriver.ChromeOptions()
settings = {
    "appState": {
        "recentDestinations": [{
            "id": "Save as PDF",
            "origin": "local",
            "account": "",
        }],
        "selectedDestinationId": "Save as PDF",
        "version": 2
    }
}
prefs = {'printing.print_preview_sticky_settings': json.dumps(settings)}
chrome_options.add_experimental_option('prefs', prefs)
chrome_options.add_argument('--kiosk-printing')
CHROMEDRIVER_PATH = '/usr/local/bin/chromedriver'
driver = webdriver.Chrome(chrome_options=chrome_options, executable_path=CHROMEDRIVER_PATH)
driver.get("https://google.com")
driver.execute_script('window.print();')
driver.quit()
$chromedriver --v
ChromeDriver 75.0.3770.90 (a6dcaf7e3ec6f70a194cc25e8149475c6590e025-refs/branch-heads/3770@{#1003})

Tout conseil ou solution sur ce qui peut être fait pour imprimer la page html ouverte dans un PDF. J'ai passé des heures à essayer de faire ce travail. Merci!


Mise à jour le 11/07/2019:

Ma question a été identifiée comme un doublon, mais a) l'autre question semble utiliser du code javascript, et b) la réponse ne résout pas le problème soulevé dans cette question - cela peut être lié à des versions logicielles plus récentes. La version Chrome utilisée est la version 75.0.3770.100 (version officielle) (64 bits), et chromedriver est ChromeDriver 75.0.3770.90. Sur Mac OS Mojave. Le script s'exécute sur Python 3.7.3.

Mise à jour le 11/07/2019:

Le code a été remplacé par

from selenium import webdriver
from selenium.webdriver.support.select import Select
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.common.exceptions import NoSuchElementException
from selenium.common.exceptions import TimeoutException
from selenium.webdriver.chrome.options import Options
from selenium.common.exceptions import WebDriverException
import time
import json

options = Options()
appState = {
    "recentDestinations": [
        {
            "id": "Save as PDF",
            "origin": "local"
        }
    ],
    "selectedDestinationId": "Save as PDF",
    "version": 2
}

profile = {'printing.print_preview_sticky_settings.appState': json.dumps(appState)}
# profile = {'printing.print_preview_sticky_settings.appState':json.dumps(appState),'savefile.default_directory':downloadPath}
options.add_experimental_option('prefs', profile)
options.add_argument('--kiosk-printing')
CHROMEDRIVER_PATH = '/usr/local/bin/chromedriver'

driver = webdriver.Chrome(options=options, executable_path=CHROMEDRIVER_PATH)
driver.implicitly_wait(5)
driver.get(url)
driver.execute_script('window.print();')

Et maintenant, rien ne se passe. Chrome se lance, charge l'URL, la boîte de dialogue d'impression apparaît mais rien ne semble se produire - rien dans la file d'attente par défaut de l'imprimante, et pas de pdf non plus - J'ai même recherché les fichiers PDF en recherchant "Fichiers récents" sur Mac.


7 commentaires

aucun PDF enregistré , où avez-vous vérifié? Il doit être enregistré dans votre dossier Téléchargements utilisateur.


@Kamal - J'ai essayé à nouveau, et j'ai remarqué que Chrome tirait une impression réelle sur mon imprimante par défaut, mais je n'étais pas au même endroit, donc je n'ai pas remarqué ce qui s'était réellement passé. supprimé la file d'attente d'impression des nombreuses fois où j'avais essayé d'imprimer au format pdf / apparu que rien ne s'est passé. donc je soupçonne que l'option "Enregistrer au format PDF" n'est pas sélectionnée et je ne sais pas comment la sélectionner.


Veuillez vous référer à cette réponse . Dans votre code, vous appelez webdriver.Chrome(options=options.. , mais la syntaxe correcte est webdriver.Chrome(chrome_options=options.. Et d'une certaine manière, avec webdriver.ChromeOptions print fonctionne plus rapidement qu'avec webdriver.chrome.options.Options , donc je vous suggère d'essayer cela.


Copie possible de Set Selenium ChromeDriver UserPreferences to Save as PDF


@Kamal - Merci pour vos commentaires. J'ai juste essayé ça aussi. a changé le code en chrome_options = webdriver.ChromeOptions (). Et en effet, webdriver.ChromeOptions semble fonctionner plus rapidement, mais même cette option déclenche une impression vers l'imprimante par défaut et non vers le PDF: (Toujours à la recherche de conseils sur la façon de procéder - si ce n'est pas avec Selenium, je me demande si c'est possible avec une autre bibliothèque. Cependant, la page que je dois atteindre est après une procédure de connexion.


Le code d'une autre question fonctionne pour moi, alors pouvez-vous mettre à jour votre question avec le dernier code que vous avez essayé?


Mise à jour de la question avec le dernier code que j'ai utilisé. Cette fois, rien ne semble aller nulle part même si la boîte de dialogue d'impression semble se lancer. La boîte de dialogue d'impression est trop rapide et ne peut pas lire quelle imprimante ou si l'option PDF est sélectionnée. Intrigué. Merci @Kamal de rester engagé et de m'avoir aidé à résoudre ce problème.


4 Réponses :


7
votes

La réponse ici , a fonctionné lorsque je n'avais aucune autre configuration d'imprimante dans mon système d'exploitation. Mais quand j'avais une autre imprimante par défaut, cela ne fonctionnait pas.

Je ne comprends pas comment, mais faire de petits changements de cette façon semble fonctionner.

from selenium import webdriver
import json

chrome_options = webdriver.ChromeOptions()
settings = {
       "recentDestinations": [{
            "id": "Save as PDF",
            "origin": "local",
            "account": "",
        }],
        "selectedDestinationId": "Save as PDF",
        "version": 2
    }
prefs = {'printing.print_preview_sticky_settings.appState': json.dumps(settings)}
chrome_options.add_experimental_option('prefs', prefs)
chrome_options.add_argument('--kiosk-printing')
CHROMEDRIVER_PATH = '/usr/local/bin/chromedriver'
driver = webdriver.Chrome(chrome_options=chrome_options, executable_path=CHROMEDRIVER_PATH)
driver.get("https://google.com")
driver.execute_script('window.print();')
driver.quit()


4 commentaires

Merci @Kamal. Cette approche fonctionne en effet mais elle s'imprime sur la dernière imprimante utilisée. Je viens de faire quelques recherches et je me demande si cups-pdf installé en tant qu'imprimante et si cups-pdf est la dernière imprimante utilisée peut aboutir au résultat souhaité - imprimer en pdf en utilisant python.


Désolé, je n'ai pas pu tester ma solution sous Linux, cela a fonctionné sous Windows 10 pour moi.


je l'ai. J'y travaillerai un peu plus et je verrai si je peux trouver quelque chose.


J'ai travaillé sur Linux pour moi. Ce serait bien si nous pouvions contrôler l'emplacement de téléchargement, cependant.



2
votes

La solution n'est pas très bonne, mais vous pouvez prendre une capture d'écran et la convertir en pdf par Pillow ...

from selenium import webdriver
from io import BytesIO
from PIL import Image

driver = webdriver.Chrome(executable_path='path to your driver')
driver.get('your url here')
img = Image.open(BytesIO(driver.find_element_by_tag_name('body').screenshot_as_png))
img.save('filename.pdf', "PDF", quality=100)


9 commentaires

Merci pour votre réponse. Le problème avec cette approche est qu'elle ne fonctionne pas pour les pages Web de plusieurs pages. Seule une partie des informations est capturée. Mais c'est une bonne solution pour les pages courtes et n'implique pas de popups.


qu'entendez-vous par pages Web multi-pages ?


ce qui signifie les pages Web qui doivent faire défiler pour voir la page Web complète et une fois imprimées au format PDF, elles tiennent sur 3-4 feuilles de papier.


vous pouvez utiliser ce code: stackoverflow.com/a/57608276/10661593 , et à la fin enregistrer au format pdf. Ps je n'ai pas compris un peu, désolé. Voulez-vous adapter la page entière sur 1 feuille lors de l'impression? ou comment


donc ce que je veux idéalement pouvoir faire - c'est imprimer une page au format pdf. sur un Mac, lorsque vous faites cela, le PDF généré peut s'exécuter sur plusieurs pages - en supposant que le PDF est créé pour une impression au format Lettre ou A4. si je rétrécis beaucoup la page et que je prends une capture d'écran qui ne sert pas le but. bien que, maintenant je comprends que Selenium ne contrôle pas les boîtes de dialogue du navigateur, et ne peut donc pas imprimer la page au format PDF. apparemment, le marionnettiste ou le pyppétiste en python peuvent le faire mais je ne sais pas encore comment utiliser ce logiciel. le lien que vous avez partagé semble parler de capture d'écran et non de pdf ...


vous pouvez enregistrer une capture d'écran au format pdf, pourquoi pas?


Je peux. Mais la page que je souhaitais enregistrer se heurte à de nombreux écrans de défilement vertical. Et ainsi cela deviendrait multiple et bas de page, puis convertir chaque capture d'écran en PDF, puis combiner les PDF. Je viens de penser à cela en fonction de votre commentaire. Cela semble encore assez kludgy, et j'espérais qu'il y aura une meilleure solution. Pyppeteer pourrait me permettre de le faire en Python semble-t-il, mais je ne sais pas comment m'en servir. :(


Je pense que cela résoudrait mon problème. miyakogi.github.io/pyppeteer/_modules/pyppeteer/… . Cependant, je ne connais pas async et attend, et j'ai besoin de les apprendre avant d'essayer d'utiliser Pyppeteer. Difficile de croire que Selenium ne pouvait pas le faire comme je l'avais en quelque sorte appris ...


Je ne dirai pas que je suis bouleversé. :) Selenium est gratuit et merci à l'équipe pour ça! C'est juste que j'étais certain que cela pouvait être fait et je pensais que je ne connaissais pas la bonne syntaxe ou les bonnes options pour activer l'impression PDF dans Selenium. Utiliser des kludges ne semble pas être la bonne chose. Il finira par se briser.



1
votes

Voici la solution que j'utilise avec Windows:

  • Téléchargez d'abord ChromeDriver ici: http://chromedriver.chromium.org/downloads et installez Selenium

  • Ensuite, exécutez ce code (basé sur la réponse acceptée, légèrement modifiée pour fonctionner sous Windows):

    import json
    from selenium import webdriver
    chrome_options = webdriver.ChromeOptions()
    settings = {"recentDestinations": [{"id": "Save as PDF", "origin": "local", "account": ""}], "selectedDestinationId": "Save as PDF", "version": 2}
    prefs = {'printing.print_preview_sticky_settings.appState': json.dumps(settings)}
    chrome_options.add_experimental_option('prefs', prefs)
    chrome_options.add_argument('--kiosk-printing')
    browser = webdriver.Chrome(r"chromedriver.exe", options=chrome_options)
    browser.get("https://google.com/")
    browser.execute_script('window.print();')
    browser.close()    
    


2 commentaires

Il s'agit d'une révision si minime ("Selon la documentation de sélénium, spécifiez les emplacements des pilotes Windows (par exemple, chromedriver.exe ) plutôt que les emplacements des pilotes Linux lors de l'exécution sous Windows") qu'il devrait simplement s'agir d'un commentaire sur la réponse acceptée. De plus, il semble que vous ayez simplement minifié la réponse acceptée pour rendre le code différent.


@RobHall Les commentaires sont parfois effacés après des années; aussi parfois, il est difficile d'extraire des informations de plusieurs commentaires, donc cette réponse. J'ai correctement cité la source ("sur la base de la réponse acceptée"); le diable est vraiment dans les détails, j'ai passé beaucoup de temps à essayer et à échouer avant que cela fonctionne enfin, donc mon objectif était vraiment de mettre un code prêt à l'emploi pour Windows comme réponse.



0
votes

Vous pouvez utiliser le code suivant pour imprimer des PDF au format A5 avec le CSS d'arrière-plan activé:

import os
from selenium import webdriver
from selenium.webdriver.common.keys import Keys
import json
import time

chrome_options = webdriver.ChromeOptions()

settings = {
    "recentDestinations": [{
        "id": "Save as PDF",
        "origin": "local",
        "account": ""
    }],
    "selectedDestinationId": "Save as PDF",
    "version": 2,
    "isHeaderFooterEnabled": False,
    "mediaSize": {
        "height_microns": 210000,
        "name": "ISO_A5",
        "width_microns": 148000,
        "custom_display_name": "A5"
    },
    "customMargins": {},
    "marginsType": 2,
    "scaling": 175,
    "scalingType": 3,
    "scalingTypePdf": 3,
    "isCssBackgroundEnabled": True
}

mobile_emulation = { "deviceName": "Nexus 5" }
chrome_options.add_experimental_option("mobileEmulation", mobile_emulation)
chrome_options.add_argument('--enable-print-browser')
#chrome_options.add_argument('--headless')

prefs = {
    'printing.print_preview_sticky_settings.appState': json.dumps(settings),
    'savefile.default_directory': '<path>'
}
chrome_options.add_argument('--kiosk-printing')
chrome_options.add_experimental_option('prefs', prefs)

for dirpath, dirnames, filenames in os.walk('<source path>'):
    for fileName in filenames:
        print(fileName)
        driver = webdriver.Chrome("./chromedriver", options=chrome_options)
        driver.get(f'file://{os.path.join(dirpath, fileName)}')
        time.sleep(7)
        driver.execute_script('window.print();')
        driver.close()


0 commentaires