#!/usr/bin/env python3 """B站搜索。通过 Bilibili Web API(无需认证即可搜索)。""" from __future__ import annotations import sys from search_utils import build_parser, get_client, get_key, make_item, make_result, print_json SEARCH_URL = "https://api.bilibili.com/x/web-interface/search/all/v2" def search(query: str, limit: int, cookie: str | None = None, order: str = "") -> list[dict]: """执行 B站搜索。""" headers = { "Referer": "https://www.bilibili.com", "Origin": "https://www.bilibili.com", } if cookie: headers["Cookie"] = cookie params = { "keyword": query, "page": 1, "page_size": min(limit, 50), } if order: params["order"] = order with get_client(headers=headers) as client: resp = client.get(SEARCH_URL, params=params) resp.raise_for_status() data = resp.json() if data.get("code") != 0: msg = data.get("message", "未知错误") raise RuntimeError(f"B站 API 返回错误: {msg}") items = [] # 结果在 data.data.result 中,按类型分组 result_groups = data.get("data", {}).get("result", []) for group in result_groups: result_type = group.get("result_type", "") if result_type not in ("video", "media_bangumi", "media_ft", "article"): continue for entry in group.get("data", []): title = _strip_html(entry.get("title", "")) if result_type == "video": bvid = entry.get("bvid", "") url = f"https://www.bilibili.com/video/{bvid}" if bvid else entry.get("arcurl", "") items.append(make_item( title=title, url=url, snippet=entry.get("description", "")[:300], author=entry.get("author", ""), play=entry.get("play", 0), like=entry.get("like", 0), pubdate=entry.get("pubdate"), type="video", )) elif result_type == "article": url = f"https://www.bilibili.com/read/cv{entry.get('id', '')}" items.append(make_item( title=title, url=url, snippet=entry.get("desc", "")[:300], author=entry.get("author_name", ""), view=entry.get("view", 0), type="article", )) if len(items) >= limit: break if len(items) >= limit: break return items[:limit] def _strip_html(html: str) -> str: import re return re.sub(r"<[^>]+>", "", html).strip() def main(): parser = build_parser("搜索 B站视频和文章") parser.add_argument("--cookie", help="B站 Cookie(也可通过 BILIBILI_COOKIE 环境变量设置,可选)") parser.add_argument("--order", default="", choices=["", "totalrank", "click", "pubdate", "dm", "stow"], help="排序:空=综合, totalrank=最佳匹配, click=播放, pubdate=最新, dm=弹幕, stow=收藏") args = parser.parse_args() cookie = get_key("BILIBILI_COOKIE", args.cookie) try: items = search(args.query, args.limit, cookie, args.order) print_json(make_result(True, args.query, "bilibili", items)) except Exception as e: print_json(make_result(False, args.query, "bilibili", [], str(e))) sys.exit(1) if __name__ == "__main__": main()