Automatisiertes Exportieren von Webseiten als PDF
Hallo liebe Community,
Ich habe folgendes Problem bzw Ziel:
Es sollen mehrere Webseiten automatisiert als PDF Datei exportiert werden. Es handelt sich hier um Stundenzettel von Kollegen. Die URLS haben alle eine fortlaufende ID, zB "https://URL.tld?id=1?weitereDatendieImmerGleichSind=blabla"
Nach Möglichkeit sollte das mit "einfachen Bordmitteln" von Windows 10 realisiert werden, zB Powershell.
Ich habe hier ein wenig experimentiert und verschiedene Ansätze ausporbiert, ich kriege es aber nicht geregelt Von dem Tool wkhtmltopdf habe ich mir da viel versprochen, doch es läuft leider auf Fehler und generiert leere PDF Dokumente
Vielleicht hat sich hier ja bereits jemand mit sowas beschäftigt oder hat einen Tipp für mich.
Lieben Dank
Ich habe folgendes Problem bzw Ziel:
Es sollen mehrere Webseiten automatisiert als PDF Datei exportiert werden. Es handelt sich hier um Stundenzettel von Kollegen. Die URLS haben alle eine fortlaufende ID, zB "https://URL.tld?id=1?weitereDatendieImmerGleichSind=blabla"
Nach Möglichkeit sollte das mit "einfachen Bordmitteln" von Windows 10 realisiert werden, zB Powershell.
Ich habe hier ein wenig experimentiert und verschiedene Ansätze ausporbiert, ich kriege es aber nicht geregelt Von dem Tool wkhtmltopdf habe ich mir da viel versprochen, doch es läuft leider auf Fehler und generiert leere PDF Dokumente
Vielleicht hat sich hier ja bereits jemand mit sowas beschäftigt oder hat einen Tipp für mich.
Lieben Dank
Bitte markiere auch die Kommentare, die zur Lösung des Beitrags beigetragen haben
Content-ID: 666118
Url: https://administrator.de/contentid/666118
Ausgedruckt am: 22.11.2024 um 01:11 Uhr
18 Kommentare
Neuester Kommentar
Servus,
da könnte dir
Invoke-Webrequest
und diese Function helfen
da könnte dir
Invoke-Webrequest
und diese Function helfen
function ConvertTo-PDF {
param(
$TextDocumentPath
)
Add-Type -AssemblyName System.Drawing
$doc = New-Object System.Drawing.Printing.PrintDocument
$doc.DocumentName = $TextDocumentPath
$doc.PrinterSettings = new-Object System.Drawing.Printing.PrinterSettings
$doc.PrinterSettings.PrinterName = 'Microsoft Print to PDF'
$doc.PrinterSettings.PrintToFile = $true
$file=[io.fileinfo]$TextDocumentPath
$pdf= [io.path]::Combine($file.DirectoryName, $file.BaseName) + '.pdf'
$doc.PrinterSettings.PrintFileName = $pdf
$doc.Print()
$doc.Dispose()
}
Servus @DarkTrinity,
ein Beispiel von diversen möglichen, mit einem einfachen CMDLet das ich vor einiger Zeit mal zusammen geschrieben hatte ...
Grüße Uwe
ein Beispiel von diversen möglichen, mit einem einfachen CMDLet das ich vor einiger Zeit mal zusammen geschrieben hatte ...
# function to convert website to pdf
function Convert-WebsiteToPDF {
[cmdletbinding()]
param(
[parameter(mandatory=$true)][string]$URL,
[parameter(mandatory=$true)][string]$path
)
function Load-MultiFileNugetAssembly {
[CmdletBinding()]
param(
[string]$url,
[string]$name,
[hashtable]$files
)
if($psscriptroot -ne ''){
$localpath = $psscriptroot
}else{
$localpath = $env:TEMP
}
$tmp = "$env:TEMP\$([IO.Path]::GetRandomFileName())"
$zip = $null
try{
Add-Type -A System.IO.Compression.FileSystem
# download if needed
if ($files.Keys | ?{!(Test-Path (join-path $localpath $_))}){
write-host "Downloading and extracting required library '$name' ... " -F Green -NoNewline
(New-Object System.Net.WebClient).DownloadFile($url, $tmp)
write-host "OK" -F Green
$zip = [System.IO.Compression.ZipFile]::OpenRead($tmp)
}
foreach($file in $files.GetEnumerator()){
$outfile = join-path $localpath $file.Name
$zip.Entries | ?{$_.Fullname -eq $file.Value.InternalPath} | %{
[System.IO.Compression.ZipFileExtensions]::ExtractToFile($_, $outfile, $true)
Unblock-File -Path $outfile
}
if ($file.Value.LoadAssembly){
Add-Type -Path $outfile -EA Stop
}
}
}catch{
throw "Error: $($_.Exception.Message)"
}finally{
if ($zip){$zip.Dispose()}
if(Test-Path $tmp){del $tmp -Force}
}
}
# Load Spire.PDF Assemblies
Load-MultiFileNugetAssembly 'https://www.nuget.org/api/v2/package/FreeSpire.PDF/7.2.0' -name 'Spire.Pdf' -files @{'Spire.Pdf.dll'=@{InternalPath='lib/net40/Spire.Pdf.dll';LoadAssembly=$true};'Spire.License.dll'=@{InternalPath='lib/net40/Spire.License.dll';LoadAssembly=$true}} -EA Stop
# create pdf document
$doc = new-object Spire.Pdf.PDFDocument
# create conversion settings objects
$html_format = New-Object Spire.Pdf.HtmlConverter.PdfHtmlLayoutFormat -Property @{
Layout = [Spire.Pdf.Graphics.PdfLayoutType]::OnePage
}
# pdf page settings
$settings = New-Object Spire.Pdf.PdfPageSettings -Property @{
Margins = New-Object Spire.Pdf.Graphics.PdfMargins 10
Size = [Spire.Pdf.PdfPageSize]::A4
Orientation = 'Portrait'
}
# load html Parameter: URL, execute javascript, convert links, detect page breaks, settings, format
$doc.LoadFromHTML($URL,$false,$false,$false,$settings,$html_format)
# save pdf object to file
$doc.SaveToFile($path)
# close document
$doc.Close()
}
# beginn with id
$start_id = 1
# stop with id
$stop_id = 10
# itterate over ids
$start_id..$stop_id | %{
# Use converter function with URL and output path
Convert-WebsiteToPDF -URL "https://URL.tld?id=$_&weitereDatendieImmerGleichSind=blabla" -path "E:\Ausgabe\stundenzettel_id_$_.pdf"
}
Grüße Uwe
Servus zurück.
Wenn ich es über die Powershell ausführe via powershell Web2PDF.ps1 erzeugt es die folgende Fehlermeldung;
Das ist z.B. eine Zeile die in meinem Code überhaupt nicht vorkommt! Ergo muss diese entweder von dir selbst hinzugefügt worden sein oder in deinem Powershell-Profil schon der Syntax-Fehler eingebaut sein!
Wenn du selbstständig Teile veränderst kann ich natürlich nichts dran machen .
Starte das Skript mal ohne das Laden des Powershell-Profils des Users, mit dem Parameter
Und schau mal in dein Powershell-Profil-Skript, was da so alles drin steht. Dazu in einer Konsole eingeben:
Das sollte dein Profil-Skript öffnen sofern vorhanden.
Grüße Uwe
das Script ist toll - erstmal ganz lieben Dank Aber irgendwie funktioniert es nicht wirklich...
Wurde hier natürlich wie immer vorher einwandfrei getestet . Ich poste keinen Code den ich nicht vorher teste.Wenn ich es über die Powershell ausführe via powershell Web2PDF.ps1 erzeugt es die folgende Fehlermeldung;
Web2PDF.ps1:15 char:55
> + [System.Windows.Forms.SendKeys]::SendWait("{ENTER}")
> + ~~
> The string is missing the terminator: ".
> + CategoryInfo : ParserError: (:) , ParentContainsErrorRecordException
> + FullyQualifiedErrorId : TerminatorExpectedAtEndOfString
Das ist z.B. eine Zeile die in meinem Code überhaupt nicht vorkommt! Ergo muss diese entweder von dir selbst hinzugefügt worden sein oder in deinem Powershell-Profil schon der Syntax-Fehler eingebaut sein!
Wenn du selbstständig Teile veränderst kann ich natürlich nichts dran machen .
Auch wenn ich die Powershell mit Administrator- Rechten ausführe oder den Parameter -ExecutionPolicy Bypass verwende erscheint diese Meldung....
Admin-Rechte sind nicht nötig für das Ausführen des Skripts. Nur Schreibrechte auf den Skript bzw. Temp-Ordner für das Herunterladen von 2 DLLs aus dem Nuget Repo.Ich habe es dann in Visual Studio Code etwas verändert - Zeile 81 - 84:
Das ist erst mal Blödsinn x mal den selben Output zu erzeugen, wenn dann verändert man die Parameter $start_id und $stop_id auf den gewünschten Wert so dass die Schleife nur mit den entsprechenden IDs ausgeführt wird.> $startid..$stopid | %{
> # Use converter function with URL and output path
> Convert-WebsiteToPDF -URL "https://URL.tld?id=128&weitereDatendieImmerGleichSind=blabla" -path "E:\Ausgabe\stundenzettel_id_128_.pdf"
> }
>
So erzeugt es den Stundenzettel wie gewünscht - aber auch nur dann wenn ich es über die IDE ausführe. In der Powershell- Konsole wird nach wie vor diese Meldung erzeugt....
Dann liegt der Fehler sehr wahrscheinlich in deinem Powershell Profil, denn obige Zeile ist wie gesagt nicht in meinem Skript enthalten und hier funktioniert das reine Skript auf sämtlichen Windows 10 oder auch 7 Maschinen problemlos, es muss also auf deiner Seite liegen.Starte das Skript mal ohne das Laden des Powershell-Profils des Users, mit dem Parameter
-NoProfile
.Und schau mal in dein Powershell-Profil-Skript, was da so alles drin steht. Dazu in einer Konsole eingeben:
start $profile
Das sollte dein Profil-Skript öffnen sofern vorhanden.
Grüße Uwe
Zitat von @DarkTrinity:
In dem Fall wird aber ein leere Datei erzeugt und die Variable (die ID) hat den Wert 0
Dann hast du aber selbst die Variable $startid schon auf 0 geändert ... Diese müssen natürlich auf die Werte gesetzt werden für die IDs deren Seiten du exportieren willst, diese werden einfach hochgezählt. $start_id ist der Anfangswert und $stop_id ist der Endwert. $start_id..$stop_id ist ein einfacher FOR-Loop zählt also immer eins hoch bis $stop_id erreicht ist.In dem Fall wird aber ein leere Datei erzeugt und die Variable (die ID) hat den Wert 0
Wenn das geklärt ist mache ich damit weiter.
Alles klar.
Schuss ins Blaue: Vielleicht versehentlich zwei verschiedene Scripte mit dem selben Namen in unterschiedlichen Verzeichnissen bearbeitet, passiert mir auch ab und zu mal wenn man sich in der Bearbeitungsphase entscheidet die Files schon mal verschieben zu müssen, in der IDE aber noch das alte Ziel hinterlegt ist.
Grüße Uwe
Das Script läuft
Na dann haben wir das Ziel ja erreicht .Nochmal vielen Dank
Immer gerne.Grüße Uwe
Hallo Uwe, auf der Suche nach einer etwas anderen Lösung bin ich auf deinen Beitrag hier gestoßen. Das funktionier perfekt. Leider habe ich nicht das fachliche Wissen, deinen Code auf meine Wünsche umzuschreiben. Ich möchte daher um deine Hilfe bitten.
Ich würde gern eine feste URL "https://URL.tld" in eine Verzeichnis ablegen. Allerdings mit Datum und Zeitstempel "E:\Ablage\dok1_datum_uhrzeit.pdf"
Das Script würde ich dann gern per Zeitsteuerung regelmäßig auslösen. Vielen Dank Frank
Ich würde gern eine feste URL "https://URL.tld" in eine Verzeichnis ablegen. Allerdings mit Datum und Zeitstempel "E:\Ablage\dok1_datum_uhrzeit.pdf"
Das Script würde ich dann gern per Zeitsteuerung regelmäßig auslösen. Vielen Dank Frank
@DPSERVER du hast Post.
Zitat von @DarkTrinity:
Ein letzter Punkt will mir jedoch nicht gelingen - kann man das Script auch dahingehend anpassen, daß es den Extract auf einer entsprechenden Anzahl an A4 Seiten verteilt ?
Kannst du in den Settings der Funktion anpassenEin letzter Punkt will mir jedoch nicht gelingen - kann man das Script auch dahingehend anpassen, daß es den Extract auf einer entsprechenden Anzahl an A4 Seiten verteilt ?
# create conversion settings objects
$html_format = New-Object Spire.Pdf.HtmlConverter.PdfHtmlLayoutFormat -Property @{
Layout = [Spire.Pdf.Graphics.PdfLayoutType]::Paginate
}
# pdf page settings
$settings = New-Object Spire.Pdf.PdfPageSettings -Property @{
Margins = New-Object Spire.Pdf.Graphics.PdfMargins 10
Size = [Spire.Pdf.PdfPageSize]::A4
Orientation = 'Portrait'
}
# load html Parameter: URL, execute javascript, convert links, detect page breaks, settings, format
$doc.LoadFromHTML($URL,$false,$false,$true,$settings,$html_format)
Hallo Uwe,
ich versuche mich gerade an deinem Skript. Leider läuft das CMD Fenster so schnell durch, dass ich nur im Vorbeifliegen etwas von "...konnte nicht gefunden werden..." erhaschen konnte.
Wie kann ich hier denn ein Protokoll für die Meldung, bzw den Fehler erstellen?
Viele Grüße,
Paul
Nachtrag:
Nach einem kleinen Anfängerfehler habe ich das Skript zum Laufen bringen können und es speichert viele, viele meiner Webseiten als Pdf. Genauer gesagt fast im Sekundentakt Eine. Und das scheinbar unendlich
Mein neues Problem: obwohl ich mich vorher auf der Webseite eingeloggt habe und dann den Pfad kopiert habe, scheitert das Skript scheinbar am Login und speichert immer nur die Hauptseite, wo sich der Login-Aufruf befindet.
Wie und an welcher Stelle kann ich denn den Login zur Webseite in das Skript einfügen?
Ich bin echt dankbar für jede Anregung und Idee, die mich weiter vorwärts bringt !!!
Viele Grüße,
Paul
ich versuche mich gerade an deinem Skript. Leider läuft das CMD Fenster so schnell durch, dass ich nur im Vorbeifliegen etwas von "...konnte nicht gefunden werden..." erhaschen konnte.
Wie kann ich hier denn ein Protokoll für die Meldung, bzw den Fehler erstellen?
Viele Grüße,
Paul
Nachtrag:
Nach einem kleinen Anfängerfehler habe ich das Skript zum Laufen bringen können und es speichert viele, viele meiner Webseiten als Pdf. Genauer gesagt fast im Sekundentakt Eine. Und das scheinbar unendlich
Mein neues Problem: obwohl ich mich vorher auf der Webseite eingeloggt habe und dann den Pfad kopiert habe, scheitert das Skript scheinbar am Login und speichert immer nur die Hauptseite, wo sich der Login-Aufruf befindet.
Wie und an welcher Stelle kann ich denn den Login zur Webseite in das Skript einfügen?
Ich bin echt dankbar für jede Anregung und Idee, die mich weiter vorwärts bringt !!!
Viele Grüße,
Paul
Servus Paul.
Der TO wollte eine Reihe von Artikeln herunterladen deswegen die Schleife von 1-10 oben!
Wie und an welcher Stelle kann ich denn den Login zur Webseite in das Skript einfügen?
Das kommt darauf an welche Methode der Login nutzt. Wenn es eine Basic-Authentification ist, lassen sich die Credentials direkt in die URL einbauen als
Wenn der Login jedoch aus einer Custom Form besteht geht das hiermit nicht.
Indem Fall müsstest du entweder zu einer Webbrowser Automation z.B. mittels Selenium greifen das habe ich hier schon mal gezeigt:
PowerShell: Einführung in die Webbrowser Automation mit Selenium WebDriver
Oder man macht den Login mittels POST/GET Requests manuell. Bedingt aber bei beiden Varianten das man weiß wie der Login genau vollzogen wird, ergo man braucht den HTML-Quellcode und per Browser-Developer Tools untersucht man den Login auf dem Netzwerktab. Ein Universalrezept gibt es hier nicht, das kommt immer auf die Webseite drauf an.
Bitte aber den Thread hier nicht weiter übernehmen, dieser wurde als erledigt gekennzeichnet.
Für mehr Informationen bitte PN oder neuen Beitrag aufmachen. Merci.
Grüße Uwe
Der TO wollte eine Reihe von Artikeln herunterladen deswegen die Schleife von 1-10 oben!
Mein neues Problem: obwohl ich mich vorher auf der Webseite eingeloggt habe und dann den Pfad kopiert habe, scheitert das Skript scheinbar am Login und speichert immer nur die Hauptseite, wo sich der Login-Aufruf befindet.
Das ist normal denn was du im Browser machst interessiert die Bibliothek nicht, weil sie eine eigene Browser-Rendering-Engine mit eigener Session-Verwaltung und eigenen Cookies nutzt!Wie und an welcher Stelle kann ich denn den Login zur Webseite in das Skript einfügen?
https://USERNAME:PASSWORT@domain.tld
Indem Fall müsstest du entweder zu einer Webbrowser Automation z.B. mittels Selenium greifen das habe ich hier schon mal gezeigt:
PowerShell: Einführung in die Webbrowser Automation mit Selenium WebDriver
Oder man macht den Login mittels POST/GET Requests manuell. Bedingt aber bei beiden Varianten das man weiß wie der Login genau vollzogen wird, ergo man braucht den HTML-Quellcode und per Browser-Developer Tools untersucht man den Login auf dem Netzwerktab. Ein Universalrezept gibt es hier nicht, das kommt immer auf die Webseite drauf an.
Bitte aber den Thread hier nicht weiter übernehmen, dieser wurde als erledigt gekennzeichnet.
Für mehr Informationen bitte PN oder neuen Beitrag aufmachen. Merci.
Grüße Uwe