Files
agent-skills/sn-search-social-cn/scripts/bilibili_search.py
Hermes Agent ccc63d1e70 first commit
2026-05-10 13:52:46 +08:00

104 lines
3.5 KiB
Python
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/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()