commodorec64
Goto Top

Daten aus Elster PDF automatisiert auslesen und in CSV ausgeben

Ich versuche aus PDF Dateien Daten von Steuererklärungen auszulesen. Leider sind die Zeilen in den Formularen oft an unterschiedlichen Stellen, deshalb suche ich ein Tool oder eine Lösung um Text aus PDF herauszulesen und nach speziellen Bedingungen in eine CSV Datei (oder auch SQL Datenbank) zu schreiben. Es sind einige hundert Dateien.

st 1 2022-02-22 10_48_02-window
st 2 2022-02-22 10_48_02-window

Also z.B. Wenn Geburtsdatum gefunden wird, dann nehme den rechts davon stehenden Eintrag bis zum Zeilenende und gebe ihn in eine CSV in die Spalte Geburtsdatum aus.
oder
Wenn Identifikationsnummer gefunden wird, dann nehme den rechts davon stehenden Eintrag bis zum Zeilenende und gebe ihn in eine CSV in die Spalte Identifikationsnummer aus.

Das müsste ich dann halt aufwändig einmal alles definieren, aber wenn das einmal gemacht ist, wäre es dann ja egal wo diese Einträge stehen, denn der Aufbau ist gleich, also links der Matchcode und rechts daneben der Wert. Nur eben manchmal in der Zeile 12 oder manchmal in der Zeile 8 oder sonstwo. Es kann auch sein das ein Wert überhaupt nicht da ist, also ein Leereintrag gemacht werden muss oder keine Ausgabe für das Feld erfolgen muss.

Ich habe bisher nur Tools gefunden die eher so funktionieren, das man Bereiche definiert und diesen Bereichen dann Variablen zuweist. Danach werden sie per OCR in diese Variablen gepackt und man kann sie ausgeben. Funktioniert super wenn die Formulare fast alle gleich sind wie z.B. Rechnungen, Lieferscheine usw. von einer Firma.
Funktioniert aber nicht bei bei meinem Fall.

Habt Ihr eine Lösung oder ein paar Links von Tools (dürfen auch was kosten) die meine Anforderungen erfüllen ?
Wer mir was programmieren kann oder schon programmiert hat, natürlich gegen Bezahlung, kann sich auch gerne melden.

Content-ID: 1977647551

Url: https://administrator.de/contentid/1977647551

Ausgedruckt am: 22.11.2024 um 10:11 Uhr

1915348599
1915348599 22.02.2022 aktualisiert um 11:18:53 Uhr
Goto Top
ukulele-7
ukulele-7 22.02.2022 um 12:04:39 Uhr
Goto Top
Wäre es nicht cleverer die Daten aus dem Vorsystem abzufragen, also im Falle von DATEV z.B. aus den Stammdaten?
colinardo
Lösung colinardo 22.02.2022, aktualisiert am 24.02.2022 um 22:19:16 Uhr
Goto Top
Servus @CommodoreC64 .
Mal schnell mit Powershell und iTextSharp zusammen gedengelt ... (ohne Gewähr und weitere Anpassungen auf Anfrage => PN )
<#
	Inhalte von PDFs eines Ordners auslesen und in CSV schreiben
#>

# QUellordner mit PDFs
$SOURCEFOLDER = "D:\Steuererklärungen"  
# Ausgabepfad für die CSV
$CSVTARGET = "D:\steuer.csv"  
# Liste der zu extrahierenden Tokens
$EXTRACTLIST = @(
    'Identifikationsnummer'  
    'Name'  
    'Vorname'  
    'Geburtsdatum'  
    'Straße (derzeitige Adresse)'  
    'Postleitzahl'  
    'Wohnort'  
    'Religion',  
    'Ausgeübter Beruf'  
    'IBAN'  
    'BIC'  
    'Geldinstitut und Ort'  
)
# =======================================

# Mindestens PS 3.0 erforderlich
if ($PSVersionTable.PSVersion.Major -lt 3){write-host "ERROR: Minimum Powershell Version 3.0 is required!" -F Yellow; return}    
$ErrorActionPreference = 'Stop'  

# Funktion zum Laden des iTextSharp Assemblies
function Load-iTextLibrary {
    if($psscriptroot -ne ''){  
        $localpath = join-path $psscriptroot 'itextsharp.dll'  
    }else{
        $localpath = join-path $env:TEMP 'itextsharp.dll'  
    }
    $zip = $null;$tmp = ''  
    try{
        if(!(Test-Path $localpath)){
            # Accept all TLS protocols
            [System.Net.ServicePointManager]::SecurityProtocol = [System.Net.SecurityProtocolType]::GetNames([System.Net.SecurityProtocolType]) 
            Add-Type -A System.IO.Compression.FileSystem
            $tmp = "$env:TEMP\$([IO.Path]::GetRandomFileName())"  
            write-host "Downloading and extracting required 'iTextSharp.dll' ... " -F Green -NoNewline  

            (New-Object System.Net.WebClient).DownloadFile('https://www.nuget.org/api/v2/package/iTextSharp/5.5.13.1', $tmp)  
            $zip = [System.IO.Compression.ZipFile]::OpenRead($tmp)
            $zip.Entries | ?{$_.Fullname -eq 'lib/itextsharp.dll'} | %{  
                [System.IO.Compression.ZipFileExtensions]::ExtractToFile($_,$localpath)
            }
            Unblock-File -Path $localpath
            write-host "OK" -F Green   
        }
        Add-Type -Path $localpath
    }catch{
        throw "Error: $($_.Exception.Message)"  
    }finally{
        if ($zip){$zip.Dispose()}
        if ($tmp -ne ''){del $tmp -Force -EA SilentlyContinue}  
    }
}
# iText Library laden
Load-iTextLibrary

# auch geschütze PDFs öffnen aktivieren
[iTextSharp.text.pdf.PdfReader]::unethicalreading = $true

# für jede PDF Datei im Quellordner
foreach($file in Get-ChildItem $SOURCEFOLDER -File -Filter *.pdf){
    $reader = $null
    try {
        write-host "Extracting data from '$($file.Fullname)' ... " -NoNewline -F Green  
        # PDF Reader Object erstellen
        $reader = New-Object iTextSharp.text.pdf.PdfReader $file.Fullname
        # Inhalt des PDFs exrahieren
        $content = 1..($reader.NumberOfPages) | %{
            [iTextSharp.text.pdf.parser.PdfTextExtractor]::GetTextFromPage($reader,$_)
        }
        # hashtable erstellen
        $obj = [ordered]@{}
        # für jedes Suchtoken
        foreach($token in $EXTRACTLIST) {
            # extrahiere Daten und weise sie dem Suchtoken zu
            $obj.$token = [regex]::match($content,"(?ism)^$([regex]::Escape($token))\s+([^\r\n]+)").Groups[1].Value.trim()  
        }
        # erstelle custom object aus der Hashtable und exportiere die Daten in die CSV-Datei
        [pscustomobject]$obj | export-csv $CSVTARGET -Delimiter ";" -NoType -Encoding UTF8 -Append  
        write-host "OK" -F Green  
    }catch{
        write-host $_.Exception.Message -F Red
    }finally{
        # cleanup
        if($reader){$reader.Dispose()}
    }
}
#edit# Fehler behoben (Dateifilter war noch auf meine Testdatei gesetzt, sorry)

Grüße Uwe

p.s. das nächste mal doch bitte an unsere Netiquette halten, Merci!
CommodoreC64
CommodoreC64 23.02.2022 um 15:54:04 Uhr
Goto Top
Vielen lieben Dank an Alle und besonders an @colinardo für den Codeschnipsel.
Habe den ausprobiert und er läuft durch, aber es gibt keine csv Datei.

Werd mich da mal reinhängen um zu schauen was noch nicht klappt.
Leider sind meine Programmierkenntnisse stark eingerostet und kommen auch aus anderen Programmiersprachen, deshalb seht es mir nach wenn ich beim lesen und probieren noch am dazulernen bin.

@ukelele-7
Leider wollen wir nicht von Datev sondern zu Datev aber der Hersteller unseres alten Programmes stellt sich stur mit Infos um direkt in die SQL Datenbank (Firebird) zu kommen (Passwörter unter Verschluss) und das Programm gibt leider nur definiert nach Elster aus und noch nichtmal irgendein anderes Format wie csv oder so.

LG
colinardo
colinardo 23.02.2022 aktualisiert um 16:40:28 Uhr
Goto Top
Servus.
Wie geschrieben, kann ich den Inhalt der PDFs hier nur mit eigenen Steuererklärungen testen und bei denen hat der im Skript enthaltene Regex problemlos funktioniert. Wenn natürlich keine Daten gefunden werden gibt es auch keine Ausgabe.
Ich geh hier mal davon aus das die Powershell-Grundlagen zur Ausführung von Skripten vorhanden sind. Wenn nicht und die Executionpolicy nicht angepasst wurde, bitte hier erst mal die Grundlagen zur Ausführung von PS Skripts anlesen
Powershell Leitfaden für Anfänger

Grüße Uwe

p.s. du hast eine PN.
ukulele-7
ukulele-7 23.02.2022 um 17:27:53 Uhr
Goto Top
Zitat von @CommodoreC64:

aber der Hersteller unseres alten Programmes stellt sich stur mit Infos um direkt in die SQL Datenbank (Firebird) zu kommen (Passwörter unter Verschluss)
Ein leidiges Thema, auch die DATEV "schützt" ihre DB ja vor dem Admin. Bei MSSQL kann ich aber eine solche DB bei gestoppten Diensten kopieren und die Kopie dann an einem anderen SQL Server einhängen und siehe da, nichts mit Passwort. Ob das bei Firebird geht weiß ich natürlich nicht und mit Komfort hat das ganze auch nichts zu tun aber für einen einmaligen Export / Übertrag von Daten eine nützliche Sache.