Rens en CSV-fil fra CRM'et
Vask tusindvis af kundeadresser fra en CSV-eksport, enten med et bulk-job på serveren eller med din egen løkke over datavask.
Adresser i et CRM forfalder: kunder flytter, veje bliver omdøbt, og halvdelen blev tastet ind i hast. Før en kampagne eller en migrering vil du vide, hvilke rækker der er gode, hvilke der kan rettes automatisk, og hvilke et menneske skal kigge på.
Der er to veje. POST /api/v1/bulk/cleanse tager hele filen og kører datavask på hver række på serveren. En løkke over GET /datavask/adresser i din egen kode giver dig fuld kontrol over hvert kald. Begge giver kategorierne A, B og C. Afsnittet Hvilken skal du vælge? sammenligner dem.
Bulk-jobbet
Krav til filen
- Filnavnet skal ende på
.csv, ellers svarer API'et400med kodencsv_required. - Højst 50 MB. En større fil giver
413med kodenfile_too_large. - Semikolon, komma eller tabulator som skilletegn. Jobbet finder selv skilletegnet og bruger det samme i resultatfilen. Et BOM-tegn fra Excel fjernes, og gamle Excel-filer i Windows-1252 læses også.
- Første linje er kolonnenavne, uden forskel på store og små bogstaver. Standardnavnene er
vejnavn,husnr,etage,dør(ellerdoer),postnrogpostnrnavn. Har du hele adressen i én kolonne, så kald denbetegnelse. Hedder dine kolonner noget andet, så send navnene i formfelternevejnavn_col,husnr_col,etage_col,doer_col,postnr_col,postnrnavn_cologbetegnelse_col.
Send filen
curl -s "https://api.danadresse.dk/api/v1/bulk/cleanse" \ -H "X-Api-Key: $DANADRESSE_API_KEY" \ -F "file=@kunder.csv" \ -F "vejnavn_col=Gade" \ -F "husnr_col=Nr" \ -F "postnr_col=Postnummer"
Svaret kommer med det samme, før rækkerne er behandlet:
{
"job_id": "3f9c2a7e5b0d4c1e9a8f6b2d7c4e1a05",
"status": "queued",
"status_url": "/api/v1/bulk/jobs/3f9c2a7e5b0d4c1e9a8f6b2d7c4e1a05",
"download_url": "/api/v1/bulk/jobs/3f9c2a7e5b0d4c1e9a8f6b2d7c4e1a05/download"
}Følg jobbet og hent resultatet
GET /api/v1/bulk/jobs/{job_id} returnerer status (queued, processing, completed eller failed), processed og error. processed opdateres for hver 100 rækker. total er antallet af rækker i filen og er kendt, så snart jobbet starter, så du kan vise en rigtig fremdrift. GET /api/v1/bulk/jobs viser dine seneste jobs.
Hent filen fra download_url, når status er completed. Spørger du for tidligt, får du 425 med koden not_ready. Jobbet huskes i én time efter, det er færdigt. Derefter svarer status og download 404 med job_not_found, så hent filen med det samme.
import os import time import requests API = "https://api.danadresse.dk" H = {"X-Api-Key": os.environ["DANADRESSE_API_KEY"]} with open("kunder.csv", "rb") as f: r = requests.post( f"{API}/api/v1/bulk/cleanse", headers=H, files={"file": ("kunder.csv", f, "text/csv")}, data={"vejnavn_col": "vejnavn", "husnr_col": "husnr", "postnr_col": "postnr"}, timeout=120, ) r.raise_for_status() job = r.json() while True: s = requests.get(API + job["status_url"], headers=H, timeout=10).json() print(s["status"], s["processed"]) if s["status"] == "completed": break if s["status"] == "failed": raise SystemExit(s["error"]) time.sleep(5) out = requests.get(API + job["download_url"], headers=H, timeout=120) out.raise_for_status() with open("kunder_renset.csv", "wb") as f: f.write(out.content)
Hvad står der i resultatet?
Filen har dine egne kolonner plus syv nye:
| Kolonne | Indhold |
|---|---|
_match_kategori | A, B eller C fra datavask, eller ERR ved fejl i rækken |
_match_score | Afledt af afstanden: 100 - 10 × afstand, og 0 uden match |
_match_id | Adresse-id for det bedste match |
_match_betegnelse | Det bedste match som én linje, f.eks. Strandvejen 100, 2900 Hellerup |
_match_adgangsadresseid | Adgangsadresse-id for det bedste match |
_match_afstand | Datavaskens afstand. 0 er præcist |
_match_forskelle | Datavaskens forskelle som JSON, f.eks. {"vejnavn":2,"husnr":0,"postnr":0,"postnrnavn":0} |
Bulk-jobbet kører den samme datavask som GET /datavask/adresser på hver række, så kategorierne betyder det samme: A er præcist, B er ét sikkert match med små stavefejl, og C er usikkert. Etage og dør tæller med. Ved C står det bedste bud i _match_*-kolonnerne, men lad en person afgøre rækken.
Din egen løkke over datavask
Vil du styre hvert kald selv, f.eks. for at vise alle C-kandidaterne for en bruger, så kald GET /datavask/adresser pr. række. Datavask tager én adresse pr. kald.
Hold øje med minutgrænsen. Hvert svar har X-RateLimit-Minute-Remaining. Når den rammer 0, så vent til X-RateLimit-Minute-Reset. Får du alligevel 429, så vent det antal sekunder, Retry-After siger. Se Grænser, kvoter og 429.
Eksemplet læser tre rækker fra en tekststreng, så du kan køre det direkte. Udskift io.StringIO(DATA) med open("kunder.csv", encoding="utf-8-sig") for en rigtig fil:
import csv import io import os import sys import time import requests DATA = """kundenr,vejnavn,husnr,etage,dor,postnr 1001,Strandvejen,100,1,,2900 1002,Strandvej,100,,,2900 1003,Rådhuspladsen,1,,,1550 """ s = requests.Session() s.headers["X-Api-Key"] = os.environ["DANADRESSE_API_KEY"] def vask(row): params = {k: row[k] for k in ("vejnavn", "husnr", "etage", "postnr") if row[k]} if row["dor"]: params["dør"] = row["dor"] while True: r = s.get("https://api.danadresse.dk/datavask/adresser", params=params, timeout=10) if r.status_code == 429: time.sleep(int(r.headers.get("Retry-After", "5"))) continue r.raise_for_status() if r.headers.get("X-RateLimit-Minute-Remaining") == "0": reset = int(r.headers.get("X-RateLimit-Minute-Reset", "0")) time.sleep(max(1, reset - int(time.time()))) return r.json() reader = csv.DictReader(io.StringIO(DATA)) cols = reader.fieldnames + ["_kategori", "_adresse_id", "_adgangsadresse_id", "_vejnavn"] out = csv.DictWriter(sys.stdout, fieldnames=cols) out.writeheader() for row in reader: svar = vask(row) top = svar["resultater"][0]["adresse"] if svar["resultater"] else {} row.update({ "_kategori": svar["kategori"], "_adresse_id": top.get("id", ""), "_adgangsadresse_id": top.get("adgangsadresseid", ""), "_vejnavn": top.get("vejnavn", ""), }) out.writerow(row)
Brug reglerne fra Valider adressen i checkout: A og B kan du gemme med den officielle stavemåde, C skal en person se på. Ved C har resultater flere kandidater, og den første er kun det bedste bud.
Hvilken skal du vælge?
| Bulk-job | Egen løkke over datavask | |
|---|---|---|
| Opsætning | Ét upload, ét download | Kode, retry og throttling |
| Kategorier | A, B og C | A, B og C |
| Etage og dør | Bruges | Bruges |
| Id'er | Adresse-id og adgangsadresse-id | Adresse-id og adgangsadresse-id |
| C-kandidater | Kun det bedste bud | Alle kandidater |
| Minutgrænse | Rammer dig ikke pr. række | Du skal selv vente |
| Store filer | Op til 50 MB pr. fil | Ingen grænse, men tager tid |
En god arbejdsgang er at køre bulk-jobbet på hele filen og derefter sende rækkerne med C gennem datavask-løkken, så en person kan vælge mellem kandidaterne.
Gode vaner
- Overskriv aldrig kildedata direkte. Skriv resultatet til nye kolonner, og lad en person godkende C-rækkerne.
- Gem adresse-id'et og adgangsadresse-id'et i CRM'et. Næste gang kan du validere med id'et i stedet for teksten. Se Gem adresse-id'et.
- Brug en live-nøgle til store kørsler. Testnøgler har gratisplanens grænser pr. IP-adresse.
Næste skridt
Relaterede guides
Markdown-kilde Fejl i guiden? Skriv til os API-reference (Swagger)