abook Adressen importieren

abook Addressbuch unter Linux

Was ist das doch manchmal schwierig Informationen zu finden. Zum Glück kann man ja heute mithilfe von so LLMs, auch in den Gebieten fischen, in denen man sich nicht so gut auskennt. Deshalb lasse ich Euch hier mal teilhaben.

Ausgangspunkt

Ich habe mir alle Kontakte aus meinem Google Konto, von Apple Kontakte, in eine vcf-Datei exportieren lassen. Diese Daten würde ich nun gern in abook importieren, damit ich die Adressen z.B. in neomutt weiterverwenden kann.

Hier einmal der Code komplett mit Anmerkungen, welche Funktion, was macht.

Script für die Konvertierung >folded
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
#!/usr/bin/env python

import sys # Importiert das sys-Modul für die Arbeit mit Systemparametern
import csv # Importiert das csv-Modul für die Arbeit mit CSV-Dateien
from vobject import readComponents # Importiert die Funktion readComponents aus dem vobject-Modul zur Verarbeitung von vCard-Daten

# Definieren Sie den Pfad zur vcf-Datei und die Ausgabe-Addressbook-Datei
vcf_file = '~/Downloads/vcard-export/alle-kontakte.vcf' # Pfad zur vcf-Datei
addressbook_file = '~/Downloads/vcard-export/addressbook.abook' # Pfad zur Ausgabe-Datei im abook-Format

try:
with open(vcf_file, 'r') as f: # Öffnet die vcf-Datei im Lesemodus
vcards = list(readComponents(f)) # Liest und parst die vCard-Daten aus der Datei
except Exception as e: # Fehlerbehandlung bei Dateizugriffsfehlern
print(f"Error reading {vcf_file}: {e}") # Gibt eine Fehlermeldung aus, falls ein Fehler auftritt
sys.exit(1) # Beendet das Programm mit einem Fehlercode

# Funktion zur Extraktion des ersten Werts eines Attributs aus einem vCard-Objekt
def get_first_value(obj, attribute):
if hasattr(obj, attribute): # Prüft, ob das Attribut existiert
attr = getattr(obj, attribute) # Holt das Attribut
if isinstance(attr, list): # Prüft, ob das Attribut eine Liste ist
return attr[0].value # Gibt den ersten Wert der Liste zurück
return attr.value # Gibt den Wert des Attributs zurück
return 'N/A' # Gibt 'N/A' zurück, falls das Attribut nicht existiert

# Funktion zur Extraktion aller Werte eines Attributs aus einem vCard-Objekt
def get_all_values(obj, attribute):
if hasattr(obj, attribute): # Prüft, ob das Attribut existiert
attr = getattr(obj, attribute) # Holt das Attribut
if isinstance(attr, list): # Prüft, ob das Attribut eine Liste ist
return ', '.join([a.value for a in attr]) # Gibt alle Werte als kommaseparierte Zeichenkette zurück
return attr.value # Gibt den Wert des Attributs zurück
return 'N/A' # Gibt 'N/A' zurück, falls das Attribut nicht existiert

# Funktion zur Extraktion einer spezifischen Adresskomponente aus einem adr-Objekt
def get_address_component(adr, component):
return getattr(adr, component, '') # Gibt die spezifische Adresskomponente zurück oder ein leeres Zeichen, falls sie nicht existiert

# Funktion zur Extraktion der Adressinformationen aus einem vCard-Objekt
def get_address(vcard):
if hasattr(vcard, 'adr'): # Prüft, ob das adr-Attribut existiert
adr = vcard.adr.value # Holt das adr-Attribut
address = get_address_component(adr, 'street') # Extrahiert die Straßenadresse
address2 = '' # Setzt address2 auf leer, da es nicht in vCard enthalten ist
city = get_address_component(adr, 'city') # Extrahiert die Stadt
state = get_address_component(adr, 'region') # Extrahiert den Staat/Region
zip_code = get_address_component(adr, 'code') # Extrahiert die Postleitzahl
country = get_address_component(adr, 'country') # Extrahiert das Land
return address, address2, city, state, zip_code, country # Gibt die Adresskomponenten zurück
return 'N/A', 'N/A', 'N/A', 'N/A', 'N/A', 'N/A' # Gibt 'N/A' zurück, falls die Adresse nicht existiert

# Öffnet die abook-Datei im Schreibmodus
with open(addressbook_file, 'w') as abookfile:
# Schreibt die Kopfzeilen der abook-Datei
abookfile.write('[format]\n')
abookfile.write('program=abook\n')
abookfile.write('version=0.6.1\n\n')

# Iteriert über die vCards und schreibt ihre Daten in die abook-Datei
for i, vcard in enumerate(vcards):
name = get_first_value(vcard, 'fn') # Holt den Namen
email = get_all_values(vcard, 'email') # Holt alle E-Mail-Adressen
address, address2, city, state, zip_code, country = get_address(vcard) # Holt die Adressinformationen
phone = get_all_values(vcard, 'tel') # Holt alle Telefonnummern
workphone = get_first_value(vcard, 'workphone') # Holt die geschäftliche Telefonnummer
fax = get_first_value(vcard, 'fax') # Holt die Faxnummer
mobile = get_first_value(vcard, 'cell') # Holt die Handynummer
nickname = get_first_value(vcard, 'nickname') # Holt den Spitznamen
url = get_first_value(vcard, 'url') # Holt die URL
notes = get_first_value(vcard, 'note') # Holt die Notizen
anniversary = get_first_value(vcard, 'bday') # BDAY wird als anniversary gespeichert
groups = get_all_values(vcard, 'categories') # Holt alle Gruppen

# Schreibt die vCard-Daten in das abook-Format
abookfile.write(f'[{i}]\n')
abookfile.write(f'name={name}\n')
abookfile.write(f'email={email}\n')
if address != 'N/A':
abookfile.write(f'address={address}\n')
if address2 != 'N/A':
abookfile.write(f'address2={address2}\n')
if city != 'N/A':
abookfile.write(f'city={city}\n')
if state != 'N/A':
abookfile.write(f'state={state}\n')
if zip_code != 'N/A':
abookfile.write(f'zip={zip_code}\n')
if country != 'N/A':
abookfile.write(f'country={country}\n')
if phone != 'N/A':
abookfile.write(f'phone={phone}\n')
if workphone != 'N/A':
abookfile.write(f'workphone={workphone}\n')
if fax != 'N/A':
abookfile.write(f'fax={fax}\n')
if mobile != 'N/A':
abookfile.write(f'mobile={mobile}\n')
if nickname != 'N/A':
abookfile.write(f'nick={nickname}\n')
if url != 'N/A':
abookfile.write(f'url={url}\n')
if notes != 'N/A':
abookfile.write(f'notes={notes}\n')
if anniversary != 'N/A':
abookfile.write(f'anniversary={anniversary}\n')
if groups != 'N/A':
abookfile.write(f'groups={groups}\n')
abookfile.write('\n') # Fügt eine Leerzeile nach jedem Eintrag hinzu

print(f"Successfully written data to {addressbook_file}") # Gibt eine Erfolgsnachricht aus

# Ende des Skripts

Das Ergebnis sieht dann wie folgt aus. So kann man mit der Datei weiterarbeiten. Das Format ist gleich korrekt und wird von abook ohne Murren verarbeitet. Ich hatte mehrere Versuche und bei den ersten wurde die Datei direkt gelöscht. Das lag offensichtlich daran, dass ich Probleme mit dem Format hatte.

1
2
3
4
5
6
7
8
9
10
11
12
# abook addressbook file

[format]
program=abook
version=0.6.1


[0]
name=Autohaus Ludwigshaven
email=N/A
address=N/A
phone=+490026950000

In einer der ersten Versionen wurden die Geburtstage nicht korrekt übernommen. Die habe ich in einer der Iterationen dann von BDAY in das Feld Anniversary übergeben. So passte das für mich besser.

Author

Peter Kursikowski

Posted on

2024-07-10

Updated on

2024-07-11

Licensed under

Kommentare