既存のAnkiのデッキにGoogle検索した画像を入れるPythonコード
開発経緯
これまでDiscordを通して単語の自動登録、既存のデッキに音声を追加などAnki関連のプログラムをPythonで色々書いてきましたが画像は未だに手動でデッキにちまちま登録していました。
作業も面倒なので今回は思い切って自動化する事にしました。
ソースコード
import requests
from bs4 import BeautifulSoup
import json
ANKI_CONNECT_URL = "http://localhost:8765"
DECK_NAME = "your_deck"
def anki_request(action, **params):
return {'action': action, 'params': params, 'version': 6}
def invoke(action, **params):
request_json = json.dumps(anki_request(action, **params))
print(f"Request: {request_json}") # リクエストの内容を出力
try:
response = requests.post(ANKI_CONNECT_URL, data=request_json)
print(f"Response status code: {response.status_code}") # レスポンスステータスコードを出力
response_json = response.json()
print(f"Response JSON: {response_json}") # レスポンスの内容を出力
if len(response_json) != 2:
raise Exception("Response has an unexpected number of fields")
if 'error' in response_json and response_json['error'] is not None:
raise Exception(response_json['error'])
return response_json['result']
except requests.exceptions.RequestException as e:
raise Exception(f"AnkiConnect request failed: {e}")
def fetch_image_url(query):
search_query = f"{query} picture Pexels" # 検索クエリ
search_url = f"https://www.google.com/search?tbm=isch&q={search_query}"
headers = {
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.3"}
response = requests.get(search_url, headers=headers)
soup = BeautifulSoup(response.text, 'html.parser')
img_tags = soup.find_all('img')
if len(img_tags) > 1:
return img_tags[1]['src'] # 最初の画像を無視して2番目の画像を取得
return None
def add_image_to_card(note_id, image_url, back_field_name="Back"):
note = invoke("notesInfo", notes=[note_id])[0]
back_field_value = note['fields'][back_field_name]['value']
new_back_field_value = back_field_value + f"<br><img src=\"{image_url}\">"
invoke("updateNoteFields", note={'id': note_id, 'fields': {back_field_name: new_back_field_value}})
def main():
# 全てのノートIDを取得
try:
note_ids = invoke("findNotes", query=f"deck:{DECK_NAME}")
print(f"Found note IDs: {note_ids}")
except Exception as e:
print(f"Error finding notes: {e}")
return
for note_id in note_ids:
try:
print(f"Processing note ID: {note_id}")
note = invoke("notesInfo", notes=[note_id])
print(f"Note info: {note}")
back_text = note[0]['fields']['Back']['value']
image_url = fetch_image_url(back_text)
if image_url:
add_image_to_card(note_id, image_url)
except Exception as e:
print(f"Error processing note {note_id}: {e}")
if __name__ == "__main__":
main()
コード解説
これは裏面にある単語+検索クエリにある単語でGoogle検索をして一番最初に出た単語をAnkiの裏面の最後の行に登録しています。
検索のクエリを変更する場合はこのpicture Pexelsという文字を変更して下さい。
search_query = f"{query} picture Pexels"
単語+imageのみだと関係ない画像が追加される事が多かったので、フリーイメージサイトのPexelsを検索ワードに追加したらいい画像を追加してくれるようになりました。
検索クエリは必要に応じてチューニングして使用して下さい。
今回はフランス語のデッキで簡単な単語のみを対象にしたのでこのやり方でうまくいきました。
単純な単語でGoogle検索の一番上の画像を取得する形式にするとブランド名、商品名、曲名、人名などがヒットしてしまいPexelsを入れるまではうまく取得する事ができませんでした。
それでもたまに変な画像が挿入されています笑
裏面でなく前面にある単語を元に画像取得したい場合は検索クエリをFrontフィールドの値に変更して下さい。
back_text = note[0]['fields']['Back']['value']
image_url = fetch_image_url(back_text)
まとめ、注意点
当たり前ですが、完全に自分の欲しい画像を取得して登録できるわけではないので注意が必要です。
私の場合は英単語のデッキは難解な単語や専門性用語が多くそもそも手動で検索しても覚える助けになりそうな画像が見つからない事も少なくありません。
そのような場合はChatGPTなどの生成AIで画像を作らせて登録しているのでAPIを使用するれば自動化する事は可能ですが、お金が掛かるので現在は手動で行なっています。
使用例は初級〜中級レベルの単語を登録してあるデッキが主になります。
上級レベルでの単語でも名詞であればチューニング次第ではうまく使うことができると思います。
既に画像が登録されているカードはスキップして登録したい場合なども注意が必要です。