diff options
| author | Jan Tuomi <jan.tuomi@valuemotive.com> | 2021-02-02 13:43:25 +0200 |
|---|---|---|
| committer | Jan Tuomi <jan.tuomi@valuemotive.com> | 2021-02-02 13:43:25 +0200 |
| commit | 1a1dc2a9dc2380fd04fa2f2da18ff9e6ac87647d (patch) | |
| tree | 847eab756e01286e0f3f36b2a076902d770120df | |
| parent | 75c731c78880c5a31a50e166d33dcae03b76349a (diff) | |
Add Wadoku client and improve stuff
| -rw-r--r-- | attain_vocab_to_anki_py/__init__.py | 26 | ||||
| -rw-r--r-- | attain_vocab_to_anki_py/io.py | 26 | ||||
| -rw-r--r-- | attain_vocab_to_anki_py/jisho_client.py | 61 | ||||
| -rw-r--r-- | attain_vocab_to_anki_py/wadoku_client.py | 42 |
4 files changed, 141 insertions, 14 deletions
diff --git a/attain_vocab_to_anki_py/__init__.py b/attain_vocab_to_anki_py/__init__.py index dee97d6..59b2753 100644 --- a/attain_vocab_to_anki_py/__init__.py +++ b/attain_vocab_to_anki_py/__init__.py @@ -1,26 +1,42 @@ import argparse import attain_vocab_to_anki_py.io import attain_vocab_to_anki_py.jisho_client +import attain_vocab_to_anki_py.wadoku_client __version__ = '0.1.0' +DEFAULT_FORMAT = 'kanji,english' + def main(): parser = argparse.ArgumentParser(description='Convert course vocab into Anki deck') + parser.add_argument('--format', metavar='format', type=str, default=DEFAULT_FORMAT, + help='comma-separated row format, e.g. kanji,hiragana,english,readings') parser.add_argument('file', metavar='file', type=str, help='vocabulary file path') args = parser.parse_args() file_path = args.file + row_format = args.format + + print("row_format:", row_format) # read entries from file print(f"[STATUS] Reading file {file_path}") - entries = io.read_from_file(file_path) + entries = io.read_from_file(file_path, row_format) + + # fetch translations from Jisho + print(f"[STATUS] Fetching English translations from Jisho") + entries = jisho_client.inject_english_translation(entries) # fetch kanji meanings from Jisho - print(f"[STATUS] Fetching kanji data from Jisho") - entries_with_meanings = jisho_client.inject_kanji_meanings(entries) + print(f"[STATUS] Fetching kanji meaning data from Jisho") + entries = jisho_client.inject_kanji_meanings(entries) + + # fetch hiragana readings from Wadoku w/ pitch accents + print(f"[STATUS] Fetching reading data from Wadoku") + entries = wadoku_client.inject_hiragana_with_accents(entries) # write entries to file - out_file_name = f"{file_path}.out" + out_file_name = file_path.replace(".csv", ".out.csv") if ".csv" in file_path else f"{file_path}.out" print(f"[STATUS] Writing result to file {out_file_name}") - io.write_to_file(out_file_name, entries_with_meanings) + io.write_to_file(out_file_name, entries) diff --git a/attain_vocab_to_anki_py/io.py b/attain_vocab_to_anki_py/io.py index 4288e06..90c9507 100644 --- a/attain_vocab_to_anki_py/io.py +++ b/attain_vocab_to_anki_py/io.py @@ -8,24 +8,36 @@ class Entry: english: str meanings: str -def read_from_file(path_str: str) -> list: +def read_from_file(path_str: str, row_format: str) -> list: p = path.join(path_str) lines = [] + format_segments = row_format.split(",") + with open(p, "r") as f: lines = f.readlines() entries = [] for line in lines: - kanji, hiragana, english = line.split(",", 2) - entries.append(Entry(kanji=kanji.strip(), - hiragana=hiragana.strip(), - english=english.strip(), - meanings="")) + if len(line.strip()) == 0: + continue + + value_dict = {} + + row_values = line.split(",", len(format_segments) - 1) + for i, format_segment in enumerate(format_segments): + value_dict[format_segment] = row_values[i] + + entries.append(Entry( + kanji=value_dict.get("kanji", "").strip(), + hiragana=value_dict.get("hiragana", "").strip(), + english=value_dict.get("english", "").strip(), + meanings=value_dict.get("meanings", "").strip() + )) return entries -def _entry_to_row(entry: Entry, delimiter: str = ";") -> str: +def _entry_to_row(entry: Entry, delimiter: str = "§") -> str: s = delimiter.join([entry.kanji, entry.hiragana, entry.english, entry.meanings]) return f"{s}\n" diff --git a/attain_vocab_to_anki_py/jisho_client.py b/attain_vocab_to_anki_py/jisho_client.py index 0ca2147..d2c0e4f 100644 --- a/attain_vocab_to_anki_py/jisho_client.py +++ b/attain_vocab_to_anki_py/jisho_client.py @@ -4,12 +4,29 @@ import urllib.parse JISHO_BASE_URL = "https://jisho.org/search" +def _meaning_tag_to_abbrev(tag: str) -> str: + if "Godan" in tag: return "G1" + if "Ichidan" in tag: return "G2" + if "Suru" in tag: return "G3" + if "Noun" in tag: return "N." + if "I-adjective" in tag: return "い-adj." + if "Na-adjective" in tag: return "な-adj." + if "No-adjective" in tag: return "の-adj." + if "Adverb" in tag: return "adv." + return tag + def inject_kanji_meanings(entries: list) -> list: entries_with_meanings = [] for index, entry in enumerate(entries): kanji = entry.kanji - print(f"Fetching data for #{index}: {kanji}") + + if len(entry.meanings) > 0: + print(f"Meaning data exists for #{index}: {kanji}. Skipping...") + entries_with_meanings.append(entry) + continue + + print(f"Fetching meaning data from Jisho for #{index}: {kanji}") resource_part = urllib.parse.quote_plus(f"{kanji}#kanji") url = f"{JISHO_BASE_URL}/{resource_part}" @@ -32,4 +49,44 @@ def inject_kanji_meanings(entries: list) -> list: entry.meanings = result entries_with_meanings.append(entry) - return entries_with_meanings
\ No newline at end of file + return entries_with_meanings + +def inject_english_translation(entries: list) -> list: + entries_with_translations = [] + + for index, entry in enumerate(entries): + kanji = entry.kanji + + if len(entry.english) > 0: + print(f"English translation exists for #{index}: {kanji}. Skipping...") + entries_with_translations.append(entry) + continue + + print(f"Fetching translation from Jisho for #{index}: {kanji}") + + resource_part = urllib.parse.quote_plus(f"{kanji}") + url = f"{JISHO_BASE_URL}/{resource_part}" + resp = requests.get(url) + resp.raise_for_status() + + soup = BeautifulSoup(resp.text, "html.parser") + container = soup.select_one("div#page_container") + + meaning_wrapper = container.select(".meanings-wrapper")[0] + + meaning_tags = meaning_wrapper.select(".meaning-tags") + meaning_tags_texts = map(lambda e: e.text.strip(), meaning_tags) + meaning_tag_abbrevs = map(_meaning_tag_to_abbrev, meaning_tags_texts) + + meaning_translations = meaning_wrapper.select(".meaning-wrapper .meaning-meaning") + meaning_translations_texts = map(lambda e: e.text.strip(), meaning_translations) + + meanings_zipped = zip(meaning_tag_abbrevs, meaning_translations_texts) + + first_translation_pair = list(meanings_zipped)[0] + result = f"{first_translation_pair[0]} {first_translation_pair[1]}" + + entry.english = result + entries_with_translations.append(entry) + + return entries_with_translations diff --git a/attain_vocab_to_anki_py/wadoku_client.py b/attain_vocab_to_anki_py/wadoku_client.py new file mode 100644 index 0000000..550f801 --- /dev/null +++ b/attain_vocab_to_anki_py/wadoku_client.py @@ -0,0 +1,42 @@ +from bs4 import BeautifulSoup +import requests +import urllib.parse + +WADOKU_BASE_URL = "https://www.wadoku.de/search" + +def inject_hiragana_with_accents(entries: list) -> list: + entries_with_readings = [] + + for index, entry in enumerate(entries): + kanji = entry.kanji.replace("~", "") + + if len(entry.hiragana) > 0: + print(f"Hiragana exists for #{index}: {kanji}. Skipping...") + entries_with_readings.append(entry) + continue + + # Remove nasty characters from kanji since Wadoku + # fails to find anything otherwise + print(f"Fetching hiragana data for #{index}: {kanji}") + + resource_part = urllib.parse.quote_plus(kanji) + url = f"{WADOKU_BASE_URL}/{resource_part}" + resp = requests.get(url) + resp.raise_for_status() + + soup = BeautifulSoup(resp.text, "html.parser") + container = soup.select_one("section#content") + + readings = container.select("span.reading") + first_reading = str(readings[0]) + + # Remove extra characters added by Wadoku + # https://www.wadoku.de/wiki/display/WAD/Hinweise+zur+Notation + result = first_reading \ + .replace("~", "") \ + .replace("|", "") \ + .replace("・", "") + entry.hiragana = result + entries_with_readings.append(entry) + + return entries_with_readings |
