|
@@ -6,14 +6,19 @@ from urllib.parse import urljoin
|
|
|
from typing import List, Literal, Iterable, Iterator
|
|
|
import gzip
|
|
|
from pathlib import Path
|
|
|
-from nb_log import get_logger
|
|
|
+import logging
|
|
|
|
|
|
URL_AUTH = "https://api.amazon.com/auth/o2/token"
|
|
|
URL_AD_API = "https://advertising-api.amazon.com"
|
|
|
|
|
|
cache = TTLCache(maxsize=10, ttl=3200)
|
|
|
|
|
|
-logger = get_logger(__name__)
|
|
|
+logger = logging.getLogger(__name__)
|
|
|
+
|
|
|
+
|
|
|
+class RateLimitError(Exception):
|
|
|
+ def __init__(self, retry_after: str = None):
|
|
|
+ self.retry_after = retry_after
|
|
|
|
|
|
|
|
|
def gz_decompress(file_path: str, chunk_size: int = 1024 * 1024):
|
|
@@ -79,7 +84,11 @@ class BaseClient:
|
|
|
params=params,
|
|
|
json=body,
|
|
|
)
|
|
|
+ if 400 <= resp.status_code <= 500:
|
|
|
+ raise Exception(resp.text)
|
|
|
js = resp.json()
|
|
|
+ if resp.status_code == 429:
|
|
|
+ raise RateLimitError(resp.headers.get("Retry-After"))
|
|
|
return js
|
|
|
|
|
|
|
|
@@ -93,6 +102,17 @@ class SPClient(BaseClient):
|
|
|
}
|
|
|
return self._request(url_path, method="POST", headers=headers, body=body)
|
|
|
|
|
|
+ def iter_campaigns(self, **body) -> Iterator[dict]:
|
|
|
+ if "maxResults" not in body:
|
|
|
+ body["maxResults"] = 100
|
|
|
+ while True:
|
|
|
+ info: dict = self.get_campaigns(**body)
|
|
|
+ yield from info["campaigns"]
|
|
|
+ if not info.get("nextToken"):
|
|
|
+ break
|
|
|
+ body["nextToken"] = info["nextToken"]
|
|
|
+ logger.info(f"总共数量:{info['totalResults']}")
|
|
|
+
|
|
|
def get_ad_groups(self, **body):
|
|
|
url_path = "/sp/adGroups/list"
|
|
|
headers = {
|
|
@@ -208,7 +228,7 @@ class SBClient(BaseClient):
|
|
|
|
|
|
def download_report(self, report_id: str, file_path: str, decompress: bool = True) -> str:
|
|
|
url = urljoin(URL_AD_API, f"/v2/reports/{report_id}/download")
|
|
|
- resp = requests.get(url, headers=self.auth_headers, stream=True)
|
|
|
+ resp = requests.get(url, headers=self.auth_headers, stream=True, allow_redirects=True)
|
|
|
logger.info(f"开始下载报告:{report_id}")
|
|
|
with open(file_path, "wb") as file:
|
|
|
for data in resp.iter_content(chunk_size=10 * 1024):
|
|
@@ -266,8 +286,9 @@ if __name__ == '__main__':
|
|
|
'unitsSold14d',
|
|
|
'attributedBrandedSearches14d',
|
|
|
'topOfSearchImpressionShare']
|
|
|
- sb.get_report(
|
|
|
- record_type="campaigns",
|
|
|
- report_date="20231008",
|
|
|
- metrics=metrics
|
|
|
- )
|
|
|
+ # sb.get_report(
|
|
|
+ # record_type="campaigns",
|
|
|
+ # report_date="20231008",
|
|
|
+ # metrics=metrics
|
|
|
+ # )
|
|
|
+ sb.iter_ad_groups()
|