mcpField
B
browsing-bluesky

browsing-bluesky

github.com/oaustegard生产力15748 次安装1 天前更新
代码仓库

关于 browsing-bluesky

这是一个通过公共 API 和可选认证账户研究 Bluesky 的 Python skill,适合需要检索社交内容的研究者。它涵盖帖子、动态、趋势、讨论串和社交关系,并支持账户分析。

主要功能

  1. 01搜索帖子和用户
  2. 02读取资料、动态与讨论串
  3. 03查看趋势和 firehose 样本
  4. 04检查点赞、转发和引用
  5. 05分析账户与社交关系

适用场景

  1. 01研究某个主题的讨论
  2. 02跟踪用户近期帖子
  3. 03探索热门主题和帖子
  4. 04归类关注或指定的账户

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/oaustegard/claude-skills --skill browsing-bluesky

安装后在 Claude Code 中输入/browsing-bluesky确认已加载。

包含的文件

除 SKILL.md 外,安装时一起下载的参考资料和脚本。

__init__.py
CHANGELOG.md
README.md
scripts/
__init__.py
bsky.py
image_transcribe.py
zeitgeist-sample.js
tests/
test_auth_identity.py

详细介绍

浏览 Bluesky

通过公共 API 和实时 firehose 访问 Bluesky 内容。支持可选身份验证,以获取个性化信息流。包含用于分类的账户分析。

实现

将技能目录添加到路径并导入:

import sys
sys.path.insert(0, '/path/to/skills/browsing-bluesky')  # or use .claude/skills symlink path
from browsing_bluesky import (
    # Core browsing
    search_posts, get_user_posts, get_profile, get_feed_posts, sample_firehose,
    get_thread, get_quotes, get_likes, get_reposts,
    get_followers, get_following, search_users,
    # Trending
    get_trending, get_trending_topics,
    # Account analysis
    get_all_following, get_all_followers, extract_post_text,
    extract_keywords, analyze_account, analyze_accounts,
    # Authentication utilities
    is_authenticated, get_authenticated_user, authenticated_identity,
    clear_session
)

身份验证(可选)

身份验证可启用个性化信息流(例如 Paper Skygest),这类信息流需要知道请求者是谁。

设置
  1. 在 Bluesky 创建应用密码:Settings → Privacy and Security → App Passwords
  2. 设置环境变量:
    export BSKY_HANDLE="yourhandle.bsky.social"
    export BSKY_APP_PASSWORD="xxxx-xxxx-xxxx-xxxx"
    
使用哪个账户读取

系统可识别两组凭据,它们的唯一区别是前缀:

凭据对身份
MUNINN_BSKY_HANDLE / MUNINN_BSKY_APP_PASSWORDmuninn — 优先使用
BSKY_HANDLE / BSKY_APP_PASSWORDowner — 未设置 Muninn 凭据对时使用

BSKY_IDENTITY=muninn|owner 可直接指定其中一个身份,且不会用其他凭据对替代指定的凭据:如果请求 muninn,但未设置 Muninn 凭据对,则会读取公共内容,而不会悄悄改用所有者账户。无法识别的值会引发错误。

这一点很重要,因为已启动的容器同时持有两组凭据。直到 2026-08-28,未加前缀的凭据对优先使用,因此所有经过身份验证的读取——包括下方的信息流,以及影响所有信息流的静音、屏蔽和标签器——返回的都是账户所有者的内容,输出中却没有任何提示。这个技能文档声明为只读,但实际持有的应用密码带有所有者账户的写入权限。对于仅配置了文档所述 BSKY_* 凭据对的机器,则没有任何变化。

行为
  • 透明:所有函数在有无凭据时的行为都相同
  • 自动:存在凭据时,会尽可能添加身份验证标头
  • 优雅降级:身份验证失败时会静默回退到公共访问。拼写错误的 BSKY_IDENTITY 属于配置错误,而非身份验证失败,会引发错误
  • 安全:令牌仅缓存在内存中,不会记录日志或持久化
检查身份验证状态
if is_authenticated():
    print(f"Logged in as: {get_authenticated_user()}")
else:
    print("Using public access")

# Which pair answered — a handle alone does not say whether it was chosen
# or simply the only one set.
authenticated_identity()   # {'identity': 'muninn', 'handle': ..., 'did': ...}

# Clear session if needed (e.g., switching accounts or identities)
clear_session()

研究工作流

调查主题

使用 search_posts(),并采用与 bsky.app 高级搜索匹配的查询语法:

  • 基本词语:event sourcing
  • 精确短语:"event sourcing"
  • 用户筛选:from:acairns.co.uk,或使用 author= 参数
  • 日期筛选:since:2025-01-01,或使用 since= 参数
  • 话题标签、提及、域名链接:#python mentions:user domain:github.com

将查询语法与函数参数结合,以执行复杂搜索。

监控用户
  1. 使用 get_profile(handle) 获取个人资料以了解背景(简介、关注者数量、帖子数量)
  2. 使用 get_user_posts(handle, limit=N) 获取近期帖子
  3. 如需查找用户发布的特定主题内容,请使用 search_posts(query, author=handle)
发现热门趋势

推荐工作流——先调用趋势 API,再用 firehose 深入分析:

1. 快速扫描热门主题(约 500 个令牌)
topics = get_trending_topics(limit=10)
# Returns: {topics: [{topic, display_name, description, link}, ...],
#           suggested: [...]}
2. 获取包含帖子数量和参与者的详细趋势
trends = get_trending(limit=10)
for t in trends:
    print(f"{t['display_name']} — {t['post_count']} posts ({t['status']})")
# Each trend includes: topic, display_name, link, started_at,
#   post_count, status, category, actors
3. 针对选定的趋势进行探索
posts = search_posts(trend["topic"], limit=25)
4. 可选:使用 Firehose 监控传播速度或发现长尾趋势

前提条件:每个会话安装一次 Node.js 依赖项:

cd /home/claude && npm install ws https-proxy-agent 2>/dev/null
data = sample_firehose(duration=30)  # Full firehose sample
data = sample_firehose(duration=20, filter="python")  # Filtered sample

返回包含以下键的字典:

  • window:{startTime, endTime, durationSeconds} — 采样时间范围
  • stats:{totalReceived, totalPosts, postsPerSecond, filter, languages} — 数量指标和语言分布
  • topWords:[[word, count], ...] — 前 50 个词语(count >= 3)
  • topPhrases:[[bigram, count], ...] — 前 30 个二元词组(count >= 2)
  • topTrigrams:[[trigram, count], ...] — 前 20 个三元词组(count >= 2)
  • entities:[[entity, count], ...] — 前 25 个用户句柄/话题标签(count >= 2)
  • samplePosts:[{text, altTexts, hasImages}, ...] — 前 50 条匹配的帖子
阅读 Feed 和列表

get_feed_posts() 接受:

  • 列表 URL:https://bsky.app/profile/austegard.com/lists/3lankcdrlip2f
  • Feed URL:https://bsky.app/profile/did:plc:xxx/feed/feedname
  • AT-URI:at://did:plc:xxx/app.bsky.graph.list/xyz

此函数会自动从 URL 中提取 AT-URI。

探索话题串

获取帖子的完整话题串上下文,包括父帖和回复:

thread = get_thread("https://bsky.app/profile/user/post/xyz", depth=10)
# Returns: {post: {...}, parent: {...}, replies: [...]}
查找引用帖子

查找引用特定帖子的帖子:

quotes = get_quotes("https://bsky.app/profile/user/post/xyz")
for q in quotes:
    print(f"@{q['author_handle']}: {q['text'][:80]}")
分析互动情况

获取与帖子互动的用户:

likes = get_likes(post_url)
reposts = get_reposts(post_url)

# Accepts both URLs and AT-URIs
likes = get_likes("at://did:plc:.../app.bsky.feed.post/...")
读取嵌入图片

每篇解析后的帖子都包含一个 images 字段,这是一个列表,其中每张嵌入图片对应一个 {alt, url, transcription} 字典。旧版 image_alts: list[str] 字段仍予以保留(仅包含非空的 alt 文本)。

当 alt 文本缺失且图片内容很重要时,可通过任意帖子获取函数(get_user_posts、search_posts、get_feed_posts、get_thread、get_quotes)的 transcribe 参数选择启用模型转录:

# Routine/bulk work (zeitgeist, inbox review, news scans) —
# gemini-2.5-flash-lite is the recommended default. Cheapest production
# model anywhere ($0.10/$0.40 per 1M tokens), ~95% accuracy on dense
# screenshots in May 2026 benchmarks:
posts = get_user_posts("ayourtch.bsky.social", limit=40, transcribe="gemini-lite")

# Token-perfect transcription, still cheap:
posts = get_user_posts(..., transcribe="gemini-flash")

# Frontier model with thinking_level=minimal — for cases where the image
# content needs reasoning, not just transcription:
posts = get_user_posts(..., transcribe="gemini-3.5-flash")

# Anthropic single-vendor option (note: empirically weaker prompt-following
# than Gemini on dense transcription — Haiku tends to summarize rather
# than transcribe):
posts = get_user_posts(..., transcribe="haiku")

# Interactive sessions where image is part of the active task and you want
# conversation context to inform interpretation (only available on Anthropic):
thread = get_thread(post_url, transcribe="opus")

# Default (no transcription) — current behavior preserved:
posts = get_user_posts("ayourtch.bsky.social", limit=40)

所有调用方都遵循同一策略:不会转录 alt 文本非空的图片(作者已经描述了图片内容,应予以信任)。只有 alt 文本缺失或为空的图片才会发送给模型。网络或 API 故障会使 transcription 保持为 None;调用方会静默降级。

成本/质量实测数据(2026 年 5 月,n=3 张内容密集的终端截图,每张各运行一次——样本量较小,仅供参考):

别名延迟$/张图片和弦 Token 召回率
gemini-lite~8s~$0.00195%
gemini-flash~10s~$0.003100%
gemini-3.5-flash~10s~$0.014100%
haiku~7s~$0.00818%(生成摘要)
opus~20s~$0.1291%

haiku 和 opus 两行数据是在 Haiku 4.5 和 Opus 4.7 上测得的。这些别名目前解析为 claude-haiku-5-5 和 claude-opus-5-5;尚未重新测量这两行数据。

haiku / opus 别名需要 ANTHROPIC_API_KEY(或 /mnt/project/claude.env 中的 API_KEY);gemini-* 别名则需要 /mnt/project/proxy.env 中的 CF AI Gateway 凭据。只有设置了该参数才会触发转录,因此没有相关凭据的调用方可以改用其他别名,或关闭此功能。

探索社交关系图

浏览关注者/关注关系:

followers = get_followers("handle.bsky.social")
following = get_following("handle.bsky.social")

# Returns list of actor dicts with handle, display_name, did, description, etc.
查找用户

按姓名、账号名或简介搜索用户:

users = search_users("machine learning researcher")
for u in users:
    print(f"{u['display_name']} (@{u['handle']}): {u['description'][:100]}")

API 端点说明

  • 公共 AppView:使用 https://api.bsky.app/xrpc/ 进行无需身份验证的读取
  • PDS:使用 https://bsky.social/xrpc/ 发送经过身份验证的请求
  • 趋势:app.bsky.unspecced.getTrends(丰富)和 app.bsky.unspecced.getTrendingTopics(轻量)
  • Firehose:wss://jetstream1.us-east.bsky.network/subscribe
  • 端点路由会自动完成——经过身份验证的请求发送到 PDS,公共请求发送到 AppView
  • 速率限制存在,但对读取操作较宽松

返回格式

所有 API 函数都会返回结构化字典,包含:

  • uri:AT 协议标识符
  • text:帖子内容
  • created_at:ISO 时间戳
  • author_handle:用户账号名
  • author_name:显示名称
  • likes、reposts、replies:互动计数
  • links:从帖子 facets 中提取的完整 URL(帖子文本会将 URL 截断为“...”)
  • image_alts:嵌入图片的 alt 文本
  • url:帖子在 bsky.app 上的直接链接

个人资料函数返回:handle、display_name、description、followers、following、posts、did

账号分析

分析账号,以便按主题进行分类。获取个人资料和帖子,提取关键词,并返回结构化数据,供 Claude 进行分类。

分析用户的社交网络
# Analyze accounts you follow
results = analyze_accounts(following="yourhandle.bsky.social", limit=50)

# Analyze your followers
results = analyze_accounts(followers="yourhandle.bsky.social", limit=50)

# Analyze specific handles
results = analyze_accounts(handles=["user1.bsky.social", "user2.bsky.social"])
单个账号分析
analysis = analyze_account("user.bsky.social")
# Returns: {handle, display_name, description, keywords, post_count, followers, following}
关键词提取选项

停用词参数可过滤特定领域的噪声:

  • "en":英语(通用,默认)
  • "ai":AI/ML 领域(过滤技术套话)
  • "ls":生命科学(过滤研究方法内容)
results = analyze_accounts(following="handle", stopwords="ai")

需要:用于提取关键词的 extracting-keywords 技能和 YAKE venv。

筛选账号
results = analyze_accounts(
    following="handle",
    exclude_patterns=["bot", "spam", "promo"]  # Skip accounts matching these
)
分页获取关注对象/关注者

对于超出 get_following/get_followers 的 100 个上限的大型账号列表:

all_following = get_all_following("handle", limit=500)  # Handles pagination
all_followers = get_all_followers("handle", limit=500)
账号分析输出

每个经过分析的账号都会返回:

{
    "handle": "user.bsky.social",
    "display_name": "User Name",
    "description": "Bio text here",
    "keywords": ["keyword1", "keyword2", "keyword3"],
    "post_count": 20,
    "followers": 1234,
    "following": 567
}

Claude 会使用简介和关键词,按主题对账号进行分类,而无需硬编码规则

评论

支持 Markdown