🧪 Skills

zotero-myscholar

将论文保存到 Zotero 文库,请按照 userid:apiKey 的格式配置 ZOTERO_CREDENTIALS 环境变量。

v1.0.0
❤️ 0
⬇️ 72
👁 1
Share

Description


name: zotero-scholar description: 将论文保存到 Zotero 文库,请按照 userid:apiKey 的格式配置 ZOTERO_CREDENTIALS 环境变量。 homepage: https://www.zotero.org metadata: { "openclaw": { "emoji": "📚", "requires": { "bins": ["uv"], "env": ["ZOTERO_CREDENTIALS"] }, "primaryEnv": "ZOTERO_CREDENTIALS", "install": [ { "id": "brew", "kind": "brew", "formula": "uv", "bins": ["uv"], "label": "Install uv (brew)", }, ], } }

Zotero Scholar

专业的文献入库助手。可以将论文元数据、PDF 链接以及 AI 生成的总结一键保存到你的 Zotero 库中。

使用示例

可以读取环境变量 ZOTERO_CREDENTIALS 中的 Zotero 凭据,格式为 userid:apiKey

使用环境变量运行

uv run {baseDir}/scripts/save_paper.py \
  --title "Attention Is All You Need" \
  --authors "Vaswani et al." \
  --url "https://arxiv.org/abs/1706.03762"

参数说明

参数 说明
--title 论文标题
--authors 作者列表(逗号分隔)
--url 论文链接 (用于排重)
--abstract 论文摘要
--summary (AI 生成) 简短总结或 Insight
--tags 标签列表(逗号分隔)
save_paper.py文件内容:
#!/usr/bin/env python3

/// script

requires-python = ">=3.10"

dependencies = ["pyzotero>=1.6.0"]

///

import argparse import os import sys from pyzotero import zotero

def main(): parser = argparse.ArgumentParser(description="保存论文到 Zotero 文献库") parser.add_argument("--title", required=True, help="论文标题") parser.add_argument("--authors", required=True, help="作者列表,以逗号分隔") parser.add_argument("--url", required=True, help="论文链接(用于查重)") parser.add_argument("--abstract", help="论文摘要") parser.add_argument("--summary", help="AI 生成的摘要") parser.add_argument("--tags", help="标签列表,以逗号分隔")

args = parser.parse_args()

library_id = None
api_key = None

zotero_creds = os.environ.get('ZOTERO_CREDENTIALS')
if zotero_creds and ':' in zotero_creds:
    try:
        parts = zotero_creds.strip().split(':')
        if len(parts) == 2:
            library_id = parts[0].strip()
            api_key = parts[1].strip()
    except:
        pass

library_type = 'user' # 默认使用个人文献库

if not library_id or not api_key:
    print("错误:需要 Zotero 凭据。", file=sys.stderr)
    print("请设置 ZOTERO_CREDENTIALS='userID:apiKey'(用于 UI 配置)", file=sys.stderr)
    sys.exit(1)

try:
    zot = zotero.Zotero(library_id, library_type, api_key)

    # 通过 URL 检查是否已存在
    # 使用搜索查询匹配 URL
    print(f"正在检查是否已存在该条目:{args.url}...")
    items = zot.items(q=args.url, limit=1)

    if items:
        print(f"该条目已存在:{items[0].get('data', {}).get('title', '未知')}")
        # 暂时跳过更新,避免覆盖用户数据
        print(f"Zotero 链接:https://www.zotero.org/{library_id}/items/{items[0]['key']}")
        return

    # 创建新条目
    template = zot.item_template('journalArticle')
    template['title'] = args.title

    # 格式化作者信息
    creators = []
    for author in args.authors.split(','):
        name_parts = author.strip().split(' ')
        if len(name_parts) > 1:
            creators.append({'creatorType': 'author', 'firstName': ' '.join(name_parts[:-1]), 'lastName': name_parts[-1]})
        else:
            creators.append({'creatorType': 'author', 'lastName': author.strip(), 'firstName': ''})
    template['creators'] = creators

    template['url'] = args.url
    if args.abstract:
        template['abstractNote'] = args.abstract

    # 添加标签
    if args.tags:
        template['tags'] = [{'tag': t.strip()} for t in args.tags.split(',')]

    print(f"正在创建条目:{args.title}...")
    resp = zot.create_items([template])

    if resp.get('successful'):
        new_item = resp['successful']['0']
        item_key = new_item['key']
        print(f"条目创建成功!")

        # 将摘要添加为笔记
        if args.summary:
            print("正在添加摘要笔记...")
            note_template = zot.item_template('note')
            note_template['note'] = f"<h3>AI 摘要</h3><p>{args.summary}</p>"
            note_template['parentItem'] = item_key
            zot.create_items([note_template])
            print("笔记已添加。")

        # 下载并附加 PDF
        if 'arxiv.org' in args.url:
            try:
                import urllib.request
                import tempfile

                # 将摘要链接转换为 PDF 链接
                pdf_url = args.url.replace('/abs/', '/pdf/')
                if not pdf_url.endswith('.pdf'):
                    pdf_url += '.pdf'

                print(f"正在下载 PDF...")

                # 设置 User-Agent 以支持下载
                opener = urllib.request.build_opener()
                opener.addheaders = [('User-agent', 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) Chrome/120.0.0.0')]
                urllib.request.install_opener(opener)

                # 创建安全的文件名
                safe_title = "".join(c for c in args.title if c.isalnum() or c in (" ", "-", "_")).strip()
                safe_title = safe_title[:50] # 限制长度
                safe_filename = f"{safe_title}.pdf"

                # 使用临时目录,但指定文件名
                with tempfile.TemporaryDirectory() as td:
                    pdf_path = os.path.join(td, safe_filename)
                    urllib.request.urlretrieve(pdf_url, pdf_path)

                    print(f"正在上传 PDF 附件({safe_filename})...")
                    zot.attachment_simple([pdf_path], item_key)
                    print("PDF 已附加。")

            except Exception as e:
                print(f"附加 PDF 失败:{e}", file=sys.stderr)

        print("注意: 请在 Zotero 客户端点击 '同步' (Sync) 按钮以获取云端 PDF 文件。")
        print("         如果是 Web API 写入,本地客户端必须同步才能看到附件内容。")

    else:
        print(f"创建条目失败:{resp}", file=sys.stderr)
        sys.exit(1)

except Exception as e:
    print(f"错误:{e}", file=sys.stderr)
    sys.exit(1)

if name == "main": main()

Reviews (0)

Sign in to write a review.

No reviews yet. Be the first to review!

Comments (0)

Sign in to join the discussion.

No comments yet. Be the first to share your thoughts!

Compatible Platforms

Pricing

Free

Related Configs