smoke_douyin_blogger.py 2.7 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677
  1. """Manual live smoke for the Crawapi douyin blogger contract (V2-M5D).
  2. Hits POST <CONTENTFIND_API_CRAWAPI_BASE_URL><CONTENTFIND_DOUYIN_BLOGGER_PATH>
  3. with the fixed three-field payload (account_id / sort_type / cursor) and prints
  4. a redacted summary only — never the raw response, never any credential.
  5. Not part of default pytest. Run manually:
  6. uv run python scripts/smoke_douyin_blogger.py --author-id '<sec_uid>'
  7. """
  8. from __future__ import annotations
  9. import argparse
  10. import json
  11. import sys
  12. from pathlib import Path
  13. import httpx
  14. ROOT = Path(__file__).resolve().parents[1]
  15. sys.path.insert(0, str(ROOT))
  16. from content_agent.integrations.douyin import _env, _load_env_file # noqa: E402
  17. def main() -> int:
  18. args = _parse_args()
  19. env = _load_env_file(args.env_file)
  20. base_url = _env("CONTENTFIND_API_CRAWAPI_BASE_URL", env, required=True)
  21. blogger_path = _env("CONTENTFIND_DOUYIN_BLOGGER_PATH", env, required=True)
  22. sort_type = args.sort_type or _env(
  23. "CONTENTFIND_DOUYIN_ACCOUNT_WORKS_DEFAULT_SORT_TYPE", env, default="最新"
  24. )
  25. url = base_url.rstrip("/") + "/" + blogger_path.lstrip("/")
  26. payload = {"account_id": args.author_id, "sort_type": sort_type, "cursor": args.cursor}
  27. response = httpx.post(
  28. url, json=payload, headers={"Content-Type": "application/json"}, timeout=60.0
  29. )
  30. try:
  31. data = response.json()
  32. except ValueError:
  33. data = {}
  34. if not isinstance(data, dict):
  35. data = {}
  36. data_block = data.get("data") if isinstance(data.get("data"), dict) else {}
  37. items = data_block.get("data") if isinstance(data_block.get("data"), list) else []
  38. summary = {
  39. "endpoint": "/" + blogger_path.lstrip("/"),
  40. "http_status": response.status_code,
  41. "business_code": data.get("code"),
  42. "result_count": len(items),
  43. "has_more": bool(data_block.get("has_more", False)),
  44. "next_cursor_present": bool(data_block.get("next_cursor")),
  45. }
  46. print(json.dumps(summary, ensure_ascii=False, indent=2))
  47. ok = (
  48. summary["http_status"] == 200
  49. and summary["business_code"] in (0, "0")
  50. and summary["result_count"] > 0
  51. )
  52. return 0 if ok else 1
  53. def _parse_args() -> argparse.Namespace:
  54. parser = argparse.ArgumentParser(description=__doc__)
  55. parser.add_argument("--author-id", required=True, help="author platform_author_id (sec_uid)")
  56. parser.add_argument("--sort-type", default=None, help="override sort_type (default from env)")
  57. parser.add_argument("--cursor", default="", help="page cursor, empty for first page")
  58. parser.add_argument("--env-file", default=str(ROOT / ".env"))
  59. return parser.parse_args()
  60. if __name__ == "__main__":
  61. sys.exit(main())