Amazon Proxy – Teil 4: Product Advertising API (PA-API) 5.0

Amazon Proxy

Die bisherigen drei Artikel über den Amazon Proxy Server bezogen sich auf die Amazon Product Advertising API Version 4. Anfang 2020 wird die von Amazon allerdings abgelöst durch eine neue Version 5.0. Damit verändert sich vieles grundsätzlich und für PA-API Nutzer bleibt beim Umstieg von V4 auf V5 kaum ein Stein auf dem anderen. Dieser Artikel geht ein auf die Unterschiede zwischen API Version 4 und 5, die Migration der API-Schlüssel und das neue Scratchpad. Danach wird der Amazon Proxy Server auf die neue Version 5.0 der Amazon PA-API upgedatet.

Was ändert sich mit der PA-API 5.0?

Natürlich ist die neue API besser, schlanker und schneller. ;-) Die wirklich auffälligen Dinge, mit denen wir es zu tun bekommen werden, sind aber folgende:

  • Neue Zugangsschlüssel (Credentials) – zumindest ältere Schlüssel müssen migriert werden. Ob das wirklich nötig ist, klären wir im nächsten Abschnitt.
  • Empfangen wird nicht mehr im XML-Format, sondern JSON Daten (Programmiererherzen schlagen höher).
  • Die Signatur der gesendeten Anforderung wird sicherer (was aber auch zu wesentlich längerem Code führt).
  • Response Groups werden abgeschafft (was kein Schaden ist), dafür gibt es jetzt Ressources.
  • Es gibt ein neues Scratchpad.
  • Und es gibt natürlich auch eine neue Dokumentation.

Vorhandene API-Schlüssel überprüfen

Amazon sagt, dass API-Schlüssel, die vor dem 29. September 2017 erzeugt wurden, migriert werden müssen. Neuere wohl nicht. Um sicher zu gehen, probieren wir das einfach aus und zwar mit dem Scratchpad. Wer nicht weiß, was das Scratchpad ist, der sollte nochmal Teil 1 dieser Artikelserie lesen, auch wenn es dort noch um PA-API Version 4 geht.

Wie oben bereits erwähnt, gibt es für die API 5.0 ein neues Scratchpad, das aber ähnlich funktioniert, wie das alte. Das rufen wir nun auf und gehen links bei Select operation auf GetItems.

Amazon Scratchpad 5.0

Und hier geben wir unsere Zugangsdaten ein. Abgesehen davon, dass sich die Bezeichnungen etwas geändert haben und dass ein Partner Type hinzugekommen ist, entspricht das grob den Eingaben im alten Scratchpad.

Im Abschnitt GetItems darunter geben wir bei ItemIds eine gültige Amazon ASIN (also Produktnummer) ein und wählen eine beliebige Ressource aus, zum Beispiel ruhig mal Select all. Beim Klick auf Run request rechts zeigt sich nun, ob die Zugangsschlüssel funktionieren. Wenn wir als Antwort bei Rendered response eine Fehlermeldung wie die folgende erhalten, dann sind unsere Zugangsschlüssel nicht API 5.0 tauglich und müssen migriert werden.

Access Denied AWS Users

API-Schlüssel migrieren

Hierzu gibt es von Amazon auch eine englischsprachige Anleitung, aber an sich ist die Sache ganz einfach. Wichtig zu wissen ist, dass beim Migrationsvorgang neue Schlüssel erzeugt werden. Die alten bleiben dabei erhalten und können weiterhin mit der PA-API 4 genutzt werden – zumindest so lange die API 4 verfügbar ist. Das neue Schlüsselpaar funktioniert mit PA-API 4 und PA-API 5.

Zur Migration melden wir uns im Amazon PartnerNet an, zum Beispiel über den Link Verdienst im SiteStripe oberhalb jeder Amazon Produkt Seite. Dann gehen wir im Menü auf Tools und Product Advertising API.

Unter Verwalte Deine Zugangsdaten können wir nun mit dem Button Umziehen die Migration anstoßen. Wichtig ist es, die neuen Zugangsschlüssel sofort sicher abzuspeichern – der Secret Key ist so geheim, dass man später nicht mehr an ihn heran kommt.

Datenstruktur mit Scratchpad erkunden

Der Aufbau des neuen Scratchpads ist dem alten ganz ähnlich. Auffällig ist zuerst, dass die ResponseGroups verschwunden sind und es statt dessen Ressources gibt. Damit wird spezifiziert, welche Antwort-Daten-Felder (Produkttitel, Beschreibung, Preis) man bekommen möchte. Früher hat man dazu ganze Listen wie Large ausgewählt, was nie passend war. Jetzt kann man die einzelnen Ressourcen einzeln oder in kleinen Gruppen auswählen. Das ist erst einmal etwas umständlicher, führt aber zu kompakteren Antworten der API.

Die zweite augenfällige Änderung sieht man beim Responseformat. Das frühere XML wurde durch JSON ersetzt, was mir wesentlich sympatischer ist. Mit XML bin ich nie recht warm geworden. Abgesehen davon, dass sich alle Bezeichnungen und die ganze Struktur geändert haben, ist die Vorgehensweise die selbe wie früher. Wir müssen im Wust der Daten nach den Stellen suchen, die die gewünschten Informationen enthalten. Was den Amazon Proxy Server angeht, hab ich das bereits gemacht – siehe weiter unten.

Wer nun glaubt, dass es mehr Informationen gibt, den muss ich gleich enttäuschen. Per Januar 2020 sind es eher weniger als früher. Das Editorial Review zum Beispiel, das die Produktbeschreibung enthielt, gibt es in der PA-API 5.0 (noch) nicht.

Und jetzt schauen wir noch ganz nach unten zu den Code snippets und zwar für PHP. Da gibt es eine gute und eine schlechte Nachricht:

a) Der PHP-Beispielcode ist besser und vollständiger. Wurde im alten Scratchpad nur der Request formuliert und signiert, wird im neuen auch die Abfrage durchgeführt und die Antwort angezeigt. (Also dann wenn man den Programmcode auf den eigenen Server übernimmt und ausführt.)

b) Durch die aufwändigere Signatur (class AwsV4) und die einzeln anzugebenden Ressourcen ist der Code wesentlich länger.

Beides hat mich zu dem Entschluss gebracht, den PHP Beispielcode (weitgehend) zu übernehmen. Aber ich baue ihn nicht ins amaprox.php Programm direkt ein, sondern mache daraus eine Include-Datei.

Modifikation des Amazon Proxy für die PA-API 5.0

Bisher ging es in diesem Artikel um die Amazon Product Advertising API 5.0 an sich und um die Neuerungen im Vergleich zur Version 4. Nun sprechen wir darüber, wie der Amazon Proxy Server, den ich im Teil 2 dieser Artikelserie vorgestellt hatte, auf die PA-API 5.0 migriert werden kann. Die gute Nachricht zuerst: Die Arbeiten beschränken sich auf die Amazon Proxy PHP Server-Komponente selbst. Der Proxy Client und seine Einbindung in WordPress oder andere Webseiten bleibt unverändert.

pa-api5.php

Das ist die neu hinzugekommene Include-Datei, die ich bereits erwähnt habe und sie entspricht weitestgehend dem PHP-Beispielcode, den das Amazon PA-API 5.0 Scratchpad erzeugt.

<?php

/* Copyright 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved. */
/* Modified Jan 2020 by Helmut Karger https://blog.helmutkarger.de */
/* Licensed under the Apache License, Version 2.0. */


function paapi5($accessKey, $secretKey, $partnerTag, $asin) {

  $serviceName="ProductAdvertisingAPI";
  $region="eu-west-1";
  $payload="{"
          ." \"ItemIds\": ["
          ."  \"".$asin."\""
          ." ],"
          ." \"Resources\": ["
          ."  \"Images.Primary.Medium\","
          ."  \"ItemInfo.Features\","
          ."  \"ItemInfo.Title\","
          ."  \"Offers.Listings.Price\""
          ." ],"
          ." \"PartnerTag\": \"".$partnerTag."\","
          ." \"PartnerType\": \"Associates\","
          ." \"Marketplace\": \"www.amazon.de\""
          ."}";
  $host="webservices.amazon.de";
  $uriPath="/paapi5/getitems";
  $awsv4 = new AwsV4 ($accessKey, $secretKey);
  $awsv4->setRegionName($region);
  $awsv4->setServiceName($serviceName);
  $awsv4->setPath ($uriPath);
  $awsv4->setPayload ($payload);
  $awsv4->setRequestMethod ("POST");
  $awsv4->addHeader ('content-encoding', 'amz-1.0');
  $awsv4->addHeader ('content-type', 'application/json; charset=utf-8');
  $awsv4->addHeader ('host', $host);
  $awsv4->addHeader ('x-amz-target', 'com.amazon.paapi5.v1.ProductAdvertisingAPIv1.GetItems');
  $headers = $awsv4->getHeaders ();
  $headerString = "";
  foreach ( $headers as $key => $value ) {
      $headerString .= $key . ': ' . $value . "\r\n";
  }
  $params = array (
          'http' => array (
              'header' => $headerString,
              'method' => 'POST',
              'content' => $payload
          )
      );
  $stream = stream_context_create ( $params );

  $fp = @fopen ( 'https://'.$host.$uriPath, 'rb', false, $stream );

  if (! $fp) {
      return false;
  }
  $response = @stream_get_contents ( $fp );
  return $response;
}

class AwsV4 {

    private $accessKey = null;
    private $secretKey = null;
    private $path = null;
    private $regionName = null;
    private $serviceName = null;
    private $httpMethodName = null;
    private $queryParametes = array ();
    private $awsHeaders = array ();
    private $payload = "";

    private $HMACAlgorithm = "AWS4-HMAC-SHA256";
    private $aws4Request = "aws4_request";
    private $strSignedHeader = null;
    private $xAmzDate = null;
    private $currentDate = null;

    public function __construct($accessKey, $secretKey) {
        $this->accessKey = $accessKey;
        $this->secretKey = $secretKey;
        $this->xAmzDate = $this->getTimeStamp ();
        $this->currentDate = $this->getDate ();
    }

    function setPath($path) {
        $this->path = $path;
    }

    function setServiceName($serviceName) {
        $this->serviceName = $serviceName;
    }

    function setRegionName($regionName) {
        $this->regionName = $regionName;
    }

    function setPayload($payload) {
        $this->payload = $payload;
    }

    function setRequestMethod($method) {
        $this->httpMethodName = $method;
    }

    function addHeader($headerName, $headerValue) {
        $this->awsHeaders [$headerName] = $headerValue;
    }

    private function prepareCanonicalRequest() {
        $canonicalURL = "";
        $canonicalURL .= $this->httpMethodName . "\n";
        $canonicalURL .= $this->path . "\n" . "\n";
        $signedHeaders = '';
        foreach ( $this->awsHeaders as $key => $value ) {
            $signedHeaders .= $key . ";";
            $canonicalURL .= $key . ":" . $value . "\n";
        }
        $canonicalURL .= "\n";
        $this->strSignedHeader = substr ( $signedHeaders, 0, - 1 );
        $canonicalURL .= $this->strSignedHeader . "\n";
        $canonicalURL .= $this->generateHex ( $this->payload );
        return $canonicalURL;
    }

    private function prepareStringToSign($canonicalURL) {
        $stringToSign = '';
        $stringToSign .= $this->HMACAlgorithm . "\n";
        $stringToSign .= $this->xAmzDate . "\n";
        $stringToSign .= $this->currentDate . "/" . $this->regionName . "/" . $this->serviceName . "/" . $this->aws4Request . "\n";
        $stringToSign .= $this->generateHex ( $canonicalURL );
        return $stringToSign;
    }

    private function calculateSignature($stringToSign) {
        $signatureKey = $this->getSignatureKey ( $this->secretKey, $this->currentDate, $this->regionName, $this->serviceName );
        $signature = hash_hmac ( "sha256", $stringToSign, $signatureKey, true );
        $strHexSignature = strtolower ( bin2hex ( $signature ) );
        return $strHexSignature;
    }

    public function getHeaders() {
        $this->awsHeaders ['x-amz-date'] = $this->xAmzDate;
        ksort ( $this->awsHeaders );

        // Step 1: CREATE A CANONICAL REQUEST
        $canonicalURL = $this->prepareCanonicalRequest ();

        // Step 2: CREATE THE STRING TO SIGN
        $stringToSign = $this->prepareStringToSign ( $canonicalURL );

        // Step 3: CALCULATE THE SIGNATURE
        $signature = $this->calculateSignature ( $stringToSign );

        // Step 4: CALCULATE AUTHORIZATION HEADER
        if ($signature) {
            $this->awsHeaders ['Authorization'] = $this->buildAuthorizationString ( $signature );
            return $this->awsHeaders;
        }
    }

    private function buildAuthorizationString($strSignature) {
        return $this->HMACAlgorithm . " " . "Credential=" . $this->accessKey . "/" . $this->getDate () . "/" . $this->regionName . "/" . $this->serviceName . "/" . $this->aws4Request . "," . "SignedHeaders=" . $this->strSignedHeader . "," . "Signature=" . $strSignature;
    }

    private function generateHex($data) {
        return strtolower ( bin2hex ( hash ( "sha256", $data, true ) ) );
    }

    private function getSignatureKey($key, $date, $regionName, $serviceName) {
        $kSecret = "AWS4" . $key;
        $kDate = hash_hmac ( "sha256", $date, $kSecret, true );
        $kRegion = hash_hmac ( "sha256", $regionName, $kDate, true );
        $kService = hash_hmac ( "sha256", $serviceName, $kRegion, true );
        $kSigning = hash_hmac ( "sha256", $this->aws4Request, $kService, true );

        return $kSigning;
    }

    private function getTimeStamp() {
        return gmdate ( "Ymd\THis\Z" );
    }

    private function getDate() {
        return gmdate ( "Ymd" );
    }
}
?>

Die zweite Hälfte des Programm, nämlich die Klasse AwsV4 ist vollkommen unverändert und entspricht 1:1 der Ausgabe des Scratchpads. In der oberen Hälfte habe ich folgende Modifikationen vorgenommen:

  • Den gesamten oberen Programmteil habe ich zu einer Funktion paapi5 gemacht, der 4 Parameter übergeben werden. Diese Funktion stellt die Daten zusammen, die an die API gesendet werden sollen ($paypoad), signiert sie, sendet den Request an Amazon und gibt die Antwort im JSON-Format an das aufrufende Programm zurück.
  • Dazu habe ich die vier Übergabeparameter, die im Beispielprogramm fest verdrahtet waren, als Variablen eingesetzt – zum Beispiel in die Payload. Parameter, die sich für die Belange des Amazon Proxies nicht ändern, wie Marketplace, Ressources und Region, bleiben jedoch fest in der Funktion definiert. Das ist zwar nicht elegant aber praktisch.
  • das echo $response wurde entfernt zu Gunsten einer Rückgabe return $response.
  • die beiden Fehlerausgaben throw new Exception habe ich ebenfalls entfernt und reiche dafür ein return false zurück. Im Fehlerfall soll der Amazon Proxy schweigend sterben und keine Fehlermeldungen im WordPress Blog ausgeben.

Änderungen an amaprox.php

Das ist die Amazon Proxy PHP Serverkomponente aus Teil 2 dieser Artikelserie. Sie besteht aus neun Programmsektionen, von denen ich hier erst einmal nur diejenigen aufführen werde, die durch die PA-API 5.0 Änderungen erfahren. Danach kommt der komplette Code nochmal in einem Stück.

I. Definitionen

<?php

require "paapi5.php";

$access_key = "ABCDEFGHIJKLMNO";
$secret_key = "AbCdEfGhIjKlMnOpQrStUvWxYz";
$associate_tag = "wwwmeinesite-21";

$cachefolder = "cache";
$amaprox_homeURL = "https://www.meine-site.de/amaprox";

Am Anfang steht die require Anweisung, die die Include-Datei einbindet. Das Programm geht hier davon aus, dass die im selben Verzeichnis wie amaprox.php selbst liegt, aber das muss man natürlich nicht so machen. Dann folgen in ähnlicher Form, wie im alten Programm, die Schlüssel und der Associate Tag. Wichtig: Hier müssen PA-API 5.0 taugliche Schlüssel verwendet werden. also ggf. vorher migrieren. Einige Definitionen des Vorgängerprogramms sind hier entfallen – die finden sich hart verdrahtet in der Include-Datei wieder.

IV. Abfrage-Request erstellen

Dieser Abschnitt entfällt komplett – seine Funktionalität ist in die Include-Datei übergegangen.

V. Amazon abfragen und Antwort entgegennehmen

$json = paapi5($access_key, $secret_key, $associate_tag, $asin);

Die Abfrage ist völlig anders – sie ruft die Funktion in der Include-Datei auf und bekommt als Antwort im Fehlerfall false und bei Erfolg eine JSON-Struktur zurück.

VI. Antwort parsen

if ($json === FALSE) {
  return;
}
$response = json_decode($json);
if ($response === FALSE) {
  return;
}
if (!empty($response->Errors)) {
  return;
}
if (!$response->ItemsResult->Items[0]->ASIN) {
  return;
}
if ($response->ItemsResult->Items[0]->ASIN !== $asin) {
  return;
}
$ama_titel = $response->ItemsResult->Items[0]->ItemInfo->Title->DisplayValue;
$ama_medium = $response->ItemsResult->Items[0]->Images->Primary->Medium;
$ama_page_url = $response->ItemsResult->Items[0]->DetailPageURL;
$ama_preis = $response->ItemsResult->Items[0]->Offers->Listings[0]->Price->DisplayAmount;
if (!empty($response->ItemsResult->Items[0]->ItemInfo->Features->DisplayValues)) {
  $ama_feature = '<ul>';
  foreach($response->ItemsResult->Items[0]->ItemInfo->Features->DisplayValues as $feature) {
    $ama_feature .= '<li>'.$feature.'</li>';
  };
  $ama_feature .= '</ul>';
  $ama_beschreibung = $ama_feature;
} else {
  $ama_beschreibung = "";
}

Zum einen wird anstelle von XML jetzt JSON geparst, zum anderen ist die Struktur anders und es sind nicht mehr alle Daten aus der Version 4 vorhanden, wie zum Beispiel die EditorialReviews. Wer hier Änderungen vornehmen möchte, der sollte sich über das Scratchpad an die gewünschten Datenfelder heran tasten.

VII. Bilder abrufen

$mediumImg = $cachefolder."/".$asin.".jpg";
$ch = curl_init($ama_medium->URL);
$zieldatei = fopen($mediumImg, "w");
curl_setopt($ch, CURLOPT_FILE, $zieldatei);
curl_setopt($ch, CURLOPT_TIMEOUT, 600);
curl_exec($ch);
fclose($zieldatei);

Hier ändert sich nur der Dateiname der Bilddatei. Nachdem es in den JSON-Daten keine eindeutige Abfrage-Id mehr gibt, verwende ich die ASIN als Dateiname. (Was natürlich voraussetzt, dass zu einem Produkt immer nur ein Bild abgerufen wird.)

amaprox.php komplett

Wie gesagt, oben habe ich nur die im Vergleich zur Version 4 geänderten Sektionen aufgeführt. Jetzt kommt das Programm komplett:

<?php

// I. Definitionen
require "paapi5.php";

$access_key = "ABCDEFGHIJKLMNO";
$secret_key = "AbCdEfGhIjKlMnOpQrStUvWxYz";
$associate_tag = "wwwmeinesite-21";

$cachefolder = "cache";
$amaprox_homeURL = "https://www.meine-site.de/amaprox";

// II. Parameter übernehmen
if (isset($_GET["template"]) && !empty($_GET["template"])) {
  $template = $_GET["template"];
} else {
  $template = "widebox";
}
if (isset($_GET["asin"]) && !empty($_GET["asin"])) {
  $asin = $_GET["asin"];
} else {
  return;
}

// III. Cache Verzeichnis bereinigen
$files = glob($cachefolder . '/*');
foreach($files as $file) {
  if(is_file($file) && (time() - filemtime($file) > 10)) {
    unlink($file);
  }
}

// IV. Abfrage-Request erstellen
// entfällt - wird durch paapi5.php erledigt

// V. Amazon abfragen und Antwort entgegennehmen
$json = paapi5($access_key, $secret_key, $associate_tag, $asin);

// VI. Antwort parsen
if ($json === FALSE) {
  return;
}
$response = json_decode($json);
if ($response === FALSE) {
  return;
}
if (!empty($response->Errors)) {
  return;
}
if (!$response->ItemsResult->Items[0]->ASIN) {
  return;
}
if ($response->ItemsResult->Items[0]->ASIN !== $asin) {
  return;
}
$ama_titel = $response->ItemsResult->Items[0]->ItemInfo->Title->DisplayValue;
$ama_medium = $response->ItemsResult->Items[0]->Images->Primary->Medium;
$ama_page_url = $response->ItemsResult->Items[0]->DetailPageURL;
$ama_preis = $response->ItemsResult->Items[0]->Offers->Listings[0]->Price->DisplayAmount;
if (!empty($response->ItemsResult->Items[0]->ItemInfo->Features->DisplayValues)) {
  $ama_feature = '<ul>';
  foreach($response->ItemsResult->Items[0]->ItemInfo->Features->DisplayValues as $feature) {
    $ama_feature .= '<li>'.$feature.'</li>';
  };
  $ama_feature .= '</ul>';
  $ama_beschreibung = $ama_feature;
} else {
  $ama_beschreibung = "";
}

// VII. Bilder abrufen
$mediumImg = $cachefolder."/".$asin.".jpg";
$ch = curl_init($ama_medium->URL);
$zieldatei = fopen($mediumImg, "w");
curl_setopt($ch, CURLOPT_FILE, $zieldatei);
curl_setopt($ch, CURLOPT_TIMEOUT, 600);
curl_exec($ch);
fclose($zieldatei);

// VIII. HTML Code generieren
switch ($template) {
  case "widebox":
    $a=' <div style="border: 1px solid #aaa; padding: 5px; margin: 30px 0;">';
    $a.='  <div style="width: '.$ama_medium->Width.'px; float: left; margin-right: 16px;">';
    $a.='   <a href="'.$ama_page_url.'" target="_blank" rel="nofollow"><img src="'.$amaprox_homeURL.'/'.$mediumImg.'" style="border: 0;" width="'.$ama_medium->Width.'" height="'.$ama_medium->Height.'" border="0"></a>';
    $a.='  </div>';
    $a.='  <div>';
    $a.='   <p style="padding-bottom: 5px;">';
    $a.='    <a href="'.$ama_page_url.'" target="_blank rel="nofollow"">'.$ama_titel.'</a>';
    $a.='   </p>';
    $a.='   <p style="padding-bottom: 5px; margin-bottom: 0;"><strong>Preis: <span style="color: #990000;">'.$ama_preis.'</span></strong></p>';
    $a.='   <div style="font-size: 12px; line-height: 16px;">'.$ama_beschreibung.'</div>';
    $a.='  </div>';
    $a.='  <div style="clear: both;"></div>';
    $a.=' </div>';
    break;
  case "smallbox":

    break;
  case "link":
    $a=' <div style="border: 1px solid #ff9201; padding: 5px; margin: 6px 0 -10px 0;">';
    $a.=' <p><a href="'.$ama_page_url.'" target="_blank" rel="nofollow">'.$ama_titel.'</a></p>';
    $a.=' </div>';
    break;
  default:
    $a='';
}

// IX. HTML absenden
header("Content-Type: text/html; charset=UTF-8");
echo $a;

?>

Wer sich mit dem Programmcode noch etwas überfordert fühlt, dem empfehle ich durchaus, einen Blick zurück auf den Teil 2 dieser Artikelserie zu werfen. Da geht es zwar noch um die PA-API 4, aber das Amazon Proxy PHP Programm ist etwas ausführlicher erklärt. Aus diesem Artikel möchte ich auch wiederholen, dass das Amazon Proxy Programm ein recht simples Konstrukt ist, das zwar funktioniert, aber auch nach Verbesserungen ruft. Verbesserungen zum Beispiel durch Werbekennzeichnung, Kaufen-Button, besseres Fehlerhandling, Logging, Reporting, wenn verlinkte Amazon Produkte nicht mehr verfügbar sind, oder Caching. Potential gibt es reichlich.

Und sonst noch?

Hoffen wir, dass die Amazon Product Advertising API 5.0 nun eine Weile Bestand hat und nicht schon bald wieder dermaßen gravierende Änderungen vom Amazon vorgenommen werden. Eine Anekdote am Rande: Amazon Partner (Associates), die sich im Amazon Partnernet ihren Verdienst ansehen, bekommen per Januar 2020 immer noch in der Kopfzeile den Hinweis: Neu: Link Builder Plugin und den entsprechenden Link dazu. Wer den klickt, erhält auf der Seite des Amazon Associates Link Builder den Hinweis: Achtung: Das Amazon Associate Link Builder Plug-in wird am 9. März 2020 eingestellt. Damit endet wohl Amazons (erster) Versuch, selbst ein WordPress Plugin für die eigenen Produktlinks anzubieten. Schade ist es darum nicht, das Teil war datenschutzmäßig eher bedenklich und hat nun scheinbar den Schritt zur PA-API 5.0 nicht geschafft. So wie übrigens viele andere WordPress Plugins, die diesen Zweck verfolgt haben, auch nicht. Ich denke, ich lehne mich nicht zu weit aus dem Fenster mit der Prognose, dass es nach Abschaltung der PA-API 4 keine kostenlosen Amazon Werbungs-Plugins mehr geben wird, die auch noch der DSGVO genügen. Bleibt nur, ein entsprechendes Plugin zu kaufen, oder selber zu programmieren – wie es geht habe ich in dieser Artikelserie gezeigt.

Weitere Artikel in dieser Kategorie:

7 Kommentare

  1. Achim Schmidtmann

    Hallo Herr Karger,
    ganz herzlichen Dank für Ihre sehr hilfreichen Beiträge. So habe ich es relativ schnell geschafft, die neue API einzubauen. Aktuell stolpere ich nur darüber, dass ich gelegentlich bei einer Anfrage ein False ($json === FALSE) zurückbekomme, haber leider nicht weiß, wie ich an weitere Informationen zu diesem False/Fehler kommen kann. (z.B. auf https://www.vaterglueck.de/autospiele.php unter Buchtipps – hier wird keine Liste erzeugt.)

    Es wäre super, wenn Sie mir da weiterhelfen könnten.
    Herzlichen Dank und viele Grüße
    Achim Schmidtmann

    Antworten
    1. Helmut (Beitrag Autor)

      Interessant, dass Ihre Amazon-Links ganz anders aussehen, als meine. Aber das ist hier nicht das Problem.
      Experimentieren Sie ein wenig mit dem Scratchpad (oben im Artikel verlinkt), geben Sie dort Ihre API-Keys ein und die ASIN des betreffenden Produkts. Dann können Sie unten sehen, was die API genau zurück liefert.

      Antworten
  2. Anonymous

    Hallo.
    Danke für den Artikel!
    Kennen sie eine Möglichkeit, auch die Bewertungen (Sternchen) für ein Produkt anzufragen? Welche Ressource muss denn dazu eingebunden werden?
    Viele Grüße!

    Antworten
    1. Helmut (Beitrag Autor)

      Bei der API 4 ging das nicht, da hab ich explizit mal nachgeforscht. Bei der API 5.0 bin ich mir nicht ganz sicher. Am besten mal mit dem Scratchpad experimentieren. Nachdem die API 5 aber (noch) nicht mehr bietet, als die 4er, glaube ich nicht, dass das geht. Die WordPress-Plugins, die das anbieten, rufen vermutlich die Amazon Produkt-Webseite ab und holen sich die Sternchen da raus.

      Antworten
  3. Oleg

    Hallo Herr Karger,

    besten Dank für Ihre(n) Artikel zum Amazon-Api!

    Nach langem Durchstöbern der Amazon-Api-Dokumentation, die tatsächlich sehr unübersichtlich ist und wo man vermutlich mehrere Tage (Wochen?) braucht, um als Hobby-Programmierer zum vernünftigen Ergebnis zu kommen, habe ich Ihre Seite entdeckt.
    Ihr Blog ist die erste Website im deutschen Internet (zumindest die ich gefunden habe), die diese Problematik (praktischer Api-Einsatz) unkompliziert und trotzdem ausführlich beschreibt und sogar den (fast) fertigen Code liefert. Toll, vielen herzlichen Dank dafür! Werde‘ versuchen, den Code für meine eigene Website noch etwas zu modifizieren, aber zumindest habe ich jetzt endlich den Durchblick, wo‘s lang geht.

    Ich schreibe selten Kommentare, im Fall Ihres Artikels muss aber wirklich gelobt werden.

    Viele Grüße aus München

    Oleg

    Antworten
  4. Stefan Enzian

    Danke für die Artikelserie!
    Noch eine Anmerkung, die vielleicht hilfreich für andere sein könnte: Der Fehler „Error TooManyRequests
    The request was denied due to request throttling. Please verify the number of requests made per second to the Amazon Product Advertising API.“ beim Aufruf im Sratchpad kann laut einer Antwort des Amazon-Supports in einem Blogpost auftreten, wenn der Key gerade erst generiert wurde:“Looking into your issue, I see that your current API key pair was created today. API keys can take a minimum of 72 hours to provision and be ready for use.”
    Die Fehlermeldung ist in diesem Fall ärgerlich irreführend :-/

    Antworten
  5. Martin

    Guter Artikel, allerdings ist der Teil „if (!empty($response->Errors))“ unnötig, da die Rückmeldung bei falscher ASIN oder falschen Daten immer ein 400 BadRequest (oder ähnlich) auswirft. Daher gibt es dann natürlich keinen Body, der sich auswerten lässt. Oder was mache ich falsch?

    Antworten

Schreiben Sie einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert