Pythonでタイピング練習プログラム
あいかわらずPythonでスクレイピングばかりしているわけですが、テーブルタグのスクレイピングが苦手なので、練習がてらに英単語をスクレイプした際に出来たデータをつかい英単語練習用プログラムを作ってみました。単語のスペルをタイプし、その単語の意味も表示される。タイプミスすると色が変わります。
ところで、私はプログラミングでなにがしたいのでしょうか・・・。
わたし(おかず)のプログラミング学習目的に作られたスクリプトです
import re import requests import json import random import sys import os import string from time import sleep from bs4 import BeautifulSoup from pathlib import Path from itertools import zip_longest from collections import defaultdict SAVE_PATH = Path(os.path.dirname(__file__)) FILE_PATH = SAVE_PATH / 'eigoduke.json' typo_cnt_dict = defaultdict(int) typo_string_dict = defaultdict(list) keys = ['chu1', 'chu2', 'chu3'] level = {'chu1': '中学1年生・英単語', 'chu2': '中学2年生・英単語', 'chu3': '中学3年生・英単語', 'kou1': '高校1年生・英単語', 'kou2': '高校2年生・英単語', 'kou3': '高校3年生・英単語' } def pageDownload(url): session = requests.session() session.headers.update({"User-Agent":'Mozilla/5.0 (X11; Linux x86_64) \ AppleWebKit/537.36 (KHTML, like Gecko)\ Chrome/73.0.3683.75 Safari/537.36'}) r = session.get(url) if r.status_code == 200: r.encoding = r.apparent_encoding soup = BeautifulSoup(r.text, 'lxml') return soup return False def eng_word_list(soup): return [ eitango_word.text for eitango_word in soup.select('.hpb-cnt-tb-cell3') if re.findall(r'[a-zA-Z0-9]+', eitango_word.text) ] def eng_meaning_list(soup): return [eng_meaning.text for eng_meaning in soup.select('.hpb-cnt-tb-cell4')] def save_dict(arg): with open(FILE_PATH, 'w') as f: json.dump(arg, f, ensure_ascii=False, indent=4) def create_engdict(): eng_words = [] gakunen = [g + str(i) for g in ["chu", "kou"] for i in range(1, 4)] for num in gakunen: soup = pageDownload(f'http://www.eigo-duke.com/tango/{num}') eng_words.append([eng_word_list(soup), eng_meaning_list(soup)]) sleep(1) eng_word_meaning_dict = dict() _ = [eng_word_meaning_dict.update({gaku: words}) for gaku in gakunen for words in eng_words] save_dict(eng_word_meaning_dict) return eng_word_meaning_dict def load_eng_word_meaning_dict(): if FILE_PATH.exists(): with open(FILE_PATH, 'r') as f: eng_word_meaning_dict = json.load(f) return eng_word_meaning_dict sys.stdout.write('英単語リストを取得します。\n') sys.stdout.write('取得には数分かかります\n') sys.stdout.flush() return create_engdict() def at_random_question(eng_word_meaning_dict, gakunen, num): return random.sample(eng_word_meaning_dict[gakunen][0], num).pop() def lookfor_key_index(arg, eng_word_meaning_dict): # 問題をrandomで選ぶため、問題の属するkeyとindexを取得する for key in eng_word_meaning_dict.keys(): for idx, value in enumerate(eng_word_meaning_dict[key][0]): if arg in value: return key, idx continue def display_question(q, level, key, meaning): msg = f''' 出題:{level[key]} 意味:{meaning} > {q} ''' ans = input(msg) return ans def typo_chenge_fg_color(char): # 文字色を赤 char = f'\033[31m{char}\033[0m' return char def is_first_char_upper_case(arg): # 先頭文字が大文字か判定 if arg[0] in string.ascii_uppercase: return True return False def typo_string_cnt(qes, ans): qes_counted_num = len(qes) ans_counted_num = len(ans) qes_lower_case = list(qes.lower()) ans_lower_case = list(ans.lower()) if qes_counted_num > ans_counted_num: # タイプが足りなければ*で埋める for i, word in enumerate(zip_longest(qes_lower_case, ans_lower_case), start=0): if word[1] is None: ans_lower_case.append('*') else: continue return "".join(ans_lower_case) elif qes_counted_num < ans_counted_num: # タイプが多すぎれば色を変える for i, word in enumerate(zip_longest(qes_lower_case, ans_lower_case), start=0): if word[0] is None: ans_lower_case[i] = typo_chenge_fg_color(word[1]) return "".join(ans_lower_case) else: continue return ans def typo_uppercase(qes, ans): if not is_first_char_upper_case(qes): # firstなら qes = list(qes.lower()) ans = list(ans.lower()) else: # Firstなら qes = list(qes) ans = list(ans) for i, word in enumerate(zip(qes, ans), start=0): if word[0] != word[1]: ans[i] = typo_chenge_fg_color(ans[i].upper()) return "".join(ans) def is_typo(qes, ans): # 正誤判定 if qes == ans: return True return False def typo_counter(key): # TYPOをカウント typo_cnt_dict[key] += 1 def typo_string_record(key, ans): # TYPOの入力文字列を記録 typo_string_dict[key].append(ans) def typo_cnt_msg(): print('') print('TYPO回数') for item in typo_cnt_dict.items(): key, value = item msg = f'{key}:\t {value}回' history = " ".join(typo_string_dict[key]) print(msg, '\t' , history) else: print() def retry_msg(retry): if int(retry) > 0: sys.stdout.write(f'ReTry: {retry + 1}/3\n') def question(): eng_word_meaning_dict = load_eng_word_meaning_dict() key = random.choice(keys) qes = at_random_question(eng_word_meaning_dict, key, 1) result = lookfor_key_index(qes, eng_word_meaning_dict) # {'chu1':[['apple','orange'],['りんご', 'オレンジ']], 'chu2': [[],[]]} meaning = eng_word_meaning_dict[result[0]][1][result[1]] retry = 0 while retry < 3: ans = display_question(qes, level, key, meaning) retry_msg(retry) if is_typo(qes, ans): break else: ans = typo_string_cnt(qes, ans) # typoした回数を数える typo_counter(qes) # typoした文字を大文字、かつ、色付けをする ans = typo_uppercase(qes, ans) # typo履歴 最後に表示 typo_string_record(qes, ans) sys.stdout.write("TYPO=> " + ans + '\n') retry += 1 def yes_no_select(choice='no'): while True: msg = 'exit? [Y]es/[N]o (default: no)' choice = input(msg).lower() if choice in ('y', 'ye', 'yes'): return True elif choice in ('n', 'no'): return False def main(): try: while True: question() except KeyboardInterrupt: if yes_no_select(): typo_cnt_msg() sys.exit(0) else: main() if __name__ == '__main__': main()
退屈なことはPythonにやらせよう ―ノンプログラマーにもできる自動化処理プログラミング
- 作者: Al Sweigart,相川愛三
- 出版社/メーカー: オライリージャパン
- 発売日: 2017/06/03
- メディア: 単行本(ソフトカバー)
- この商品を含むブログ (6件) を見る
- 作者: 辻真吾
- 出版社/メーカー: 技術評論社
- 発売日: 2018/04/12
- メディア: 大型本
- この商品を含むブログ (1件) を見る