eBay per VBA steuern: Angebote suchen

Möchtest Du den gesamten Artikel lesen? Und vielleicht sogar den Artikel im PDF-Format und die Beispieldateien herunterladen? Dann hole Dir den Artikel gleich hier - völlig kostenlos!

Im ersten Teil der Artikelreihe zum Thema Steuerung von eBay mit VBA haben wir gezeigt, wie man einen Entwickler-Account anlegt, eine neue Anwendung bei eBay erstellt, grundlegende Zugriffsdaten holt und die für die Authentifizierung im Kontext eines bestimmten Benutzerkontos notwendigen Informationen holt – hier speziell das Authentifizierungstoken. Damit haben wir die Basis geschaffen, um per VBA auf die Rest API von eBay zuzugreifen. Damit fahren wir in diesem Teil fort: Wir wollen den grundlegenden Zugriff auf die Rest-API von eBay herstellen und verwenden dazu einfache Beispiele. Wie sich zeigt, gibt es zwei verschiedene Kontexte, in denen wir hier arbeiten, den Anwendungs- und den Benutzerkontext. Beide beschreiben wir in diesem Artikel.

Anwendungs- und Benutzerkontext

Wir im ersten Teil der Artikelreihe namens eBay per VBA steuern: Zugangsdaten holen (www.vbentwickler.de/460) beschrieben, gibt es zwei verschiedene Kontexte, in denen wir auf die Rest-API von eBay zugreifen können:

  • Anwendungskontext: Dies erlaubt uns die Nutzung allgemein zugänglicher Informationen – also beispielsweise solche, die man auch auf der Webseite ebay.com als nicht angemeldeter Benutzer einsehen kann. Hier für reicht das im oben genannten Artikel ermittelte Anwendungstoken zur Authentifizierung aus.
  • Benutzerkontext: Hiermit können wir solche Aktionen durchführen, die man auch als angemeldeter Benutzer erledigen kann. Dazu benötigen wir das Benutzertoken aus dem vorherigen Artikel. Damit wir die Benutzerfunktionen nutzen können, muss das Benutzertoken auch im Kontext der Anmeldung des entsprechenden Benutzers geholt werden.

Zu beachten ist, dass man je nach der verwendeten API und Funktion keine Authentifizierung, die Anwendungsauthentifizierung oder die Benutzerauthentifizierung benötigt. Wann welche Authentifizierung benötigt wird, erfährt man am einfachsten in der API-Dokumentation beziehungsweise im API-Explorer.

Zurechtfinden im API-Dschungel

eBay hat einen umfangreichen Bestand an API-Funktionen. Einen ersten Überblick findet man auf der folgenden Webseite:

https://developer.ebay.com/develop

Von hier aus geht es weiter zu den absoluten Grundlagen, zum Entwickeln von Anwendungen zum Verkaufen oder Kaufen oder zu weiteren Themen.

Im Bereich Kaufen interessiert uns beispielsweise, wie wir eine Suche nach Artikeln per VBA realisieren können. Im Bereich Verkaufen wäre es spannend, eigene Artikel voll automatisiert per VBA bei eBay einstellen zu können. Oder auch herauszufinden, welche Artikel wir gerade bei eBay anbieten und in welcher Anzahl, um hier gegebenenfalls aufzustocken. Beide Bereiche bieten zahlreiche Funktionen bereit, wir wollen uns jedoch auf den Bereich des Verkaufens konzentrieren.

Über diesen können wir uns in den weiterführenden Artikeln des oben genannten Links einen ersten Überblick verschaffen. Diesen finden wir zum Zeitpunkt der Erstellung dieses Artikels unter dem folgenden Link:

https://developer.ebay.com/api-docs/sell/static/selling-ig-landing.html

Hier finden wir einen Überblick über die Unterbereiche zum Thema Verkaufen auf eBay (siehe Bild 1).

Überblick über die eBay Sell API

Bild 1: Überblick über die eBay Sell API

Einstellen von Artikeln

Zum Einstellen von Artikeln finden wir verschiedene Ansätze:

  • eBay Trading API: Diese API ist bereits etwas älter. Sie ist XML-basiert und bietet beispielsweise Funktionen wie AddItem.
  • eBay Inventory API: Diese API ist moderner und verwendet JSON für den Datenaustausch.

Wir wollen uns in dieser Artikelreihe auf die aktuellen Techniken funktionieren und schauen uns daher die Variante an, welche die eBay Inventory API nutzt.

API-Katalog

Aufrufe von Rest-API haben wir in diesem Magazin bereits an einigen Beispielen demonstriert. Aber woher beziehen wir im Falle der eBay-API die wirklich wichtigen Informationen wie die folgenden:

  • Welche Authentifizierungsmethode benötigen wir – anwendungs- oder benutzerorientiert?
  • Wie lauten die Endpunkte für die gewünschten Aufrufe?
  • Welche Parameter müssen wir noch übermitteln?
  • Wie werden die JSON-Dokumente aufgebaut, die wir übermitteln?
  • Und wie ist der Aufbau der JSON-Dokumente, die als Ergebnis zurückgeliefert werden?
  • Welche Statuscodes werden von den verschiedenen Funktionen zurückgeliefert und was bedeuten diese?

Antworten auf viele dieser Fragen liefert der API-Katalog, den wir unter dem folgenden Link finden (alternativ suchen wir im Internet nach dem Suchbegriff ebay api explorer):

https://developer.ebay.com/my/api_test_tool?index=0

Damit landen wir auf der API Explorer-Seite (siehe Bild 2). Hier sehen wir verschiedene Elemente.

Aufrufen einer API-Funktion

Bild 2: Aufrufen einer API-Funktion

Wichtig ist erst einmal, dass wir oben die richtige Umgebung auswählen, also Sandbox oder Production.

Danach wählen wir im linken Bereich die zu verwendende Anwendung aus, hier amvBay, und die eBay-Seite, die wir untersuchen wollen. Wir möchten auf der deutschen Seite suchen und wählen deshalb (77) Germany aus.

Danach entscheiden wir, welche API wir nutzen wollen. Wir wollen erst einmal Angebote durchsuchen, also wählen wir die Browse API.

Dies aktualisiert wiederum direkt die Auswahl unter Select an API call. Hier wählen wir die Funktion search aus.

Dadurch wird rechts das Feld Web Service URI (endpoint) gefüllt, in diesem Fall mit dem folgenden Beispielcode:

https://api.ebay.com/buy/browse/v1/item_summary/search?q=drone&limit=3

Dies sind die Bestandteile:

  • Basis-URL https://api.ebay.com/buy/browse/v1/: Dies ist der Einstiegspunkt für die eBay Browse API, die Informationen zu Artikeln bereitstellt, die auf eBay zum Verkauf stehen.
  • Endpunkt item_summary/search: Dieser Endpunkt führt eine Suche nach Artikeln durch und liefert eine Zusammenfassung (item summary) der gefundenen Ergebnisse.
  • Parameter q=drone: Dies ist der Suchbegriff. In diesem Fall wird nach Artikeln gesucht, die den Begriff drone enthalten. Es durchsucht Titel, Beschreibung und andere relevante Felder der Artikel.
  • Anzahl der Ergebnisse limit=3: Dies legt fest, wie viele Ergebnisse pro Anfrage zurückgegeben werden sollen. In diesem Fall werden maximal drei Artikel zurückgegeben.

Wichtig ist auch noch der Inhalt des kleinen Kästchens in der Nähe von Call Request, das zum Beispiel GET, POST, PUT oder DELETE enthalten kann – eine Information, die wir später für den Aufruf der Rest AP benötigen.

HTTP-Header

Darunter finden wir den Bereich HTTP Headers. Auch hier finden wir wertvolle Informationen, die wir gegebenenfalls in unserem eigenen Aufruf per VBA berücksichtigen müssen. Auch dort haben wir die Möglichkeit, Header zu übersenden. Klicken wir nun auf Execute, erhalten wir im unteren Bereich das Ergebnis. Dieses sieht wie in Bild 3 aus.

Ergebnis der Artikelsuche

Bild 3: Ergebnis der Artikelsuche

Hier sehen wir im oberen Bereich die Response-Header, die für uns weniger interessant sind. Spannender ist das tatsächliche Ergebnis unter Response Body.

Hier finden wir im JSON-Format die Eigenschaften der gefundenen Artikel. Unser Ziel ist es, dieses Dokument per VBA auszulesen und es dann auslesen zu können. Das erledigen wir in den folgenden Abschnitten.

Voraussetzung: OAuth Application Token

Um auf die Api zuzugreifen, benötigen wir das sogenannte OAuth Application Token. Das holen wir uns, nachdem wir die im Artikel eBay per VBA steuern: Zugangsdaten holen (www.vbentwickler.de/460) beschriebenen Schritte zum Erstellen eines Entwicklerkontos und einer App durchgeführt haben, mit der VBA-Prozedur GetEbayAppToken. Diese rufen wir wie folgt auf, um das Token direkt in der Registry zu speichern:

Public Sub GetEbayAppTokenInRegistry()
     Dim strAppToken As String
     strAppToken = GetEbayAppToken(GetAppSetting("AppID"), _
         GetAppSetting("CertID"), cStrAPIScope)
     SaveAppSetting "AppToken", strAppToken
End Sub

Voraussetzung ist, dass wir zuvor die übrigen notwendigen Informationen, also die AppID und die CertID sowie den APIScope wie im oben genannten Artikel ermittelt haben.

Erster Wurf: Aufruf testen

In der Prozedur GetItems haben wir einen ersten Anlauf zusammengestellt, um eine Liste von Artikeln abzurufen (siehe Listing 1). Wobei erster Anlauf untertrieben ist – wir haben im Vorfeld bereits einige Versuche unternommen, bis wir eine lauffähige Variante hatten.

Public Function GetItems(strResponse As String) As Boolean
     Dim objXMLHTTP As MSXML2.XMLHTTP60
     Dim strURL As String
     Dim strOAuthToken As String
     strURL = "https://api.ebay.com/buy/browse/v1/item_summary/search?q=drone&limit=3"
     strOAuthToken = "Bearer " & cStrAppToken
     Set objXMLHTTP = New MSXML2.XMLHTTP60
     objXMLHTTP.Open "GET", strURL, False
     
     objXMLHTTP.setRequestHeader "Authorization", strOAuthToken
     objXMLHTTP.setRequestHeader "X-EBAY-C-MARKETPLACE-ID", "EBAY_DE"
     objXMLHTTP.setRequestHeader "X-EBAY-C-ENDUSERCTX", _
         "ffiliateCampaignId=<ePNCampaignId>,affiliateReferenceId=<referenceId>"
     objXMLHTTP.Send
     strResponse = objXMLHTTP.responseText
     Select Case objXMLHTTP.status
         Case 200
             GetItems = True
         Case Else
             Debug.Print objXMLHTTP.status & vbCrLf & objXMLHTTP.responseText
     End Select
     
     Set objXMLHTTP = Nothing
End Function

Listing 1: Erster Aufruf der eBay-Rest API

Die Dokumentation des hier verwendeten Endpunkts item_summary/search findest Du hier:

https://developer.ebay.com/api-docs/buy/browse/resources/item_summary/methods/search

Hier findest Du ausführlich alle möglichen Parameter und wie man sie einsetzt und es wird auch der komplette Output dieses Aufrufs erläutert.

Die Prozedur deklariert zunächst eine Variable des Typs MSXML2.XMLHTTP60. Um diese verwenden zu können, benötigen wir einen Verweis auf die Bibliothek Microsoft XML, v6.0 hinzu.

In diesem Zuge addieren wir direkt noch einen Verweis auf Bibliothek Microsoft Scripting Runtime (siehe Bild 4).

Verweise für XML und JSON

Bild 4: Verweise für XML und JSON

Letzteren benötigen wir für Funktionen für den Zugriff auf die von der Rest API zurückgelieferten JSON-Dokumente.

Wenn Du die Anwendung nachbauen möchtest, benötigst Du auf jeden Fall noch die folgenden beiden Module:

  • mdlJSON: Enthält Funktionen zum Parsen von JSON-Dokumenten ein Objektmodell und zum Erzeugen von JSON-Dateien aus diesem Objektmodell.
  • mdlJSONDOM: Enthält Funktionen, mit denen wir die Bezüge für den Zugriff auf die Elemente des Objektmodells für alle JSON-Dokumente leicht ausgeben und übernehmen können.

Außerdem ist auch das Modul mdlZwischenablage hilfreich. Dieses enthält eine Funktion, mit der wir den Inhalt einer Variablen in die Zwischenablage kopieren können.

Das ist hilfreich, wenn wir größere JSON-Dokumente von der Rest-API zurückbekommen, die wir nicht vollständig im Direktbereich ausgeben können, ohne das der obere Teil gelöscht wird. Dann können wir solche Texte aus der Zwischenablage in einen Text- oder JSON-Editor kopieren, um sie dort zu analysieren.

Die Prozedur erstellt noch weitere String-Variablen. Dann fügt sie der Variablen strUrl die Adresse unserer Rest API-Funktion hinzu, die wir hier vorerst 1:1 aus dem API Explorer entnommen haben. Danach fügt sie das Schlüsselwort Bearer mit dem Anwendungstoken aus der Konstanten cStrAppToken zusammen.

Damit erstellt sie nun ein Objekt auf Basis des Typs MSXML2.XMLHTTP60 und ruft dessen Open-Methode auf. Die Parameter sehen wie folgt aus:

  • bstrMethod: Gibt die Zugriffsmethode an, zum Beispiel GET, POST, PUT oder DELETE
  • bstrURL: Gibt die Adresse der Rest API-Funktion an.
  • varAsynch: Gibt an, ob der Aufruf asynchron angegeben werden soll. Der Wert False legt fest, dass dieser synchron erfolgen soll, das heißt, die ausführende Prozedur wird erst fortgesetzt, wenn der Aufruf beendet ist.

Danach setzen wir Request-Header, die wir ebenfalls dem entsprechenden Bereich im API Explorer entnehmen können.

Diese teilen wir am Doppelpunkt auf und geben den linken Teil in Anführungszeichen für den Parameter bstrHeader an und den rechten als bstrValue. So übergeben wir das Token und auch weitere Informationen über den Aufruf wie beispielsweise den zu durchsuchenden Markt.

Danach senden wir die Anfrage schließlich mit der Send-Methode ab und erhalten verschiedene Ergebnisse, zum Beispiel:

  • über die Eigenschaft status den Status der Anfrage, zum Beispiel mit dem Wert 200 im Erfolgsfall oder 404, falls die Adresse aus strUrl nicht existiert und
  • über die Eigenschaft responseText, die zumindest dann, wenn die URL korrekt war, einen Ergebnistext zurückliefert.

Geben wir zum Beispiel das falsche Token an, erhalten wir für status den Wert 401 und für responseText diesen Text:

{"errors":
   [
     {      "errorId": 1001,      "domain": "OAuth",      "category": "REQUEST",      "message": "Invalid access token",      "longMessage": "Invalid access token. Check the value of the Authorization HTTP request header." }
   ]
}

Im Erfolgsfall hingegen erhalten wir ein JSON-Dokument, das etwa wie in Bild 5 aussieht.

Ergebnis der Abfrage im JSON-Format

Bild 5: Ergebnis der Abfrage im JSON-Format

Hier ist der erste von drei Artikel aus dem Ergebnis der Abfrage abgebildet.

Wie aber wollen wir hier nur gezielt auf einzelne Elemente zugreifen?

Während das gelegentlich rein mit Zeichenkettenfunktionen erledigt wird, indem man beispielsweise nach dem Namen des gewünschten Elements sucht, ist das in größeren Dokumenten wie diesem hier keine angenehme Aufgabe.

Hier kommen unsere Prozeduren aus den beiden Modulen mdlJSON und mdlJSONDOM ins Spiel.

Wir bauen eine Prozedur zum Aufrufen der Funktion GetItems und zum Auswerten des Ergebnisses. Diese sieht zunächst wie folgt aus:

Public Sub Test_GetItems()
     Dim strJSON As String
     Dim objJSON As Object
     
     strJSON = GetItems()
     Set objJSON = ParseJson(strJSON)
     Debug.Print GetJSONDOM(strJSON, True)
End Sub

Die Variable strJSON soll das JSON-Dokument als Zeichenkette aufnehmen.

Die Variable objJSON füllen wir mit dem Ergebnis der Funktion ParseJson mit dem Parameter strResponse und erhalten ein Objektmodell, dass alle Elemente des JSON-Dokuments enthält und aus verschachtelten Dictionary– und Collection-Elementen besteht.

Wie aber erfahren wir nun, wie wir gezielt auf die einzelnen Informationen zugreifen können – oder wie wir beispielsweise in einer Schleife durch die zurückgelieferten Artikel laufen können?

Die Grundlage dazu liefert die Funktion GetJSONDOM. Dieser übergeben wir den kompletten Inhalt des JSON-Dokuments und mit dem zweiten Parameter den Wert True, damit nicht nur die Ausdrücke, die zu den Werten führen, ausgegeben, sondern auch die Werte selbst.

Die Funktion durchläuft alle Elemente und trägt sie in einer Zeichenkette zusammen. Diese können wir entweder im Direktbereich ablegen oder wir speichern sie in der Zwischenablage.

Der Inhalt sieht wie in Listing 2 aus. Der linke Teil enthält jeweils das Objekt objJSON, dahinter folgt der Ausdruck, mit dem man den Wert für das entsprechende Element auslesen kann.

objJSON.Item("href"):https://api.ebay.com/buy/browse/v1/item_summary/search?q=drone&limit=3&offset=0
objJSON.Item("total"):6081
objJSON.Item("next"):https://api.ebay.com/buy/browse/v1/item_summary/search?q=drone&limit=3&offset=3
objJSON.Item("limit"):3
objJSON.Item("offset"):0
objJson.Item("itemSummaries").Item(1).Item("itemId"): v1|145588822372|0
objJson.Item("itemSummaries").Item(1).Item("title"): 
     Refurbished ATOM Fly More Combo GPS Drone 4K Kamera 3-Achsen-Gimbal Kameradrohne
objJson.Item("itemSummaries").Item(1).Item("leafCategoryIds").Item(1): 179697
objJson.Item("itemSummaries").Item(1).Item("categories").Item(1).Item("categoryId"): 179697
objJson.Item("itemSummaries").Item(1).Item("categories").Item(1).Item("categoryName"): Kamera-Drohnen
objJson.Item("itemSummaries").Item(1).Item("categories").Item(2).Item("categoryId"): 625
objJson.Item("itemSummaries").Item(1).Item("categories").Item(2).Item("categoryName"): Foto & Camcorder
objJson.Item("itemSummaries").Item(1).Item("image").Item("imageUrl"): 
     https://i.ebayimg.com/images/g/7ssAAOSw18hlvKY6/s-l225.jpg
objJson.Item("itemSummaries").Item(1).Item("price").Item("value"): 309.99
objJson.Item("itemSummaries").Item(1).Item("price").Item("currency"): EUR
objJson.Item("itemSummaries").Item(1).Item("itemHref"): https://api.ebay.com/buy/browse/v1/item/v1%7C145588822372%7C0
objJson.Item("itemSummaries").Item(1).Item("seller").Item("username"): potensic_store
objJson.Item("itemSummaries").Item(1).Item("seller").Item("feedbackPercentage"): 99.3
objJson.Item("itemSummaries").Item(1).Item("seller").Item("feedbackScore"): 3262
objJson.Item("itemSummaries").Item(1).Item("seller").Item("sellerAccountType"): BUSINESS
objJson.Item("itemSummaries").Item(1).Item("condition"): Zertifiziert - Refurbished
objJson.Item("itemSummaries").Item(1).Item("conditionId"): 2000
objJson.Item("itemSummaries").Item(1).Item("thumbnailImages").Item(1).Item("imageUrl"): 
     https://i.ebayimg.com/images/g/7ssAAOSw18hlvKY6/s-l1600.jpg
objJson.Item("itemSummaries").Item(1).Item("shippingOptions").Item(1).Item("shippingCostType"): FIXED
objJson.Item("itemSummaries").Item(1).Item("shippingOptions").Item(1).Item("shippingCost").Item("value"): 0.00
objJson.Item("itemSummaries").Item(1).Item("shippingOptions").Item(1).Item("shippingCost").Item("currency"): EUR
objJson.Item("itemSummaries").Item(1).Item("buyingOptions").Item(1): FIXED_PRICE
objJson.Item("itemSummaries").Item(1).Item("epid"): 28063837524
objJson.Item("itemSummaries").Item(1).Item("itemWebUrl"): 
     https://www.ebay.de/itm/145588822372?_skw=drone&hash=item21e5c52164:g:7ssAAOSw18hlvKY6&amdata=enc...
objJson.Item("itemSummaries").Item(1).Item("itemLocation").Item("postalCode"): 55***
objJson.Item("itemSummaries").Item(1).Item("itemLocation").Item("country"): DE
objJson.Item("itemSummaries").Item(1).Item("additionalImages").Item(1).Item("imageUrl"): 
     https://i.ebayimg.com/images/g/GRIAAOSwzfFlvKam/s-l225.jpg
...
objJson.Item("itemSummaries").Item(1).Item("adultOnly"): Falsch
objJson.Item("itemSummaries").Item(1).Item("unitPricingMeasure"): Einheit
objJson.Item("itemSummaries").Item(1).Item("unitPrice").Item("value"): 309.99
objJson.Item("itemSummaries").Item(1).Item("unitPrice").Item("currency"): EUR
objJson.Item("itemSummaries").Item(1).Item("legacyItemId"): 145588822372
objJson.Item("itemSummaries").Item(1).Item("availableCoupons"): Falsch
objJson.Item("itemSummaries").Item(1).Item("itemCreationDate"): 2024-02-02T08:28:06.000Z
objJson.Item("itemSummaries").Item(1).Item("topRatedBuyingExperience"): Wahr
objJson.Item("itemSummaries").Item(1).Item("priorityListing"): Wahr
objJson.Item("itemSummaries").Item(1).Item("listingMarketplaceId"): EBAY_DE
objJson.Item("itemSummaries").Item(2).Item("itemId"): v1|285778132279|0

Listing 2: Ausdrücke für den Zugriff auf den Inhalt des JSON-Dokuments

Für den Titel des Artikels verwenden wir:

Debug.Print objJson.Item("itemSummaries").Item(1).Item("title")

Auf ähnliche Weise können wir auf die übrigen Elemente zugreifen.

Noch spannender ist die Frage, wie wir Elemente in Schleifen durchlaufen können, die mehrmals vorkommen. Dazu schauen wir uns erst einmal an, um welche Elemente es hier geht.

Die drei Artikel, die unser Ergebnis zurückliefert, können wir grundsätzlich über diese Ausdrücke referenzieren:

objJson.Item("itemSummaries").Item(1) ...
objJson.Item("itemSummaries").Item(2) ...
objJson.Item("itemSummaries").Item(3) ...

Um diese in einer Schleife zu durchlaufen, deklarieren wir eine Zählervariable:

Dim i As Integer

Außerdem benötigen wir eine Variable, in der wir das jeweilige Hauptelement für den aktuellen Artikel speichern:

Ende des frei verfügbaren Teil. Wenn Du mehr lesen möchtest, hole Dir ...

den kompletten Artikel im PDF-Format mit Beispieldatenbank

diesen und alle anderen Artikel mit dem Jahresabo

Schreibe einen Kommentar