用python背单词

最近女朋友在背单词,加的群每天会发单词计划,是一个每日单词表,如下图所示:
每日单词表
但是群里只给了五天,作为一个程序员男朋友,马上就想到了用自动化技术生成每日单词表。

需求

由于是给女朋友用的,当然不能用控制台的小黑框了。python有很多图形库,我选了一个比较简单的tkinter。
现在分析一下,我们的需求:

  • 可以输入今天背多少个单词
  • 可以输入今天是第几天,作为生成的pdf的名字
  • 每天随机生成单词
  • 背过的单词就不再使用了

界面设计

界面很简单,只需要:

  • 输入单词数量的输入框和提示文字
  • 输入天数的地方和提示文字
  • 提交按钮
  • 显示结果
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
from tkinter import *
import os
class Application(Frame):
def __init__(self, master=None):
Frame.__init__(self, master)
self.pack()
self.createWidgets()
def createWidgets(self):
self.wordnumLabel = Label(self, text='请输入今天要背的单词数:')
self.wordnumLabel.pack()
self.wordnumInput = Entry(self)
self.wordnumInput.pack()
self.dayLabel = Label(self, text='今天是第几天呀:')
self.dayLabel.pack()
self.dayInput = Entry(self)
self.dayInput.pack()
self.alertButton = Button(self, text='开始背单词!', command=self.genereate_plan)
self.alertButton.pack()
self.resultLabel = Label(self, text=' ')
self.resultLabel.pack()
def genereate_plan(self):
self.resultLabel['text'] = "Running"
num = int(self.wordnumInput.get())
day = int(self.dayInput.get())
input_path = os.path.join(os.getcwd(),'考研词汇.csv')
output_path = os.path.join(os.getcwd(),'Day %d 单词任务.pdf'%(day))
# 读取词库,生成今天要背的单词
wordlist = read_wordlist(input_path,num)
# 生成pdf
generate_pdf(output_path,wordlist,num)
self.resultLabel['text'] = "已保存到当前文件夹!"
app = Application()
app.master.title('佳佳的每日单词计划')
app.mainloop()

界面

爬取词库

词库不太好找,所以我们可以使用爬虫爬取,任务比较简单,就没有使用scrapy了:

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
import requests
from bs4 import BeautifulSoup
import re
import os
headers = {
"user-agent": "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.81 Safari/537.36"
}
def get_HTML(url):
#获取页面信息
try:
r = requests.get(url, headers = headers)
r.raise_for_status()
r.encoding = r.apparent_encoding
return r.text
except:
return ""
def copy_url(html):
#获得页面中单词链接
words_url = re.findall('<li class="clearfix">.*?<a href="(.*?)" target="_blank">',html,re.S)
return words_url
def dowload_url(html,word_name):
#获取单词页面的汉语意思并保存
soup = BeautifulSoup(html,"html.parser")
content = soup.select('div.sp-lexicon-word-comment.clearfix')
if len(content)==0:
print(word_name)
word_content = content[0].get_text().strip()
with open(os.path.join(os.getcwd(),'考研词汇.csv'),"a+",encoding = "UTF-8") as f:
f.write(word_name+','+word_content+'\n')
if __name__ == "__main__":
urls = ["https://www.hujiang.com/ciku/zuixinkaoyanyingyucihui_{0}/".format(i) for i in range(1,276)]
i = 1
for url in urls:
html = get_HTML(url)
words_url = copy_url(html)
for word_url in words_url:
# 有的单词会有单引号 o'clock
ind = word_url.find('&#39;')
if ind != -1:
process_url = word_url[:ind] + "'" + word_url[ind+5:]
print(process_url)
else:
process_url = word_url
new_url = "https://www.hujiang.com" + process_url
word_name = process_url.split("/")[2]
word_html = get_HTML(new_url)
dowload_url(word_html,word_name)
print(i)
i += 1

简单的小爬虫,都是比较基础的东西。

生成单词表

接下来就是根据词库来随机生成单词了:

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
def read_wordlist(input_path,num):
record = []
with open(os.path.join(os.getcwd(),'背单词记录.txt'),"r") as f1:
lines = f1.read().splitlines()
record = lines
num_count = 0
wordlist = []
with open(input_path,"r",encoding='utf-8') as f2:
data = f2.read().splitlines()
while num_count<num:
ranint = random.randint(0,len(data)-1)
word = data[ranint]
ind = word.find(',')
w = word[:ind]
c_old = word[ind+1:]
c = ''
while len(c_old)>35:
c += c_old[:35]+'\n'
c_old = c_old[35:]
c += c_old
if w not in record:
wordlist.append([w,c])
num_count += 1
with open(os.path.join(os.getcwd(),'背单词记录.txt'),"a+") as f3:
f3.writelines([w+'\n'])
return wordlist

我们要先读取词库和已背单词记录,然后随机挑出输入数量的没背过的单词。由于有的单词解释过长,所以每35个字符我们加个换行,方便我们后面生成pdf时,表格行高比较好设置。

生成pdf

接下来就是将单词表写进pdf里了。我们用到reportlab这个包:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
def generate_pdf(file_name,wordlist,num):
pdfmetrics.registerFont(TTFont('Simyou', './SIMYOU.TTF'))
doc = SimpleDocTemplate(file_name,pagesize=(A4[1],A4[0]),topMargin = 15,bottomMargin = 15)
content = []
table_data = wordlist
table_style = [
('FONTNAME', (0, 0), (-1, -1), 'Simyou'), # 字体
('FONTSIZE', (0, 0), (-1, 0), 10), # 第一行的字体大小
('FONTSIZE', (0, 1), (-1, -1), 10), # 第二行到最后一行的字体大小
('ALIGN', (0, 0), (-1, -1), 'CENTER'), # 所有表格左右中间对齐
('VALIGN', (0, 0), (-1, -1), 'MIDDLE'), # 所有表格上下居中对齐
('GRID', (0, 0), (-1, -1), 0.1, colors.black), # 设置表格框线为黑色,线宽为0.1
]
table = Table(data=table_data, style=table_style, colWidths=[170,450])
content.append(table)
doc.build(content)

由于我们要用到中文,所以需要先引入字体。简单点的话,字体文件就用windows自带的。表格的格式设置语法比较复杂,如果需要很复杂的表格,可以去reportlab官网找手册。默认表格行高是自适应的,所以我们上面一步加入换行符就可以让解释比较长的单词的行高更高一点,这样表格更加美观。

界面美化

设置下界面大小、偏移量和图标:

1
2
app.master.geometry('300x150+500+200')
app.master.iconbitmap("./佳佳.ico")

打包成exe

让女朋友用,当然不能让她再装个python用啦,所以要打包成exe。用pyinstaller打包即可。需要注意的是,pyinstaller打包时会一并打包很多不必要的模块,所以会比较大,动辄几百MB。我们用anaconda再创建一个新的python环境即可。打包的时候注意要用新的这个环境去打包。我的打包完就只有10MB了。

1
pyinstaller -Fw ./generate_wordplan.py

-F是打包成一个文件,可以试试去掉,会出现一个文件夹,里面有很多dll等。
-w是不要界面。因为我们自己写了界面了,如果不加w的话,运行时会弹出一个控制台。
打包完成后可以运行测试一下,如果一个黑屏一闪而过,可以用cmd运行这个程序,cmd里面会有报错。

不足

由于时间仓促,技术有限,这个小程序还有很多不足:

  • 界面设计太简陋,可以用QT等重新写界面
  • 没有错误处理(由于用户就一个,还可以随时指导,所以错误处理一概没写)
  • 单词解释较长较复杂,比如一个单词意思太多,可以对单词解释进行处理一下
  • 功能单一,仅满足了需求。