PDF avläsning med python

PDF avläsning med python

Har ni ett gammalt eller ett ekonomisystem som är svårt att integrera?
Nedan finns kod för att läsa av innehållet i en PDF. Detta kommer inte fungera rakt av för din lösning, men kan ge inspiration.

Om du behöver hjälp så finns mina kontaktuppgifter på den här sidan eller Linkedin.

#Created by Karl Sjökvist

from pdfminer.pdfinterp import PDFResourceManager, PDFPageInterpreter
from pdfminer.converter import TextConverter, XMLConverter, HTMLConverter
from pdfminer.layout import LAParams
from pdfminer.pdfpage import PDFPage
from io import BytesIO

import os
import glob
import xml.etree.ElementTree as ET


def convert_pdf(path, format='xml', codec='utf-8', password=''):
    rsrcmgr = PDFResourceManager()
    retstr = BytesIO()
    laparams = LAParams()
    if format == 'text':
        device = TextConverter(rsrcmgr, retstr, codec=codec, laparams=laparams)
    elif format == 'html':
        device = HTMLConverter(rsrcmgr, retstr, codec=codec, laparams=laparams)
    elif format == 'xml':
        device = XMLConverter(rsrcmgr, retstr, codec=codec, laparams=laparams)
    else:
        raise ValueError('provide format, either text, html or xml!')
    fp = open(path, 'rb')
    interpreter = PDFPageInterpreter(rsrcmgr, device)
    maxpages = 0
    caching = True
    pagenos=set()
    for page in PDFPage.get_pages(fp, pagenos, maxpages=maxpages, password=password,caching=caching, check_extractable=True):
        interpreter.process_page(page)

    text = retstr.getvalue().decode()
    fp.close()
    device.close()
    retstr.close()
    return text

#Analyserar och flyttar de analyserade filerna till klara efter att en xml har skapats av innehållet

PATH = "C:/Users/karl.sjokvist/Desktop/read pdf/"

if not os.path.exists('klara'):
    os.makedirs('klara')

pdffiles = (glob.glob(PATH + "*.pdf")) #Listar alla filer
for pdf in pdffiles:
    text = convert_pdf(pdf) #Anropet till konverteringen
    filename = pdf.split("\\")
    filename = filename[1].split(".")
    filename = filename[0]
    print ("påbörjar analys av " + filename)
    f = open(filename + ".xml", "w")
    text = text.replace("utf-8", "ISO-8859-1")
    text+="</pages>" #Var tvungen att lägga till detta då det finns en bugg
    f.write(text)
    f.close()
    
    os.replace(pdf, PATH+"klara/" + filename + ".pdf") #Flyttar filen

    #XML query för att få fram datan
    tree = ET.parse(filename + ".xml")
    root = tree.getroot()

    raknadesidor = 0
    sidor = 1

    #Räknar sidor i PDFn
    for value in root.iter('page'):
        raknadesidor+=1

    #Går genom alla sidor enskillt
    while sidor <= raknadesidor:
        print ("Sida" + str(sidor))
        for value in root.iter('page'):
            if value.attrib['id'] == str(sidor): #Sidorna på PDFen
    
                #För att få fram alla kostnadsrader
                #Artikelrader
                kostnadsrader = []
                for subvalue in value.iter('textline'):
                    if subvalue.attrib['bbox'].startswith("53.150"): #Kordinaterna på PDFen
                        textstring = ""
                        for text in subvalue.iter('text'): #Slår ihop indeviduella tecken till rader
                            textstring+=text.text
                        textstring = textstring[:-1]#Tar bort nya radbytet
                        kostnadsrader.append(textstring)
                firstindex = kostnadsrader.index("Artikel") #Första radindex
                secondindex = [i for i in kostnadsrader if i.startswith('Moms')]
                secondindex = kostnadsrader.index(secondindex[0])
                kostnadsrader = kostnadsrader[firstindex + 1:secondindex] #tar bort allt innan och efter index

                print (kostnadsrader)

                #Counts the numbers of type rows i.e. rows that has numbers
                posoffirstnum = None
                countrows = 0
                for i in kostnadsrader:
                    if i[0].isnumeric():
                        if i[-1].isnumeric():
                            if posoffirstnum == None:
                                posoffirstnum = countrows
                    countrows+=1

                #Benämning
                benamningsrader = []
                for subvalue in value.iter('textline'):
                    if subvalue.attrib['bbox'].startswith("130.400"): #Kordinaterna på PDFen
                        textstring = ""
                        for text in subvalue.iter('text'): #Slår ihop indeviduella tecken till rader
                            textstring+=text.text
                        textstring = textstring[:-1]#Tar bort nya radbytet
                        benamningsrader.append(textstring)
                firstindex = benamningsrader.index("Benämning") #Första radindex
                benamningsrader = benamningsrader[firstindex + 1:] #tar bort allt ibörjan och slutet av array

                print (benamningsrader)
            
                #antal
                antalrader = []
                for subvalue in value.iter('textline'):
                    if subvalue.attrib['bbox'].startswith("360.200") or subvalue.attrib['bbox'].startswith("360.650") or subvalue.attrib['bbox'].startswith("365.150") or subvalue.attrib['bbox'].startswith("364.700"): #Kordinaterna på PDFen
                        textstring = ""
                        for text in subvalue.iter('text'): #Slår ihop indeviduella tecken till rader
                            textstring+=text.text
                        textstring = textstring[:-1]#Tar bort nya radbytet
                        textstring = textstring.replace(" St","");
                        textstring = textstring.replace(" ","");
                        antalrader.append(textstring)

                print (antalrader)
            
                #enhet
                enheter = []
                for subvalue in value.iter('textline'):
                    if subvalue.attrib['bbox'].startswith("365.150") or subvalue.attrib['bbox'].startswith("391.400") or subvalue.attrib['bbox'].startswith("360.650") or subvalue.attrib['bbox'].startswith("360.200"): #Kordinaterna på PDFen
                        textstring = ""
                        for text in subvalue.iter('text'): #Slår ihop indeviduella tecken till rader
                            textstring+=text.text
                        textstring = textstring[:-1]#Tar bort nya radbytet
                        enheter.append(textstring)
                
                #Rensar onödig informaton från enhet
                enheterloop = 0
                while enheterloop < len(enheter):
                    if "st" in enheter[enheterloop]:
                        enheter[enheterloop] = "st"
                    if "tim" in enheter[enheterloop]:
                        enheter[enheterloop] = "tim"
                    if "skif" in enheter[enheterloop]:
                        enheter[enheterloop] = "skif"
                    if "St" in enheter[enheterloop]:
                        enheter[enheterloop] = "St"
                    if enheter[enheterloop] != "st" and enheter[enheterloop] != "tim" and enheter[enheterloop] != "skif" and enheter[enheterloop] != "St":
                        del enheter[enheterloop]
                        if len(enheter) >=1:
                            enheterloop-=1
                    enheterloop+=1

                print (enheter)
            
                #pris
                prisrader = []
                for subvalue in value.iter('textline'):
                    if subvalue.attrib['bbox'].startswith("417.150") or subvalue.attrib['bbox'].startswith("421.650") or subvalue.attrib['bbox'].startswith("426.150"): #Kordinaterna på PDFen
                        textstring = ""
                        for text in subvalue.iter('text'): #Slår ihop indeviduella tecken till rader
                            textstring+=text.text
                        textstring = textstring[:-1]#Tar bort nya radbytet
                        prisrader.append(textstring)
                print (prisrader)

                #skriva ut raderna
                rader = 0
                offset = 0
                print ("Skriver ut raderna")
                while rader < len(kostnadsrader):
                    rad = kostnadsrader[rader]
                    if rader >= posoffirstnum:
                        if offset < len(benamningsrader):
                            rad = rad + " " + benamningsrader[offset] + " " + antalrader[offset] + " " + enheter[offset] + " " + prisrader[offset]
                            offset+=1
                    rader+=1
                    print (rad)
                print ("klar med analys\n")
        sidor+=1