场景

我有很多个单词对应的 excel 文件,我需要把这些文档导入到 Anki 卡片中去。可以通过 Python+AnkiConnect 实现这个功能。

通过 AnkiConnect API 向 Anki 中创建新的牌组(deck)和卡片(note),数据来源是多个 CSV 文件。

我的表格数据是类似于这样的形式,如下图Responsive Image

image.png

步骤

AnkiConnect 设置

代码通过 ankiconnect_url 将请求发送到本地的 AnkiConnect API(默认在 localhost:8765 端口运行),这是一种允许外部程序与 Anki 进行交互的 API。

创建牌组(create_deck 函数)

该函数用于创建一个新的 Anki 牌组。它通过 AnkiConnect 的 createDeck 动作发送一个请求,如果成功,Anki 会创建一个指定名称的牌组。

创建卡片(create_anki_card 函数)

该函数负责向指定的牌组中添加卡片。它构建一个请求,指定牌组名称、卡片模型(此处为 "form")和卡片字段(通过 CSV 文件获取的数据)。 函数会处理几种常见错误: 如果返回的错误是 cannot create note because it is a duplicate,表示卡片已经存在,跳过创建。 如果返回 deck not found,表示指定的牌组不存在,则会首先创建牌组,然后再次尝试创建卡片。

处理 CSV 文件并创建卡片

代码遍历 CSV 文件。如果文件存在,则读取内容,生成卡片的数据。 每一行 CSV 文件的数据代表一张卡片,数据结构通过字典 note_data 定义,包括字段 numAmeanAwords_A 等。 对每张卡片,调用 create_anki_card 函数将卡片添加到相应的牌组(如 UnitB1UnitB2 等)中。如果卡片是重复的,则跳过并打印提示信息。

代码

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
import csv
import json
import requests
import os

# 设置 AnkiConnect 的 URL
ankiconnect_url = "http://localhost:8765"


def create_deck(deck_name):
    """
    使用 AnkiConnect API 创建一个新的牌组。

    参数:
        deck_name (str): 要创建的新牌组的名称。

    返回:
        dict: 从 AnkiConnect API 返回的响应,包含结果和错误(如果有)。
    """
    request = {
        "action": "createDeck",
        "version": 6,
        "params": {
            "deck": deck_name
        }
    }

    response = requests.post(ankiconnect_url, json=request)
    response_json = response.json()

    return response_json


def create_anki_card(note_data, deck_name):
    # 构建 AnkiConnect 的请求数据
    request = {
        "action": "addNote",
        "params": {
            "note": {
                "deckName": deck_name,
                "modelName": "form",
                "fields": note_data
            }
        }
    }
    # 发送 POST 请求到 AnkiConnect
    response = requests.post(ankiconnect_url, json=request)
    response_json = response.json()

    # 检查是否有错误,如果是因为重复卡片而失败,则返回 None
    if isinstance(response_json, dict) and "error" in response_json:
        if response_json["error"] == "cannot create note because it is a duplicate":
            return None
        elif response_json["error"] == "deck not found":
            # 如果找不到卡组,则先创建它
            create_deck_result = create_deck(deck_name)
            if "error" in create_deck_result:
                print(f"创建牌组 '{deck_name}' 时出错: {create_deck_result['error']}")
                return None
            else:
                # 然后再次尝试创建卡片
                response = requests.post(ankiconnect_url, json=request)
                response_json = response.json()
                return response_json
        else:
            # 其他类型的错误,直接返回
            return response_json
    else:
        return response_json


# 遍历所有 CSV 文件并创建卡片
for i in range(1, 50):
    file_name = f"Unit B{i}.csv"
    deck_name = f"UnitB{i}"

    if os.path.exists(file_name):
        with open(file_name, "r", encoding="utf-8-sig") as file:
            reader = csv.DictReader(file)
            for row in reader:
                note_data = {
                    "numA": row["numA"],
                    "meanA": row["meanA"],
                    "words_A": row["words_A"],
                    "numB": row["numB"],
                    "meanB": row["meanB"],
                    "words_B": row["word_B"]
                }
                result = create_anki_card(note_data, deck_name)
                if result is not None:
                    print(result)
                else:
                    print(f"跳过重复的卡片: {note_data}")