Projekte
2.000 Chemikalien, 37 Merkmale: Stoffdaten aus PubChem.
Festanstellung30. Juli 2026
- Bereich
- B2B-Handel
- Umsetzung
- Oktober bis November 2025
- Kompetenz
- Data Engineering
- Stack
- Python · PubChem · pandas · Excel · Git
Ergebnis
- 2.000 CAS-Nummern in 84 Minuten zu 41 Spalten Stoffdaten — 92 % Treffer, kein einziger Abbruch
- Jeder Textwert trägt seine Herkunft mit: Datenbankname und Literaturzitat stehen in der Zelle
- Quellenwahl und Spaltenlayout je Merkmal in einer Konfigurationsdatei statt im Code
- Regressionstest über 15 Stoffe und 223 Felder schützt die Ausgabe vor stillen Änderungen
- Belegte Lückenbilanz: 44 % der gefundenen Stoffe haben keine einzige gemessene Eigenschaft
In drei Sätzen: Ein technischer Fachhändler braucht zu 2.000 Chemikalien belastbare Stoffdaten — Siedepunkt, Dichte, Löslichkeit, Beschreibung, Verwendung — und die stehen frei verfügbar in PubChem, nur eben in einer Datenbank mit 120 Millionen Einträgen und Dutzenden konkurrierenden Quellen pro Merkmal. Daraus ist ein Werkzeug entstanden, das die Liste in 84 Minuten in eine fertig formatierte Arbeitstabelle mit 41 Spalten verwandelt, bei jedem Textwert die Quelle mitschreibt und dort, wo nichts zu holen ist, die Lücke sichtbar lässt statt sie zu füllen. Der interessanteste Teil des Projekts war nicht das Abholen der Daten, sondern die Entscheidung, welcher von zwölf widersprüchlichen Siedepunkten in die Zelle kommt — und die Erkenntnis, dass 44 % der Stoffe überhaupt keine gemessene Eigenschaft in der Datenbank haben.
Hinweis zu diesem Text: Dieses Werkzeug ist im Rahmen meiner Festanstellung entstanden, nicht als Freelance-Auftrag. Der Auftraggeber ist anonymisiert; die Branche — technischer Fachhandel mit Chemikaliensortiment — nicht, weil der Fall ohne sie nicht verständlich wäre. Alle Kennzahlen stammen aus einem echten Vollauf vom 24. Oktober 2025. Die genannten Stoffe und Merkmale sind Beispiele aus PubChem, einer Datenbank des US-amerikanischen NCBI, deren Inhalte gemeinfrei sind.
Die Ausgangslage
Ein mittelständischer technischer Fachhandel führt neben Geräten und
Verbrauchsmaterial ein
Chemikaliensortiment. Jeder dieser Artikel hat eine CAS-Nummer — die
weltweit eindeutige Registriernummer eines Stoffes, 64-19-7 für Essigsäure,
7722-84-1 für Wasserstoffperoxid. Und zu jedem gehören Angaben, die weder im
ERP noch im Lieferantenkatalog stehen: Siedepunkt, Schmelzpunkt, Dichte,
Dampfdruck, Löslichkeit, Aussehen, Lagerstabilität, dazu Molekularformel,
Summenformel, Strukturschlüssel und eine verständliche Beschreibung, was der
Stoff eigentlich ist und wofür er benutzt wird.
Diese Angaben werden an vielen Stellen gebraucht — im Webshop, in Produktdatenblättern, in Katalogtexten, in der internen Auskunft. Bisher entstanden sie so, wie solche Dinge meist entstehen: Jemand öffnet die PubChem-Seite des Stoffes im Browser, sucht die Abschnitte durch, kopiert heraus, was brauchbar aussieht, und fügt es in eine Excel-Tabelle ein. Für einen Stoff dauert das ein paar Minuten. Für zwei Fälle ist das der schnellste Weg. Für 2.000 sind es rund zehn Arbeitswochen, in denen niemand nachvollziehen kann, aus welcher Quelle die Zahl in Zeile 1.487 kommt.
Die Daten selbst waren nie das Problem. PubChem ist eine öffentliche Datenbank der US-amerikanischen National Library of Medicine, gemeinfrei, mit zwei dokumentierten Programmierschnittstellen. Das Problem war der Weg von einer Spalte CAS-Nummern zu einer Tabelle, der man trauen kann.
Warum das kein Web-Scraper ist
Der interne Arbeitstitel des Projekts war „Scraper“, und das ist irreführend. Es wird keine HTML-Seite geparst. PubChem stellt zwei offizielle Schnittstellen bereit, und beide liefern etwas grundlegend Verschiedenes.
PUG-REST liefert die berechneten Eigenschaften: Summenformel, Strukturschlüssel (InChI, InChIKey, SMILES), exakte Masse, topologische polare Oberfläche, Zahl der Wasserstoffbrücken-Donoren, Komplexität, Stereozentren — rund zwei Dutzend Werte, die PubChem selbst aus der Molekülstruktur rechnet. Diese Werte sind immer da, sobald der Stoff überhaupt in der Datenbank ist, und sie sind eindeutig. Es gibt keinen Streit über die Zahl der Schweratome.
PUG-View liefert das Gegenteil: kuratierte Inhalte aus der Literatur, als verschachteltes XML-Dokument, gegliedert wie das Inhaltsverzeichnis eines Handbuchs. Hier stehen Siedepunkt, Dichte, Löslichkeit, Aussehen, Beschreibung und Verwendung — jeweils als Sammlung von Einzelaussagen mit Quellenangabe. Für einen gut dokumentierten Stoff sind das mehrere hundert Kilobyte XML mit Dutzenden Referenzen.
Zwei Web-Scraper für ChemSpider und NIST liegen im Projekt und werden im Normalbetrieb nicht benutzt. Sie sind als Reserve entstanden, für den Fall, dass PubChem eine Größe nicht führt. Der Fall trat nicht ein, und deshalb sind sie geblieben, was sie sind: ungenutzter Code, den ich in einem Aufräumdurchgang eher lösche als pflege.
Das eigentliche Problem: welcher Wert von welcher Quelle
Wer noch nie in ein PUG-View-Dokument geschaut hat, stellt sich den Abschnitt „Boiling Point“ als ein Feld mit einer Zahl vor. Er ist eine Liste. Für einen verbreiteten Stoff stehen dort ein halbes Dutzend Aussagen nebeneinander, aus verschiedenen Quellen, in verschiedenen Einheiten, bei verschiedenen Drücken, teils als Zahl, teils als Satz. Dieselbe Struktur gilt für Dichte, Löslichkeit, Dampfdruck, Aussehen, Beschreibung und Verwendung.
Damit ist die Kernfrage des Projekts gestellt, und sie ist keine technische: Welche dieser Aussagen kommt in die Zelle?
„Die erste“ ist die naheliegende Antwort und die schlechteste. Die Reihenfolge im XML ist keine Rangfolge — sie ist die Reihenfolge, in der PubChem seine Quellen einsammelt. Wer immer die erste nimmt, bekommt eine Tabelle, in der die Herkunft der Werte von Stoff zu Stoff springt, ohne dass es jemandem auffällt.
Die Antwort im Werkzeug ist eine Quellenrangfolge je Merkmal, festgelegt in der Konfiguration:
BoilingPoint:
extraction_strategy: single_by_source_priority
source_priority:
- Hazardous Substances Data Bank (HSDB)
- CAMEO Chemicals
fallback_to_first: true
Für die physikalisch-chemischen Größen steht die HSDB ganz oben — eine Datenbank der National Library of Medicine, in der Werte redaktionell geprüft und mit Originalzitat versehen sind. Danach kommt CAMEO Chemicals, eine Gefahrstoffdatenbank der US-Küstenwache und der Umweltbehörde. Bei Dampfdruck und Dampfdichte liegen dazwischen noch die Internationalen Chemikalien-Sicherheitskarten des IPCS. Für die beschreibenden Felder gilt eine andere Rangfolge: dort liefert ChEBI verständlichere Sätze als eine Gefahrstoffdatenbank.
Drei Details an dieser Mechanik haben mehr Zeit gekostet als der ganze Rest der Auswahllogik.
Erstens: Quellennamen kann man nicht raten. Die erste Fassung der
Rangfolge enthielt HSDB — die Abkürzung, unter der jeder Chemiker diese
Datenbank kennt. Sie traf nie zu, denn im XML heißt die Quelle
Hazardous Substances Data Bank (HSDB). Noch deutlicher bei den
Sicherheitskarten: fachlich „ILO-WHO ICSC“, in den Daten
IPCS,CEC; International Chemical Safety Card. Der Effekt war jedes Mal
derselbe und heimtückisch: Die Rangfolge griff nicht, die Rückfallregel nahm
den ersten Treffer, und das Ergebnis sah völlig plausibel aus. Nur eben aus der
falschen Quelle. Die Namen mussten aus den Daten selbst herausgelesen werden,
nicht aus dem Fachwissen.
Zweitens: die Quellenzuordnung entsteht pro Stoff neu. Im XML trägt jede Aussage keine Quelle, sondern eine Referenznummer. Welche Nummer welche Quelle ist, steht in einem separaten Block am Dokumentende — und die Nummerierung ist pro Stoff anders. Referenz 5 ist bei Essigsäure eine andere Datenbank als bei Wasserstoffperoxid. Also wird für jeden Stoff zuerst die komplette Zuordnung Nummer → Quellenname aufgebaut und erst danach ausgewählt. Eine einmal fest verdrahtete Nummerntabelle hätte über 2.000 Stoffe hinweg zuverlässig Unsinn produziert.
Drittens: exakte Überschriftentreffer, keine Teiltreffer. Die Abschnitte
werden über ihre Überschrift im Inhaltsverzeichnis gefunden. Ein Teiltreffer
auf Density findet auch Vapor Density — und dann steht die Dampfdichte in
der Dichtespalte. Die Suche vergleicht deshalb den ganzen Text, nur
groß-klein-unempfindlich. Das ist eine Zeile Code und der Unterschied zwischen
einer brauchbaren und einer wertlosen Spalte.
Dazu kommen Ausschlussmuster pro Merkmal, weil manche Quellen technische
Artefakte in die Beschreibungsfelder schreiben. Bei der Beschreibung fliegen
Einträge mit See other relationships, PEPTIDE und der Zeichenfolge $$$$
heraus — letztere ein Trennzeichen aus dem SDF-Dateiformat, das gelegentlich in
Textfelder gerät.
Verworfen: die Zahl mit Einheit
Die erste Fassung war ehrgeiziger. Siedepunkt, Dampfdruck, Dichte und
Löslichkeit sollten als Zahl plus Einheit in getrennten Spalten stehen,
sauber normiert: Temperaturen in °C, Drücke in mmHg, Dichten in g/cm³,
Löslichkeiten in g/L. Dafür gibt es eine ganze Einheitenverarbeitung —
Schreibweisen werden normalisiert (g cm-3, g/cm3 und g/cm³ sind dasselbe),
bevorzugte und akzeptable Einheiten stehen pro Größenkategorie in der
Konfiguration, und Fahrenheit-Werte werden nach Celsius umgerechnet, wenn kein
Celsius-Wert vorliegt.
Der Ansatz ist an den echten Daten gescheitert. Drei Beispiele aus dem Dampfdruck-Abschnitt, unverändert so, wie sie in PubChem stehen:
11.4 mmHg at 68 °F ; 20 mmHg at 86 °F (NTP, 1992)
Vapor pressure, kPa at 20°C: 48 (25%)
0.33 [mmHg]
Die erste Zeile enthält zwei Messungen bei zwei Temperaturen. Die zweite eine
Angabe für eine 25-prozentige Lösung. Die dritte einen Wert ohne
Bezugstemperatur. Aus jeder dieser Zeilen kann man eine Zahl herausschneiden —
11.4, 48, 0.33 — und jede dieser Zahlen ist ohne ihren Kontext
falsch nutzbar. Ein Dampfdruck ohne Temperatur ist keine Angabe, sondern
eine Einladung zum Fehler.
Die Entscheidung war deshalb, bei allen literaturbasierten Größen den Originaltext unverändert in die Zelle zu schreiben. Die Spalte ist breiter, sie lässt sich nicht sortieren, und für eine Rechnung muss ein Mensch hinschauen. Genau das ist der Punkt: Diese Werte sind nicht zum Rechnen da, sondern zum Nachlesen — und wer sie doch rechnen will, sieht sofort, welche Bedingungen dazugehören.
Die Einheitenverarbeitung ist damit auf die berechneten Größen geschrumpft: exakte Masse und monoisotopische Masse in Dalton, polare Oberfläche in Ångström². Der Code für Temperatur, Druck, Dichte und Löslichkeit steht noch da, seine Zuordnungslisten sind leer. Das ist keine Eleganz, sondern eine Altlast — aber eine bewusste: Sollte eine Größe später doch numerisch gebraucht werden, ist der Weg dorthin einen Konfigurationseintrag lang.
Merkmale als Konfiguration, nicht als Code
Ein Merkmal ist in diesem Werkzeug kein Stück Programm, sondern ein Eintrag in einer YAML-Datei. Dort steht alles, was das Merkmal ausmacht: aus welchem XML-Abschnitt es kommt, mit welcher Strategie es ausgelesen wird, welche Quellen in welcher Reihenfolge gelten, was ausgeschlossen wird, ob der Wert als HTML mit Quellenangabe formatiert wird — und gleich daneben, wie die Spalte in Excel aussieht: Breite, Kopffarbe, Ausrichtung, Textumbruch.
Description:
data_type: text
column_width: 40.0
header_color: light_green
align: left
text_wrap: true
extraction_strategy: description_record
source_priority: [CAMEO Chemicals, ChEBI]
exclude_patterns: [See other relationships, PEPTIDE, "$$$$"]
html_format: true
source_css_class: PubChem-source-green
reference_css_class: PubChem-source-gray
Hinter extraction_strategy stehen zehn austauschbare Auslesestrategien mit
gemeinsamer Schnittstelle: die ersten N Einträge, der längste Text, der Wert
nach Quellenrangfolge, dieselbe Auswahl mit HTML-Formatierung, ein Sonderfall
für den Beschreibungsabschnitt und ein weiterer für den Verwendungsabschnitt,
der im XML nicht am erwarteten Ort liegt. Eine kleine Registrierungsklasse
liefert zum Namen aus der Konfiguration die passende Strategie.
Der Nutzen dieser Trennung ist im Alltag banal und deshalb wertvoll: Die Fachabteilung wünscht sich, dass beim Aussehen künftig die HSDB Vorrang hat. Das ist eine geänderte Zeile in einer Textdatei, kein Programmiertermin. Auch die Spaltenreihenfolge kommt aus dieser Datei — die Reihenfolge der Einträge ist die Reihenfolge in Excel. Für eine 41-spaltige Tabelle, in der Anwender bestimmte Blöcke nebeneinander erwarten, ist das die häufigste Änderungsanfrage überhaupt.
Auch die CSS-Klassennamen für die Quellenauszeichnung stehen in der Konfiguration. Das klang zunächst nach Übertreibung — bis eine Anpassung an das Shop-Stylesheet nötig wurde und der Klassenname vorher an zwei Stellen im Code verdrahtet war.
Die Ausgabe ist das Produkt
Bei einem Werkzeug wie diesem ist die Versuchung groß, die Arbeit für getan zu halten, sobald die Daten im Speicher stehen. Tatsächlich entscheidet die Ausgabedatei darüber, ob das Ganze benutzt wird. Sie geht an Menschen, die Excel öffnen und mit 41 Spalten zurechtkommen müssen.
Die Datei hat vier Blätter. Data trägt die Nutzdaten, eine Zeile je CAS-Nummer. Units_Summary protokolliert für jeden Wert mit Einheit, welche Einheit gewählt wurde und welche zur Auswahl standen — im Vollauf 5.523 Zeilen. Processing_Stats hält die Kennzahlen des Durchlaufs fest. Resume_Data enthält den Zustand, aus dem sich ein abgebrochener Lauf fortsetzen lässt.
Auf dem Datenblatt steckt die Arbeit in Kleinigkeiten, die alle denselben Zweck haben — eine sehr breite Tabelle benutzbar zu halten:
- Der Kopf ist um 90° gedreht und die erste Zeile eingefroren. Bei 41 Spalten ist ein waagerechter Kopf entweder unlesbar abgeschnitten oder die Spalten werden absurd breit.
- Blockfarben gruppieren die Spalten: Bezeichner, Beschreibungen, physikalisch-chemische Größen, Strukturschlüssel, Molekülkennzahlen. Neun Farben, alle in der Konfiguration hinterlegt.
- Autofilter über den gesamten Bereich, weil die erste Frage an so eine Tabelle immer „zeig mir nur die mit …“ ist.
- Einheitenspalten sind ausgeblendet, nicht gelöscht. Drei Merkmale haben eine eigene Einheitenspalte; sie wird auf Breite null gesetzt und versteckt. Wer sie braucht, holt sie hervor; wer nicht, sieht sie nie.
- Die Zählspalte „Found“ steht ganz vorn, gelb, und sagt, wie viele der 37
Merkmale bei diesem Stoff tatsächlich gefüllt sind. Sie zählt bewusst nur die
Werte mit echtem Inhalt und lässt „nicht gefunden“, „nicht versucht“ und
Fehlerzustände außen vor. Eine Zeile mit
Found = 8ist damit als dünn erkennbar, ohne dass jemand 37 Spalten durchscrollt.
Der wichtigste Teil steht in den Textzellen selbst. Beschreibung, Verwendung und Wirkmechanismus sind nicht nackte Sätze, sondern kleine HTML-Blöcke aus drei Absätzen: der Inhalt, darunter das Literaturzitat in Grau, darunter der Quellenname in Grün. Damit reist die Herkunft mit dem Wert — auch dann, wenn jemand die Zelle in ein Datenblatt kopiert. Im Vollauf tragen alle 1.457 Beschreibungen einen Quellennamen, 716 der 1.118 Verwendungstexte zusätzlich ein Zitat.
Die Reihenfolge Grau-vor-Grün war eine späte Korrektur und ist kein Geschmacksurteil: Das Zitat gehört näher an die Aussage, der Datenbankname ist die grobere Angabe und steht deshalb zuletzt. Da beide Klassennamen aus der Konfiguration kommen, war der Wechsel eine Änderung an einer Stelle statt an vier.
Für das Zitat gibt es eine dreistufige Rückfallkette, weil PubChem Literaturangaben nicht einheitlich ablegt: erst das direkte Referenzfeld, dann die Zitatangabe einer erweiterten Referenz, dann die Zitatangabe innerhalb ihres Treffer-Blocks. Ohne diese Kette blieb bei einem Teil der Stoffe das Zitat leer, obwohl es im Dokument stand — nur eine Ebene tiefer.
Jede Zelle kann zusätzlich einen Kommentar mit dem Auswahlstatus tragen: kam der Wert aus einer bevorzugten Quelle, aus einer Alternative, oder über die Rückfallregel. Für den 2.000-Zeilen-Lauf ist das abgeschaltet — Zehntausende Zellkommentare machen die Datei zäh, und der Nutzen sinkt mit der Zeilenzahl. Für einen Prüflauf über 20 Stoffe ist es dagegen die schnellste Art, die Auswahlregeln zu kontrollieren.
Was der Vollauf über die Datenbank verrät
Der Lauf vom 24. Oktober 2025: 2.000 CAS-Nummern, 1 Stunde 23 Minuten, 2,51 Sekunden je Stoff, kein einziger Fehler. Für 1.841 Stoffe (92,0 %) fand PubChem eine Verbindungsnummer, für 159 nicht.
Diese Kennzahlen sind die uninteressanten. Interessant wird es, wenn man auszählt, welche Merkmale tatsächlich gefüllt sind — und dafür ist ein Lauf über 2.000 Stoffe genau das richtige Werkzeug. Die Trefferquoten, bezogen auf alle 2.000 Zeilen:
| Merkmal | gefüllt | Anteil |
|---|---|---|
| Molekularformel, Strukturschlüssel, Molekülkennzahlen | 1.841 | 92,0 % |
| IUPAC-Name | 1.818 | 90,9 % |
| Beschreibung | 1.457 | 72,9 % |
| Verwendung | 1.118 | 55,9 % |
| Verteilungskoeffizient (XLogP3) | 995 | 49,8 % |
| Löslichkeit | 928 | 46,4 % |
| Schmelzpunkt | 897 | 44,9 % |
| Aussehen / Form | 734 | 36,7 % |
| Dichte | 621 | 31,1 % |
| Dampfdruck | 589 | 29,4 % |
| Siedepunkt | 545 | 27,3 % |
| Wirkmechanismus | 466 | 23,3 % |
| Stabilität / Haltbarkeit | 435 | 21,8 % |
| Dampfdichte | 251 | 12,6 % |
Die Tabelle zerfällt sichtbar in zwei Hälften, und die Trennlinie ist keine technische, sondern eine erkenntnistheoretische. Alles, was PubChem rechnet, liegt bei 92 % — also bei 100 % der gefundenen Stoffe. Alles, was PubChem aus Literatur sammelt, liegt zwischen 12 und 47 %. Kein Stück Code kann diese Lücke schließen, denn sie ist nicht im Werkzeug, sondern in der Welt: Für Zehntausende von Handelschemikalien hat nie jemand einen Siedepunkt in eine kuratierte Datenbank eingetragen.
Zwei Zahlen machen das noch deutlicher. Von den 1.841 gefundenen Stoffen haben 805 — also 43,7 % — keine einzige der acht gemessenen Eigenschaften. Umgekehrt haben nur 701 Stoffe (38,1 %) mindestens vier davon. Die Zählspalte sagt dasselbe pro Zeile: Bei den gefundenen Stoffen liegt sie im Mittel bei 29 von 37 Merkmalen, im schlechtesten Fall bei 23, im besten bei 36. Unter 23 kommt niemand, weil die berechneten Größen immer da sind — das ist der Sockel, auf dem jede Zeile steht.
Für die Auftraggeberseite war das die eigentlich wertvolle Auskunft, und sie war nicht bestellt: Der Aufwand, alle 2.000 Artikel aus offenen Daten mit vollständigen physikalischen Kennwerten zu versehen, ist nicht eine Frage des besseren Werkzeugs. Er endet bei etwa einem Drittel des Sortiments. Der Rest braucht Herstellerdatenblätter oder eine kostenpflichtige Fachdatenbank. Diese Antwort ist unangenehm und billiger als ein zweiter Anlauf mit derselben Quelle.
Ein Nebenbefund, der beim Nachzählen auffiel: Die 1.841 Treffer verweisen auf nur 1.821 verschiedene PubChem-Einträge. 18 Einträge werden von mehr als einer CAS-Nummer getroffen. Die Beziehung CAS-Nummer zu Datenbankeintrag ist also nicht eineindeutig — Hydrate, Salze, alte und neue Registrierungen desselben Stoffes können auf denselben Eintrag zeigen. Wer aus dieser Tabelle heraus Artikel zusammenführen wollte, müsste das wissen.
Wie man so etwas ändert, ohne es zu brechen
Ein Werkzeug, dessen Ausgabe niemand Zeile für Zeile prüfen kann, hat ein eigenes Risiko: Änderungen brechen die Ausgabe still. Man ändert eine Rangfolge, der Lauf läuft durch, die Datei sieht aus wie immer — und in 300 Zeilen steht jetzt ein anderer Wert. Ohne Vergleichsmaßstab merkt das niemand.
Die Antwort darauf ist ein Vergleichsdatensatz: 15 Stoffe, deren Ausgabe von Hand geprüft wurde, mit allen Feldern als Erwartungswert festgehalten. Dazu zwei Prüfläufe unterschiedlicher Tiefe — ein schneller über einen Stoff für die Kontrolle zwischendurch, und ein vollständiger über alle 15 Stoffe und 223 Felder vor jeder Übernahme. Nicht nur die Werte werden verglichen, sondern auch die HTML-Struktur und die Reihenfolge der Quellenabsätze.
Zusätzlich gibt es einen Vergleich zweier Ausgabedateien, der Unterschiede nach
Art gruppiert. Nach einer Änderungsrunde sah das Ergebnis so aus: 182
Formatänderungen bei Zahlen (0.0 → 0), 14 bei einem Wahrheitswert
(1.0 → True), 14 gewechselte Beschreibungsquellen, vier ergänzte Zitate,
eine geänderte Absatzreihenfolge — und null unerwartete Abweichungen. Der
Wert dieser Auszählung liegt nicht im Ergebnis, sondern in der Möglichkeit, es
überhaupt zu behaupten.
Diese Absicherung ist nicht aus Ordnungsliebe entstanden, sondern nach einem
Vorfall, der genau die Schwachstelle des Konfigurationsansatzes traf. Ich hatte
den Hauptschlüssel in der Konfigurationsdatei umbenannt — von
properties_config auf das schönere properties. Der Code las weiterhin den
alten Namen, fand ihn nicht und behandelte das als „keine Merkmale
konfiguriert“. Das Programm lief durch, das Protokoll meldete 15 erfolgreich
verarbeitete Stoffe, und die erzeugte Excel-Datei hatte null Zeilen und null
Spalten.
Der zweite Teil desselben Vorfalls war subtiler. Ein Prüfskript schrieb die Konfiguration nach einer Änderung zurück — mit der Standardeinstellung der YAML-Bibliothek, die Schlüssel alphabetisch sortiert. Da die Reihenfolge der Einträge die Spaltenreihenfolge ist, war die Tabelle danach zwar vollständig, aber alphabetisch sortiert statt fachlich gruppiert. Aus einem stillen Fehler wurden zwei.
Die Lehren sind unspektakulär und haben sich beide bewährt: Wer die Konfiguration zur einzigen Wahrheit macht, muss einen fehlenden Schlüssel als Abbruch behandeln, nicht als leere Liste. Und jede Stelle, die Konfiguration schreibt, muss die Reihenfolge erhalten. Beides ist heute so, und der Vergleichsdatensatz würde beides sofort zeigen.
Betrieb: Prüfziffern, Doppelte, Wiederaufnahme
Drei Dinge entscheiden bei einem Lauf über 2.000 Netzabfragen darüber, ob er lästig ist oder nicht.
Vor dem ersten Aufruf wird geprüft. CAS-Nummern aus einer Arbeitstabelle sind selten sauber: Leerzeichen, doppelte Bindestriche, verlorene Trennzeichen aus einer Excel-Zellformatierung. Der Prüfer normalisiert das und rechnet anschließend die Prüfziffer nach — CAS-Nummern haben eine, mit positionsgewichteter Summe modulo zehn. Eine Nummer, die diese Prüfung nicht besteht, ist ein Tippfehler und wird gar nicht erst abgefragt. Das kostet Millisekunden und spart Netzaufrufe, die garantiert nichts finden.
Doppelte werden entfernt, die Reihenfolge bleibt. Die Eingabeliste kommt aus einer Artikeltabelle, in der derselbe Stoff mehrfach vorkommt — verschiedene Gebindegrößen, gleiche Chemikalie. Entdoppelt wird ordnungserhaltend, damit die Ausgabe in derselben Reihenfolge steht wie die Eingabe; das ist die Voraussetzung dafür, dass jemand beide Dateien nebeneinanderlegen kann.
Der Zustand wird laufend gesichert. Alle zehn Stoffe schreibt das Werkzeug seinen Fortschritt weg, alle hundert einen Abzug, von dem es fünf behält. Wird der Lauf abgebrochen — Tastendruck, Netzstörung, Neustart — setzt er auf Wunsch an der Stelle fort, an der er stehen geblieben ist, und schon verarbeitete Stoffe gehen nicht zweimal ins Netz. Bei 84 Minuten Laufzeit ist das der Unterschied zwischen einer Unterbrechung und einem verlorenen Vormittag.
Dazu kommen die üblichen Rücksichten gegenüber einer fremden, kostenlosen Schnittstelle: eine halbe Sekunde Pause zwischen den Aufrufen, 30 Sekunden Zeitlimit, drei Versuche mit wachsender Wartezeit. Ein „nicht gefunden“ gilt sofort als endgültig und wird nicht wiederholt — es ist eine Antwort, kein Fehler. Das Ergebnis dieser Zurückhaltung steht in der Statistik: 0 Fehler auf 2.000 Abfragen.
Was ich anders machen würde
Der Auswahlstatus ist keiner. Jeder Wert trägt eine Statusangabe, die sagen
soll, wie er zustande kam: bevorzugte Einheit, Alternative, Rückfall. Im
Vollauf steht in allen 5.523 Zeilen des Einheitenprotokolls derselbe Wert —
fallback. Der Grund ist harmlos: PubChem liefert die berechneten Größen als
nackte Zahl ohne Einheit, die Einheit wird also aus einer festen Zuordnung
ergänzt, und damit greift nie der Zweig „bevorzugte Einheit gefunden“. Eine
Statusangabe, die immer denselben Wert hat, ist keine Information, sondern
Rauschen. Richtig wäre ein eigener Status „Einheit ergänzt“ — dann steht dort
eine Aussage statt einer irreführenden.
Die Reservescraper gehören gelöscht. Zwei Web-Scraper für ChemSpider und NIST liegen im Projekt, werden initialisiert, bei jedem Start auf Erreichbarkeit geprüft und nie benutzt. Ungenutzter Code, der beim Start Zeit kostet, ist keine Reserve, sondern eine Behauptung.
Das Verzeichnis ist ein Vorwurf. Rund fünfzig Prüf- und Fehlersuchskripte liegen im Projektstammverzeichnis statt bei den Tests, daneben ein Dutzend Berichtsdateien mit Titeln, die alle „endgültig“ behaupten. Der Code ist in Ordnung, das Drumherum nicht. So etwas entsteht, wenn jede Änderung sofort überprüft und die Prüfung danach nicht weggeräumt wird — und es fällt genau in dem Moment auf, in dem jemand anderes das Projekt öffnet.
Was ich daraus mitnehme
Bei fremden Daten ist die Auswahlregel das Produkt. Das Abholen von Daten über eine dokumentierte Schnittstelle ist Handwerk und in einem Tag erledigt. Die Frage, welcher von zwölf widersprüchlichen Werten der richtige ist, ist die eigentliche Arbeit — und sie ist keine Programmierfrage, sondern eine fachliche, die man mit der Fachabteilung entscheidet und dann in Konfiguration gießt.
Herkunft gehört an den Wert, nicht in die Dokumentation. Eine Zahl in einer Zelle ohne Quelle ist in dem Moment wertlos, in dem jemand sie anzweifelt — und angezweifelt wird sie garantiert. Die Quelle in derselben Zelle mitzuführen kostet zwei Absätze HTML und erspart die Rückfrage „wo kommt das her?“ vollständig.
Normieren kann Information zerstören. Aus „11,4 mmHg bei 20 °C; 20 mmHg bei 30 °C“ die Zahl 11,4 zu machen sieht aus wie Datenqualität und ist Informationsverlust. Wo der Kontext den Wert erst nutzbar macht, ist der Originaltext die richtige Speicherform — auch wenn die Spalte dadurch hässlich wird.
Ein Lauf über alle Daten ist selbst ein Befund. Die wertvollste Erkenntnis des Projekts war keine gelieferte Zeile, sondern die Auszählung: 44 % der Stoffe haben keine einzige gemessene Eigenschaft. Diese Zahl beendet eine Diskussion — nämlich die, ob man mit mehr Aufwand nicht doch auf Vollständigkeit kommt. Wer misst, was fehlt, spart die zweite Runde.
Was davon für kleine Betriebe übrig bleibt
2.000 Chemikalien und eine amerikanische Forschungsdatenbank klingen speziell. Das Muster darunter ist es nicht: Irgendwo außerhalb des eigenen Systems liegen Daten, die man braucht, und jemand kopiert sie von Hand hinein.
Das kommt in fast jedem Betrieb vor. Lieferanten-Datenblätter, aus denen Katalogtexte entstehen. Ein öffentliches Register, gegen das Kundenadressen geprüft werden. Ein Portal, aus dem Bestellstände abgetippt werden. Preis- und Verfügbarkeitslisten, die als PDF kommen. Die Arbeit ist immer dieselbe: öffnen, suchen, kopieren, einfügen — und niemand weiß hinterher, aus welchem Stand die Angabe stammt.
Drei Dinge sind in solchen Fällen fast immer die richtige Antwort, unabhängig von der Betriebsgröße:
- Die Quelle mit übernehmen, nicht nur den Wert. Ohne Herkunft ist jede übernommene Angabe eine Behauptung, die sich später niemand traut zu verwenden.
- Die Auswahlregel aufschreiben, wo sie jemand ändern kann. Wenn „welche Quelle gilt“ im Programmcode steht, ist jede fachliche Änderung ein Entwicklertermin. In einer Textdatei ist sie eine Zeile.
- Zählen, was fehlt. Eine Lückenübersicht ist kein Schönheitsfehler des Ergebnisses, sondern das Ergebnis: Sie sagt, ob der Weg trägt oder ob eine andere Quelle her muss.
Der Unterschied zum Fall hier ist der Umfang, nicht der Ansatz. Für 200 Artikel statt 2.000 ist es dasselbe Werkzeug mit einer kürzeren Eingabeliste — und genau der Umfang, den ich als Automatisierungspaket für kleine Betriebe anbiete.
Wenn Ihnen beim Lesen eine Datenquelle aus dem eigenen Betrieb eingefallen ist, aus der jemand regelmäßig abtippt: Offen für eine Festanstellung in Data Analytics und Automatisierung? Kontakt aufnehmen.