Domain Rating per VBA abrufen, ohne JSON-Bibliothek (Access und Excel)

Du willst das Domain Rating deiner eigenen Domain regelmäßig mitschreiben. Oder das von ein paar Kundenseiten, Wettbewerbern, einem Linkkandidaten. Bisher klickst du dich dafür durch die Ahrefs-Weboberfläche und tippst die Zahl von Hand in eine Tabelle. Geht auch anders. Es gibt einen kostenlosen Endpunkt, ohne API-Key, und du holst den Wert mit Bordmitteln direkt in deine Access-Anwendung oder dein Excel-Sheet.

Das Problem ist nicht der Abruf, sondern die Antwort

Eine REST-Antwort abholen kann VBA seit Jahren über MSXML2.ServerXMLHTTP. Der unangenehme Teil ist das JSON. Der Reflex vieler Entwickler ist, sich den VBA-JSON-Konverter ins Projekt zu ziehen, eine externe Klassendatei mit ein paar hundert Zeilen, nur um anschließend eine einzige Zahl auszulesen. Das ist Aufwand, der in keinem Verhältnis zum Ergebnis steht.

Für genau einen Zahlenwert lohnt keine Bibliothek. Harte Zerlegung der Zeichenkette reicht, ist nachvollziehbar und hat keine Abhängigkeit, die dir bei der nächsten Office-Aktualisierung um die Ohren fliegt.

Was Domain Rating ist, und was nicht

Domain Rating, kurz DR, ist eine Ahrefs-Metrik für die relative Stärke des Backlink-Profils einer Website, gemessen auf einer logarithmischen Skala von 0 bis 100. Logarithmisch heißt: der Sprung von 70 auf 71 ist deutlich schwerer als der von 20 auf 21.

Wichtig für die Einordnung, bevor du anfängst, die Zahl zu überhöhen: DR ist rein linkbasiert und kein Google-Ranking-Faktor. Der Wert taugt zum Vergleichen und zum Beobachten von Trends über die Zeit, nicht als Steuerungsgröße, an der du blind drehst. Genau deshalb ist es sinnvoll, ihn automatisiert mitzuschreiben statt punktuell abzulesen, denn interessant ist die Bewegung, nicht der Einzelwert.

Der kostenlose Endpunkt

Ahrefs stellt unter v3/public/domain-rating-free einen öffentlichen Endpunkt bereit. Kostenlos, kein API-Key, kein Authentifizierungs-Header. Du übergibst eine Domain oder eine vollständige URL als target, dazu das gewünschte Ausgabeformat. Mehr braucht es nicht.

Die Antwort hat einen kleinen Haken, der beim harten Zerlegen der einzige Stolperstein ist. Der Schlüssel ist verschachtelt und heißt zweimal gleich:

{ "domain_rating": { "domain_rating": 67.0 } }

Der äußere Schlüssel zeigt auf ein Objekt, der innere auf die Zahl. Wer naiv das erste Vorkommen von domain_rating greift, landet auf der Klammer, nicht auf dem Wert. Lösung: mit InStrRev von hinten suchen, dann steht man automatisch auf dem inneren, letzten Vorkommen.

Die Funktion

Der folgende Code holt die Antwort ab, prüft den HTTP-Status, zerlegt die Zahl hart heraus und gibt sie als Double zurück. Im Fehlerfall liefert er minus 1 und schreibt einen Klartext in den optionalen Parameter errText. Kein Verweis auf externe Bibliotheken, reines Late Binding.

'==================================================================
' Ahrefs Domain Rating (Free Endpoint, ohne API-Key)
' Laeuft unveraendert in Access VBA UND Excel VBA (Late Binding).
' Rueckgabe: DR als Double (0..100), bei Fehler -1 + errText gesetzt.
' Quelle Endpoint: https://docs.ahrefs.com/en/api/reference/public/get-domain-rating-free
'==================================================================
Public Function AhrefsDomainRating(ByVal target As String, _
                                   Optional ByRef errText As String) As Double
    Const ENDPOINT As String = "https://api.ahrefs.com/v3/public/domain-rating-free"
    Dim http As Object
    Dim url As String, body As String, drText As String
    Dim status As Long

    errText = ""
    AhrefsDomainRating = -1

    If Len(Trim$(target)) = 0 Then
        errText = "Kein target uebergeben."
        Exit Function
    End If

    url = ENDPOINT & "?target=" & UrlEncode(target) & "&output=json"

    On Error GoTo EH
    Set http = CreateObject("MSXML2.ServerXMLHTTP.6.0")
    http.setTimeouts 10000, 10000, 10000, 30000   ' resolve, connect, send, receive
    http.Open "GET", url, False
    http.setRequestHeader "Accept", "application/json"
    http.send
    status = http.status
    body = http.responseText
    Set http = Nothing

    ' --- Fehler-Responses (400/401/403/429/500) liefern {"error":"..."} ---
    If status <> 200 Then
        Dim apiErr As String
        apiErr = ExtractJsonString(body, "error")
        If Len(apiErr) > 0 Then
            errText = "HTTP " & status & ": " & apiErr
        Else
            errText = "HTTP " & status & " - " & Left$(body, 300)
        End If
        Exit Function
    End If

    ' --- 200: inneren domain_rating-Wert extrahieren ---
    drText = ExtractDomainRating(body)
    If Len(drText) = 0 Then
        errText = "domain_rating nicht gefunden. Body: " & Left$(body, 300)
        Exit Function
    End If

    AhrefsDomainRating = Val(drText)   ' Val => '.' immer Dezimaltrenner, locale-unabhaengig
    Exit Function

EH:
    errText = "Fehler " & Err.Number & ": " & Err.Description
    AhrefsDomainRating = -1
    On Error Resume Next
    Set http = Nothing
End Function

'------------------------------------------------------------------
' Inneren domain_rating-Wert holen.
' Response: {"domain_rating":{"domain_rating":67.0}}
' -> InStrRev nimmt das LETZTE (innere) Vorkommen des Schluessels.
'------------------------------------------------------------------
Private Function ExtractDomainRating(ByVal json As String) As String
    Dim key As String, p As Long, c As Long, i As Long
    Dim ch As String, numChars As String

    key = """domain_rating"""
    p = InStrRev(json, key)               ' inneres Vorkommen
    If p = 0 Then Exit Function

    c = InStr(p + Len(key), json, ":")
    If c = 0 Then Exit Function

    i = c + 1
    ' fuehrende Whitespaces ueberspringen
    Do While i <= Len(json)
        ch = Mid$(json, i, 1)
        If ch <> " " And ch <> vbTab And ch <> vbCr And ch <> vbLf Then Exit Do
        i = i + 1
    Loop

    ' erstes signifikantes Zeichen muss numerisch sein (sonst z. B. null)
    ch = Mid$(json, i, 1)
    If InStr("0123456789+-.", ch) = 0 Then Exit Function

    ' Zahl einsammeln (inkl. wissenschaftlicher Notation)
    Do While i <= Len(json)
        ch = Mid$(json, i, 1)
        If InStr("0123456789+-.eE", ch) > 0 Then
            numChars = numChars & ch
            i = i + 1
        Else
            Exit Do
        End If
    Loop

    ExtractDomainRating = numChars
End Function

'------------------------------------------------------------------
' String-Wert zu einem Schluessel holen (fuer "error").
' Beruecksichtigt escapte Anfuehrungszeichen \"
'------------------------------------------------------------------
Private Function ExtractJsonString(ByVal json As String, ByVal key As String) As String
    Dim k As String, p As Long, c As Long, q1 As Long, q2 As Long
    Dim i As Long, ch As String

    k = """" & key & """"
    p = InStr(1, json, k, vbTextCompare)
    If p = 0 Then Exit Function
    c = InStr(p + Len(k), json, ":")
    If c = 0 Then Exit Function
    q1 = InStr(c + 1, json, """")
    If q1 = 0 Then Exit Function

    i = q1 + 1
    Do While i <= Len(json)
        ch = Mid$(json, i, 1)
        If ch = "\" Then
            i = i + 2                     ' Escape-Sequenz ueberspringen
        ElseIf ch = """" Then
            q2 = i
            Exit Do
        Else
            i = i + 1
        End If
    Loop
    If q2 = 0 Then Exit Function

    ExtractJsonString = Mid$(json, q1 + 1, q2 - q1 - 1)
End Function

'------------------------------------------------------------------
' Minimales URL-Encoding (RFC 3986 unreserved bleibt stehen).
' Hinweis: nur ASCII. IDN-Domains mit Umlauten vorher in Punycode wandeln.
'------------------------------------------------------------------
Private Function UrlEncode(ByVal s As String) As String
    Dim i As Long, code As Long, ch As String, out As String
    For i = 1 To Len(s)
        ch = Mid$(s, i, 1)
        code = Asc(ch)
        Select Case code
            Case 48 To 57, 65 To 90, 97 To 122, 45, 46, 95, 126  ' 0-9 A-Z a-z - . _ ~
                out = out & ch
            Case Else
                out = out & "%" & Right$("0" & Hex$(code), 2)
        End Select
    Next i
    UrlEncode = out
End Function

Zwei Stellen sind nicht offensichtlich. Erstens das InStrRev, das wegen des doppelten Schlüssels von hinten suchen muss. Zweitens das Val am Ende: auf einem deutschen System interpretiert CDbl("67.0") den Punkt als Tausendertrenner oder wirft einen Typkonflikt, je nach Office-Version. Val ignoriert die Regions-Einstellung komplett und nimmt immer den Punkt als Dezimaltrenner. Genau das willst du bei JSON-Zahlen.

Aufruf in Access

Im Direktbereich oder aus einer Prozedur:

Sub TestDR()
    Dim e As String, dr As Double
    dr = AhrefsDomainRating("sesoft.de", e)
    If dr < 0 Then
        Debug.Print "Fehler: " & e
    Else
        Debug.Print "DR sesoft.de = " & dr
    End If
End Sub

Wer den Wert mitschreiben will, packt das Ergebnis in eine kleine Verlaufstabelle nach dem Muster reines Einfügen, eine Zeile pro Abruf mit Domain, Wert und Zeitstempel. So bekommst du die Bewegung über Wochen, und die ist aussagekräftiger als jede Momentaufnahme.

Excel: als Zellfunktion und als Sammel-Makro

Der Code oben läuft in Excel VBA unverändert, weil er nichts aus der Access-Bibliothek braucht. Kopier die vier Prozeduren in ein Standardmodul, fertig. Für die Tabellen-Fraktion gibt es zwei Wege.

Erstens als Zellfunktion. Ein dünner Wrapper macht das Ergebnis zellfreundlich, indem er den Fehlertext direkt in die Zelle schreibt statt über einen ByRef-Parameter:

' In Excel als UDF nutzbar:  =DR(A2)
Public Function DR(ByVal target As String) As Variant
    Dim e As String, v As Double
    v = AhrefsDomainRating(target, e)
    If v < 0 Then
        DR = "Fehler: " & e
    Else
        DR = v
    End If
End Function

Damit schreibst du in eine Zelle schlicht =DR(A2) und ziehst die Spalte runter. Der entscheidende Punkt: Jede Neuberechnung löst einen neuen HTTP-Abruf aus. Für eine Handvoll Zellen ist das egal, für eine lange Liste wird es lahm und reizt das Limit des kostenlosen Endpunkts aus.

Deshalb zweitens für größere Listen ein Sammel-Makro, das einmal über den Bereich läuft und feste Werte schreibt, also nicht bei jeder Neuberechnung erneut zieht:

' Liest Domains aus Spalte A ab Zeile 2, schreibt DR nach Spalte B,
' Zeitstempel nach Spalte C. Pause gegen das Rate-Limit.
Sub DR_Batch()
    Dim ws As Worksheet, lastRow As Long, r As Long
    Dim e As String, v As Double
    Set ws = ActiveSheet
    lastRow = ws.Cells(ws.Rows.Count, "A").End(xlUp).Row

    For r = 2 To lastRow
        If Len(Trim$(ws.Cells(r, "A").Value)) > 0 Then
            v = AhrefsDomainRating(CStr(ws.Cells(r, "A").Value), e)
            If v < 0 Then
                ws.Cells(r, "B").Value = "Fehler: " & e
            Else
                ws.Cells(r, "B").Value = v
            End If
            ws.Cells(r, "C").Value = Now
            DoEvents
            Application.Wait Now + TimeSerial(0, 0, 1)   ' 1 Sekunde Pause
        End If
    Next r

    MsgBox "Fertig: " & (lastRow - 1) & " Zeilen geprueft."
End Sub

Der Unterschied in der Praxis: Die UDF ist bequem für den schnellen Blick, das Makro ist die saubere Variante für eine Wettbewerbsliste, die du einmal pro Woche aktualisierst.

Wo der Ansatz an Grenzen stößt

Drei Dinge solltest du wissen, bevor du das in den Produktivbetrieb nimmst.

Der kostenlose Endpunkt ist mengenbegrenzt. Bei zu vielen Abrufen in kurzer Zeit kommt ein HTTP 429 zurück, den der Code sauber abfängt und als Klartext meldet. Bau die Pause aus dem Batch-Makro ein, dann bleibst du im grünen Bereich.

Die freien Werte können gerundet oder leicht zeitverzögert sein gegenüber dem, was du im bezahlten Ahrefs-Konto siehst. Für Trendbeobachtung reicht das, für Vertragszahlen nicht.

Und die wichtigste Grenze ist keine technische: DR ist linkbasiert und kein Google-Ranking-Faktor. Die Zahl ist ein grober Indikator für Link-Popularität, mehr nicht. Wer seine Inhaltsstrategie an einer einzelnen Drittmetrik ausrichtet, optimiert am Ziel vorbei.

Für Entwickler, die weiterdenken

Das Muster, eine externe REST-Antwort ohne Bibliothek hart zu zerlegen, trägt weit über diesen einen Endpunkt hinaus. Tankerkönig, Wechselkurse, Wetterdienste, Webshop-Schnittstellen: Überall, wo eine API einen überschaubaren JSON-Brocken liefert, ist die harte Zerlegung der schlankere Weg als eine eingebundene Klassenbibliothek. Den vollständigen Code dieses Beitrags kannst du eins zu eins übernehmen, die beiden Hilfsfunktionen für Zahl und String sind generisch.

Wenn dich nicht der Code interessiert, sondern die Frage, was es deinem Betrieb bringt, Daten aus solchen Außenquellen automatisch in deine bestehende Access- oder Excel-Landschaft zu holen, statt sie von Hand abzutippen oder dafür neue Software zu kaufen: Darum geht es im Kern bei der Anbindung von Altsystemen an die Außenwelt. Ein unverbindliches Erstgespräch dazu gibt es über sesoft.de/kontakt.

Quellen

Autor

Sönke Schäfer ist selbstständiger IT-Berater und Datenarchitekt aus Sierksdorf in Ostholstein. Er entwickelt seit über 25 Jahren mit Microsoft Access, VBA und SQL Server und verbindet gewachsene Datenbankbestände im norddeutschen Mittelstand mit externen Schnittstellen, von REST-APIs über WordPress bis zur Power Platform. Mehr zur Person unter Der Datenschäfer.

Nach oben scrollen