webサイトからAnkiノートを一括作成する
javascript/typescript
, HTML
, css
を使用して、web サイトから Anki ノートを一括作成する方法を紹介します。
まず公式サイトのマニュアルを一読することをおすすめします。これも Immersion の一環です。
カードとノートの違い
Anki のノートとカードの概念がややこしいのでまとめました。
- ノートはフィールドとカード(s)を定義する
- カードはあるノートの表示方法を
HTML
,css
などによって定義する
web サイトからノートを作る
例えば以下のスクリプトで語源まとめサイトから各語源のリンクとタイトルを取得できます。
javascript
// in browser consoledocument.querySelectorAll('.entry-content h3 + ul li a').forEach((a) => console.log(a.href, a.textContent));
リストなどの形式で保存しておきます。
src/targets.tstypescript
export const targets = [{href: 'https://shinuwakaeng.com/a-an-gogen-matome',name: 'a, an (= without 否定/ない)',},// ...];
Anki からノートを定義します。名前は例えばword_root
、フィールドは以下のように定義しました。
定義したフィールドに合わせてタイプを定義します。
src/types.tstypescript
export type Note = {Expression: string;Definition: string;Example: string;Image: string;URL: string;};
先程用意したリストから csv ファイルを出力します。以下の例では Deno を使用しています。Anki は HTML によってカードを表示するので、web サイトからinnerHTML
などのプロパティでそのまま HTML コードを取得すると後で便利です。
src/main.tstypescript
import { DOMParser } from 'https://deno.land/x/deno_dom@v0.1.33-alpha/deno-dom-wasm.ts';import { writeCSVObjects } from 'https://deno.land/x/csv@v0.7.5/mod.ts';const notes: Note[] = [];const parser = new DOMParser();for (const { href, name } of targets) {try {await new Promise((resolve) => setTimeout(resolve, 500));const response = await fetch(href);const document = parser.parseFromString(await response.text(), 'text/html');if (!document) throw new Error('document not found');// ... get content from document ...const note: Note = {Expression: name.replace(/(.*)/, '') ?? '',Definition: definition ?? '',Example: example ?? '',Image: image ?? '',URL: href,};notes.push(note);} catch (err) {console.log(err);}}const f = await Deno.open('./notes.csv', { write: true, create: true, truncate: true });const header = Object.keys(notes[0]);await writeCSVObjects(f, notes, { header });f.close();
以下のコマンドで実行します。
zsh
deno run src/main.ts
Anki から csv ファイルをインポートすると以下の画面が表示されます。作成したノートとデッキを選択します。フィールドと各項目を合わせてインポートします。一括作成する場合、同じ単語のカードが既に存在していることがよくあります。その時にインポートしないこともここで設定できます。今回は重複があってもインポートする設定にしています。フィールドにHTML
を使用している場合、Allow HTML in fields
をチェックします。
あとはカードのテンプレートを作成して完成です。
html
<!-- Front Template --><div class="front">{{Expression}}</div><script>// ...</script>
html
<!-- Back Template --><div class="front">{{FrontSide}}</div><hr class="separate" /><div class="panels"><div class="half"><div class="photos" id="image">{{Image}}</div></div><div class="half"><div id="definition">{{Definition}}</div><div id="example">{{Example}}</div><div id="URL"><a href="{{URL}}">{{URL}}</a></div><!-- ... --></div></div><script>// ...</script>
css
は直接カードに定義するか、link
タグでHTML
から読み込み出来ます。
css
/* style.css */.front {font-size: 2rem !important;text-align: center;}#definition,#example,#URL {margin: 0.5rem !important;border: 1px solid;border-color: var(--border-color);border-radius: 5px;padding: 1rem;}ul {padding-left: 1rem;}strong {text-decoration: underline;}/* ... */
デモ
寄付のお願い
このブログやプロジェクトを継続するために寄付を頂ければ幸いです。
BTC: 1L5r7dDeJfq56UvPA96WCvQSDCfSUmwjT4
XRP: rEb8TK3gBgk5auZkwc6sHnwrGVJH8DuaLh
Destination Tag: 106945877