probe_platforms.py 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120
  1. """平台数据可下载性 + Gemini 直读 URL 能力 一次测全。
  2. 各平台 detail → 图片/视频字段 → 实下载探测;最后测:远程视频 URL 直接喂 Gemini(不 base64)。
  3. 用法:python scripts/probe_platforms.py <env_file>
  4. """
  5. from __future__ import annotations
  6. import sys
  7. import time
  8. import httpx
  9. CRAW = "http://crawler.aiddit.com"
  10. IOS = "Mozilla/5.0 (iPhone; CPU iPhone OS 16_0 like Mac OS X) AppleWebKit/605.1.15"
  11. REFERER = {"douyin": "https://www.douyin.com/", "kuaishou": "https://www.kuaishou.com/",
  12. "bilibili": "https://www.bilibili.com/", "xiaohongshu": "https://www.xiaohongshu.com/"}
  13. PROBES = [
  14. ("小红书·图文", "/crawler/xiao_hong_shu/detail", "67e4bdf50000000006028a59", "xiaohongshu"),
  15. ("小红书·视频", "/crawler/xiao_hong_shu/detail", "6976f6fd000000001a01eede", "xiaohongshu"),
  16. ("抖音·视频", "/crawler/dou_yin/detail", "7612631899479648866", "douyin"),
  17. ("B站·视频", "/crawler/bilibili/detail", "BV1qd4y1x76w", "bilibili"),
  18. ("快手·视频", "/crawler/kuai_shou/detail", "3xepqgwddgbickc", "kuaishou"),
  19. ]
  20. def load_env(p):
  21. e = {}
  22. for ln in open(p):
  23. ln = ln.strip()
  24. if ln and not ln.startswith("#") and "=" in ln:
  25. k, v = ln.split("=", 1)
  26. e[k.strip()] = v.strip().strip('"').strip("'")
  27. return e
  28. def detail(path, cid):
  29. return httpx.post(CRAW + path, json={"content_id": cid}, timeout=40).json()
  30. def inner(r):
  31. d = ((r.get("data") or {}).get("data")) or {}
  32. if isinstance(d, list):
  33. return d[0] if d else {}
  34. return d if isinstance(d, dict) else {}
  35. def vurl_of(d):
  36. vl = d.get("video_url_list")
  37. if isinstance(vl, list) and vl:
  38. return vl[0].get("video_url") if isinstance(vl[0], dict) else vl[0]
  39. return None
  40. def main():
  41. env_file = sys.argv[1] if len(sys.argv) > 1 and sys.argv[1].endswith(".env") else ".env"
  42. env = load_env(env_file)
  43. or_key = env.get("OPENROUTER_API_KEY")
  44. or_base = (env.get("OPENROUTER_BASE_URL") or "https://openrouter.ai/api/v1").rstrip("/")
  45. model = env.get("OPENROUTER_MODEL") or "google/gemini-3-flash-preview"
  46. for name, path, cid, plat in PROBES:
  47. try:
  48. r = detail(path, cid)
  49. d = inner(r)
  50. il = d.get("image_url_list") or []
  51. mb = d.get("multi_bitrate")
  52. vurl = vurl_of(d)
  53. print(f"\n[{name}] code={r.get('code')} type={d.get('content_type')} "
  54. f"title={(d.get('title') or '')[:26]}")
  55. print(f" 图片={len(il)} 视频链接={'有' if vurl else '无'} "
  56. f"多码率={list(mb.keys()) if isinstance(mb, dict) else mb}")
  57. if vurl:
  58. try:
  59. with httpx.stream("GET", vurl, headers={"User-Agent": IOS,
  60. "Referer": REFERER[plat], "Range": "bytes=0-524287"},
  61. timeout=60, follow_redirects=True) as resp:
  62. chunk = next(resp.iter_bytes(), b"")
  63. print(f" ↓视频: http={resp.status_code} "
  64. f"type={resp.headers.get('content-type')} magic={chunk[4:12]!r}")
  65. except Exception as e:
  66. print(" ↓视频失败:", str(e)[:80])
  67. elif il:
  68. u = il[0] if isinstance(il[0], str) else il[0].get("image_url")
  69. try:
  70. resp = httpx.get(u, timeout=30, follow_redirects=True)
  71. print(f" ↓图片: http={resp.status_code} "
  72. f"type={resp.headers.get('content-type')} {len(resp.content)}B")
  73. except Exception as e:
  74. print(" ↓图片失败:", str(e)[:80])
  75. time.sleep(16)
  76. except Exception as e:
  77. print(f"[{name}] 失败: {e}")
  78. print("\n=== 关键测试:远程视频 URL 直接喂 Gemini(不下载、不 base64)===")
  79. d = inner(detail("/crawler/dou_yin/detail", "7612631899479648866"))
  80. vurl = vurl_of(d)
  81. body = {"model": model, "messages": [{"role": "user", "content": [
  82. {"type": "text", "text": "这视频在讲什么?一句话。"},
  83. {"type": "video_url", "video_url": {"url": vurl}}]}]}
  84. try:
  85. g = httpx.post(f"{or_base}/chat/completions",
  86. headers={"Authorization": f"Bearer {or_key}", "Content-Type": "application/json"},
  87. json=body, timeout=180)
  88. print(" 抖音远程URL直喂: HTTP", g.status_code)
  89. if g.status_code == 200:
  90. j = g.json()
  91. print(" video_tokens=", j.get("usage", {}).get("video_tokens"),
  92. "→ 远程 URL 可直接处理!")
  93. print(" 回答:", j["choices"][0]["message"]["content"][:120])
  94. else:
  95. print(" 失败:", g.text[:240], "→ 远程 URL 不行,必须下载+base64")
  96. except Exception as e:
  97. print(" 异常:", str(e)[:150])
  98. print("\n===PROBEDONE===")
  99. return 0
  100. if __name__ == "__main__":
  101. raise SystemExit(main())