Problem mit xlsxwriter bei Hyperlinks

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
Antworten
BlueDogi
User
Beiträge: 30
Registriert: Mittwoch 29. April 2015, 22:25

Hallo zusammen,
ich würde gerne eine Verzeichnis Struktur einlesen und dieses in einer Xlsx-Datei speichern. In der Xlsx-Datei möchte ich des weiteren Hyperlinks benutzen um aus EXCEL direkt einen Ordner oder Datei zu öffnen.

Das schreiben selber klappt. Ich habe jetzt ein Problem bei dem Verlinken.

Der relevante Teil des Codes:

Code: Alles auswählen

def ErstelleXlsxDatei(Ausgabe_Verzeichnis, Name_Excel_Datei, XlcsStrucktur, Verzeichnis_liste):

    XlscDatei = os.path.join(Ausgabe_Verzeichnis, Name_Excel_Datei)
    workbook = xlsxwriter.Workbook(XlscDatei)
    worksheet = workbook.add_worksheet("FindeInDoku")
    Xlsx.info(BeginnXlsx)
    Zeile = 0
    EndeZeilen = len(XlcsStrucktur)
    while Zeile < EndeZeilen:
        EndeSpalte = len(XlcsStrucktur[Zeile])
        Spalte = 2
        while Spalte < EndeSpalte:
            url = os.path.join(*XlcsStrucktur[Zeile])
            Xlsx.debug("Schreibe Zeile " + str(Zeile+1) + " Und Spalte " + str(Spalte-2) + " in Xlsx Datei.")
            Xlsx.debug("Zellen Inhalt: " + XlcsStrucktur[Zeile][Spalte])
            Xlsx.debug("Url: " + url)
            worksheet.write_url(row=Zeile+1, col=Spalte-2, url="external:D:/Test/Ordner1/NeuesTextdokument.txt", string=XlcsStrucktur[Zeile][Spalte])
            Spalte = Spalte + 1
        Zeile = Zeile + 1
    Xlsx.info(EndeXlsx)

    workbook.close() 
Der komplette Code ist hier:http://codeviewer.org/view/code:5319 Die ini-Datei hier:http://codeviewer.org/view/code:531a

Wenn das Skript jetzt ausgeführt wird bekomme ich keinen Fehler. Erst beim öffnen der Xlsx Datei kommt ein Fehler das Alle Hyperlinks entfern wurden.
Wenn ich nun die Funktion worksheet.write_url() mit einem url sting: "external:D:\Test\Ordner1\NeuesTextdokument.txt" bekomme ich diesen Fehler:

Bild

Wenn ich aber den string: "external:D:\Test\Ordner1\NeuesTextdokument.txt" benutze habe funktioniert der Link.

Jemand eine Idee?

PS: Ja ich weiß ich sollte mich mehr an PEP8 halten... :roll:
Benutzeravatar
darktrym
User
Beiträge: 784
Registriert: Freitag 24. April 2009, 09:26

Kollege, schau dir mal die hübsche Escape-Sequenz an die du da einbaust.
„gcc finds bugs in Linux, NetBSD finds bugs in gcc.“[Michael Dexter, Systems 2008]
Bitbucket, Github
Sirius3
User
Beiträge: 17747
Registriert: Sonntag 21. Oktober 2012, 17:20

@BlueDogi: besser als ein Screenshot ist es, den Inhalt der Konsole (Fehlermeldung) als Text zu kopieren.
Zum Code:
Jeder import sollte in eine eigene Zeile, Sternchenimporte sind schlecht, os lädt dir über 230 Namen in den Namensraum, darunter so sinnvolle wie etliche, die gleich heißen wie builtins, wie open.
In Python gibt es weder eine Variablen-Delegration noch ein Deklaration und globale Variablen sollte man sowieso nicht benutzen. Tust Du auch nicht, daher sind die Zeilen 9 und 10 überflüssig.
Drei Logger sind glaube ich ein bißchen übertrieben. Das Vorhandensein von Dateien und Verzeichnissen prüft man normalerweise dadurch, ob ein Zugriff klappt oder nicht. Theoretisch kann sich da ja auch zwischen Deiner Prüfung und dem Zugriff noch was daran ändern. Klammern um einzelne Variablen sind unnötig. Mehr als zwei, drei Rückgabewerte machen den Code unleserlich. Bei so vielen Argumenten wären wohl Klassen angebracht. Wenn Fehler passieren, nimmt man Exceptions und nicht wie bei Setze_LogLevel eine Status-Variable. Genauso bei Konfiguration. Das bricht im Fehlerfall sowieso ab, weil Fertig dann nicht gesetzt ist. Die ganze Fehlerbehandlung ist aber sowieso unsinnig. Wenn ein Verzeichnis nicht vorhanden ist, will ich das ja wissen und nicht mit einem nichtsagenden "Konfigurationsfehler" abgespeist werden.
In Python gibt es sogar schon so moderne Dinge wie for-Schleifen!

Code: Alles auswählen

def os_walkNachTabelle(Verzeichnis_liste):
    XlcsStrucktur = []
    for verzeichnis in Verzeichnis_liste:
        pfad = PfadNachListe(verzeichnis)
        os_walk.debug(pfad)
        XlcsStrucktur.append(pfad)
    os_walk.info(UmwndlugTabelleOK)
    return XlcsStrucktur
obwohl, die ganze Funktion ist sowieso überflüssig, weil man die Aufspaltung gleich dort machen kann, wo sie gebraucht wird:

Code: Alles auswählen

def ErstelleXlsxDatei(Ausgabe_Verzeichnis, Name_Excel_Datei, Verzeichnis_liste):
    XlscDatei = os.path.join(Ausgabe_Verzeichnis, Name_Excel_Datei)
    workbook = xlsxwriter.Workbook(XlscDatei)
    worksheet = workbook.add_worksheet("FindeInDoku")
    Xlsx.info(BeginnXlsx)
    for zeile, verzeichnis in enumerate(Verzeichnis_liste, 1):
        url = "external:%s" % verzeichnis
        for spalte, pfad in enumerate(PfadNachListe(verzeichnis)[2:]):
            Xlsx.debug("Schreibe Zeile %d und Spalte %d in Xlsx Datei." % (zeile, spalte))
            Xlsx.debug("Zellen Inhalt: %s" % pfad)
            Xlsx.debug("Url: " + url)
            worksheet.write_url(row=Zeile, col=Spalte, url="external:"+url, string=pfad)
    Xlsx.info(EndeXlsx)
    workbook.close()
Alles in allem ist das Programm over-engineered. So gut wie keine Log-Ausgabe ist sinnvoll. Ob und welcher Inhalt in welche Spalte geschrieben wird, sieht man ja am fertigen Excel-File. Exceptionhandling an den richtigen Stellen ersetzt die gesamte, nicht funktionierende, selbst-ausgedachte Fehlerbehandlung. Die Variabelnnamensschreibweise ist für jemanden, der den Standard gewohnt ist, mehr als hinderlich.
Die Funktionen sind meist keine Funktionen, sondern Programmabschnitte mit Namen. Das erkennt man daran, dass sie viel zu viele Parameter und Rückgabewerte haben. Eine Funktion die eine Aufgabe hat, kommt normalerweise auch mit wenigen Parametern und einem Rückgabewert aus.
BlueDogi
User
Beiträge: 30
Registriert: Mittwoch 29. April 2015, 22:25

Vielen Dank!
Ich habe jetzt noch mal ein paar Sachen ausprobiert. Und zwar bin ich jetzt dahintergekommen das wenn Ordner oder Dateien Leerzeichen enthalten der Excel Fehler kommt. In Folge dessen schmeißt Excel dann alle Hyperlinks raus (Ist meine Vermutung) eine Log von Excel habe ich hier http://codeviewer.org/view/code:5325 . Denn Unicode Fehler konnte ich mit einem Präfix R beseitigen:

Code: Alles auswählen

url = R'external:%s' %verzeichnis
Ich muss dazu sagen, dass Loggerkonzept kommt nicht von mir wurde leider so vorgegeben. Das Konzept beinhaltet auch das ich wenn eine Funktion startet den Namen der Funktion schreibe und die Eingangs Parameter… Wenn die Funktion zu Ende ist soll ich dies ebenfalls festhalten so wie die Ausgabe Parameter… Aber das war mir bisher auch zu blöd. :D
Exceptions habe ich mir bisher noch nicht angesehen werde ich machen.

Auf die Idee mit der For-Schleife bin ich leider nicht gekommen habe es aber jetzt umgesetzt:

Code: Alles auswählen

def ErstelleXlsxDatei(Ausgabe_Verzeichnis, Name_Excel_Datei, Verzeichnis_liste):
    XlscDatei = os.path.join(Ausgabe_Verzeichnis, Name_Excel_Datei)
    workbook = xlsxwriter.Workbook(XlscDatei)
    worksheet = workbook.add_worksheet("FindeInDoku")
    Xlsx.info(BeginnXlsx)
    for zeile, verzeichnis in enumerate(Verzeichnis_liste, 1):
        url = R'external:%s' %verzeichnis
        for spalte, pfad in enumerate(PfadNachListe(verzeichnis)[2:]):
            Xlsx.debug("Schreibe zeile %d und Spalte %d in Xlsx Datei." % (zeile, spalte))
            Xlsx.debug("Zellen Inhalt: %s" % pfad)
            Xlsx.debug("Url: " + url)
            worksheet.write_url(row=zeile, col=spalte, url= url, string=pfad)
    Xlsx.info(EndeXlsx)
    workbook.close()
Deine anderen Tipps werde ich auch mal durchgehen.
Sirius3
User
Beiträge: 17747
Registriert: Sonntag 21. Oktober 2012, 17:20

@BlueDogi: das R hilft Dir in Deinem Beispiel hier überhaupt nichts. Das hat nur geholfen, als Du verzeichnis explizit angegeben hattest.
Da es sich bei url um eine URL handelt, müssen Sonderzeichen entsprechend escaped werden:

Code: Alles auswählen

worksheet.write_url(row=zeile, col=spalte, url=urllib.quote(url, safe='/:')), string=pfad)
BlueDogi
User
Beiträge: 30
Registriert: Mittwoch 29. April 2015, 22:25

Ich konnte dein Beispiel nicht direkt benutzen da ich Python 3.4 benutze. Meine Funktion sieht nun wie folgt aus:

Code: Alles auswählen

def ErstelleXlsxDatei(Ausgabe_Verzeichnis, Name_Excel_Datei, Verzeichnis_liste):
    XlscDatei = os.path.join(Ausgabe_Verzeichnis, Name_Excel_Datei)
    workbook = xlsxwriter.Workbook(XlscDatei)
    worksheet = workbook.add_worksheet("FindeInDoku")
    Xlsx.info(BeginnXlsx)
    for zeile, verzeichnis in enumerate(Verzeichnis_liste, 1):
        url = 'external:%s' %verzeichnis
        for spalte, pfad in enumerate(PfadNachListe(verzeichnis)[2:]):
            Xlsx.debug("Schreibe zeile %d und Spalte %d in Xlsx Datei." % (zeile, spalte))
            Xlsx.debug("Zellen Inhalt: %s" % pfad)
            Xlsx.debug("Url: " + url)
            worksheet.write_url(row=zeile, col=spalte, url=urllib.parse.quote(url, safe='/:'), string=pfad)
    Xlsx.info(EndeXlsx)
    workbook.close()
Die Geht aber leider immer noch nicht. Der Fehler ist derselbe wie ohne die Änderung. Der Inhalt der Excel Log ist ebenfalls derselbe…

Um erlich zusein ich habe grade keine Idee mehr…
BlackJack

@BlueDogi: Was genau ist denn jetzt der Fehler und wo tritt der mit welchen Werten auf und welche Typen haben diese Werte?
BlueDogi
User
Beiträge: 30
Registriert: Mittwoch 29. April 2015, 22:25

Also das Skript läuft ohne Fehler durch. Ich habe es noch einmal Hochgeladen (@Sirius3: Leider noch keine Zeit gehappt um deine Tipps umzusetzen)http://codeviewer.org/view/code:532b

Der Fehler kommt wenn ich jetzt die Datei mit EXCEL 2007 öffnen will:
Als erstes kommt die Meldung, dass die Datei beschädigt ist. Und ob ich sie Wiederherstellen möchte. Bei Nein öffnet er die Mappe nicht. Bei Ja bekomme ich die Meldung:

Excel hat die Überprüfung und Reparatur auf Dateiebene abgeschlossen. Einige Teile dieser Arbeitsmappe wurden repariert oder verworfen.
Reparierter Teil: Teil /xl/worksheets/sheet1.xml.
Entferntes Feature: Hyperlinks von /xl/worksheets/sheet1.xml-Part

Mit dem Verweis auf die Log Datei…

Code: Alles auswählen

  <?xml version="1.0" encoding="UTF-8" standalone="yes" ?> 
- <recoveryLog xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main">
  <logFileName>error039720_01.xml</logFileName> 
  <summary>Fehler in Datei 'C:\Users\z002tzbz\Downloads\Python zu Excel\Finde_in_Doku.xlsx'</summary> 
- <additionalInfo>
  <info>Excel hat die Überprüfung und Reparatur auf Dateiebene abgeschlossen. Einige Teile dieser Arbeitsmappe wurden repariert oder verworfen.</info> 
  </additionalInfo>
- <repairedParts summary="Die folgenden Reparaturen wurden durchgeführt:_x000d__x000a__x000d__x000a_">
  <repairedPart>Reparierter Teil: Teil /xl/worksheets/sheet1.xml.</repairedPart> 
  </repairedParts>
- <removedFeatures summary="Folgende Features wurden entfernt:">
  <removedFeature>Entferntes Feature: Hyperlinks von /xl/worksheets/sheet1.xml-Part</removedFeature> 
  </removedFeatures>
  </recoveryLog>
Aber ich kann damit nix anfangen...
Sirius3
User
Beiträge: 17747
Registriert: Sonntag 21. Oktober 2012, 17:20

@BlueDogi: welche Version von xlsxwriter benutzt Du? Und welche Version von Excel?
BlueDogi
User
Beiträge: 30
Registriert: Mittwoch 29. April 2015, 22:25

Ich bin nach der Installation Anleitung Easy_Install vorgegangen.
https://xlsxwriter.readthedocs.org/getting_started.html

wie bekomme ich den raus welche Version das dann ist? Habe in der Startseite gesehen das Excel 2007 unterstützt wird damit war das Thema für mich durch.

Und meine Excel Version ist Excel 2007 SP3 von MS Office Professional Plus 2007.
BlueDogi
User
Beiträge: 30
Registriert: Mittwoch 29. April 2015, 22:25

Hat nicht noch jemand eine Idee? Ich bin jetzt auf Python 2.7.10 gegangen.

Laut dieser Seite : https://readthedocs.org/projects/xlsxwriter/ wird Python 3.4 noch nicht unterstützt aber leider gib es noch keine Besserung.
Sirius3
User
Beiträge: 17747
Registriert: Sonntag 21. Oktober 2012, 17:20

@BlueDogi: wenn ich versuche, Links einzubinden, schaffe ich es nicht, dass Excel Probleme macht. Kannst Du mal ein problematisches XLS und ein lauffähiges Erzeugerprogramm posten?
BlueDogi
User
Beiträge: 30
Registriert: Mittwoch 29. April 2015, 22:25

So habe es jetzt hochgeladen... Ich hoffe das Hilft weiter...
Hyperlink_Fehler.zip
BlueDogi
User
Beiträge: 30
Registriert: Mittwoch 29. April 2015, 22:25

So das Problem hat sich gelöst. Ich habe den Entwickler von XlsxWriter angeschrieben. Dieser hat einen Bug gefunden:
https://github.com/jmcnamara/XlsxWriter/issues/278

Der Bug wurde inzwischen auch auf dem master von github gefixt.
https://github.com/jmcnamara/XlsxWriter

Aber danke für eure Hilfe.
Antworten