• python:bottle + eel 模仿 mdict 查英汉词典


    Eel 是一个轻量的 Python 库,用于制作简单的类似于离线 HTML/JS GUI 应用程序,并具有对 Python 功能和库的完全访问权限。

    Eel 托管一个本地 Web 服务器,允许您使用 Python 注释函数(annotate functions),可以从 JavaScript 调用python函数,也可以从python调用JavaScript函数。

    Eel 基于 Bottle 和 gevent 构建,它们提供了类似于 JavaScript 的异步事件循环。

    用chrome 访问 https://www.lfd.uci.edu/~gohlke/pythonlibs/#python-lzo
    下载 python_lzo-1.14-cp38-cp38-win_amd64.whl
    pip install python_lzo-1.14-cp38-cp38-win_amd64.whl

    pip install readmdict ;

    pip install eel

    Eel-0.16.0.tar.gz (24 kB)
    bottle-websocket-0.2.9.tar.gz (2.0 kB)
    whichcraft-0.6.1-py2.py3-none-any.whl (5.2 kB)
    gevent_websocket-0.10.1-py3-none-any.whl (22 kB)
    gevent-23.9.1-cp310-cp310-win_amd64.whl (1.5 MB)
    zope.event-5.0-py3-none-any.whl (6.8 kB)

    编写 mdict_eel.py 如下

    1. # -*- coding: utf-8 -*-
    2. """ web server 用于查询英汉词典 """
    3. import os
    4. import sys
    5. import json
    6. import time
    7. from readmdict import MDX
    8. import bottle
    9. from bottle import route, post, request, static_file
    10. import eel
    11. import win32com.client # TTS
    12. sapi = win32com.client.Dispatch("SAPI.SpVoice")
    13. start_time = time.time()
    14. os.chdir("/mdict")
    15. # 加载.mdx文件
    16. filename = "your.mdx"
    17. mdx = MDX(filename)
    18. headwords = [*mdx] # 单词名列表
    19. items = [*mdx.items()] # 释义html源码列表
    20. n = len(headwords)
    21. m = len(items)
    22. if n == m:
    23. print(f'{filename} 加载成功:共{n}条')
    24. end_time = time.time()
    25. print('cost %f second' % (end_time - start_time))
    26. else:
    27. print(f'ERROR:加载失败 {n}!={m}')
    28. sys.exit(1)
    29. app = bottle.Bottle()
    30. # 静态资源的目录通常称为public或static
    31. @app.route('/')
    32. def server_static(filepath):
    33. return static_file(filepath, root='./')
    34. def eng_han(txt):
    35. """ 英译中 """
    36. if not txt.isascii():
    37. return 'Maybe text is not english'
    38. word = txt.encode()
    39. word1 = txt.capitalize().encode() # 第1个字母变大写
    40. global headwords, items
    41. try: # 查词,返回单词和html文件
    42. if word in headwords:
    43. wordIndex = headwords.index(word)
    44. else:
    45. wordIndex = headwords.index(word1)
    46. word,html = items[wordIndex]
    47. result = html.decode()
    48. if result.startswith('@@@LINK='):
    49. w = result[8:].strip()
    50. result = ''">' +w+ ''
    51. else:
    52. result = result.replace(''
      result = result.replace('"/thumb/', '"data/thumb/')
    53. result = result.replace('entry://', '/trans?txt=')
    54. #result = result.replace('sound://','/data/')
    55. except:
    56. result = f"

      {txt} is not in word_list.

      "
    57. return result
    58. @app.route('/prefix')
    59. def prefix():
    60. """ 前缀匹配 """
    61. try:
    62. txt = request.query.txt
    63. except:
    64. return '1: get txt error'
    65. if len(txt.strip()) ==0:
    66. return 'text is null'
    67. print(txt)
    68. if len(txt) > 1:
    69. alist = []
    70. word = txt.strip().lower() # 字母变小写
    71. for hw in headwords:
    72. hws = hw.decode().lower()
    73. if hws.startswith(word):
    74. hws = hw.decode()
    75. alist.append(hws)
    76. if len(alist) > 0:
    77. result = json.dumps(alist)
    78. else:
    79. result = '["not found"]'
    80. else:
    81. result = '["length too short"]'
    82. return result
    83. @app.route('/trans')
    84. def trans():
    85. """ method=GET 英译中"""
    86. try:
    87. txt = request.query.txt
    88. except:
    89. return '1: get txt error'
    90. if len(txt.strip()) ==0:
    91. return 'text is null'
    92. print(txt)
    93. result = eng_han(txt)
    94. return result
    95. @app.route('/trans', method='POST')
    96. def trans():
    97. """ 英译中 """
    98. try:
    99. #txt = request.forms.get('txt')
    100. txt = request.POST.get('txt')
    101. except:
    102. return '1: get txt error'
    103. if len(txt.strip()) ==0:
    104. return 'text is null'
    105. print(txt)
    106. result = eng_han(txt)
    107. return result
    108. eel.init('.')
    109. @eel.expose # 暴露python函数给js
    110. def py_speak(txt):
    111. """ text TTS """
    112. if txt.strip() !='':
    113. sapi.Speak(txt)
    114. #eel.start('index.html', app=middleware)
    115. eel.start('index5.html', app=app, size=(1000,600))
    116. #eel.start('index5.html', app=app, mode="edge", size=(1000,600))

    编写 index5.html 如下

    1. html>
    2. <html lang="en">
    3. <head>
    4. <meta charset="utf-8">
    5. <meta http-equiv="X-UA-Compatible" content="IE=edge">
    6. <meta name="viewport" content="width=device-width, initial-scale=1.0">
    7. <title>查询英汉词典title>
    8. <script src="/eel.js">script>
    9. <script src="jquery-3.2.1.min.js">script>
    10. <style>
    11. /* portrait 判断为竖屏 */
    12. @media only screen and (orientation: portrait){
    13. #lab1 {display:none;}
    14. }
    15. /* landscape 判断为横屏 */
    16. @media only screen and (orientation: landscape){
    17. #lab1 {display: ;}
    18. }
    19. style>
    20. head>
    21. <body>
    22. <form name="form" id="form" action="trans" method="POST" target="iframe">
    23. <label id="lab1">请输入:label>
    24. <input type="text" name="txt" id='txt' size="30" placeholder="请输入 a word">
    25. <input type="submit" name="eng_han" value="英译汉">
    26. <input type="button" name="btn1" id="btn1" value="前缀查询">
    27. <input type="button" name="btn2" id="btn2" value="TTS读音" onclick="tts2();">
    28. form>
    29. <p>p>
    30. <div style="float:left; width:100%;">
    31. <div id="result" style="float:left; width:80%; height:400; border:2px;">
    32. <iframe name="iframe" id="iframe" width="100%" height="400"> iframe>
    33. div>
    34. <div id="alist" style="float:right; width:20%; height:400; border:2px;">
    35. div>
    36. div>
    37. <script type="text/javascript">
    38. $(function(){
    39. $("#btn1").click(function(){
    40. $.getJSON("/prefix?txt="+$("#txt").val(), function(data){
    41. var items = [];
    42. $.each(data, function(i, item){
    43. if (i<=20){
    44. }
    45. });
    46. var a = items.join('\n');
    47. if (a) $('#alist').html(a);
    48. })
    49. })
    50. });
    51. // TTS
    52. function tts() {
    53. var txt = document.getElementById('txt').value;
    54. if (txt.length >1) eel.py_speak(txt);
    55. }
    56. // 屏幕双击取词
    57. function tts2() {
    58. // 获取iframe里的选择内容
    59. var select = window.frames['iframe'].getSelection();
    60. var txt = select.toString();
    61. if (txt.length >1) eel.py_speak(txt);
    62. else tts();
    63. }
    64. // 页面加载添加:监听iframe网页点击事件
    65. $(document).ready(function(){
    66. var listener = window.addEventListener('blur', function(){
    67. if (document.activeElement === document.getElementById('iframe')){
    68. $('iframe').contents().find('a.fayin').click(function(event){
    69. event.preventDefault();
    70. var a = $(this);
    71. if (a){
    72. var addr = a.attr('href');
    73. if (addr.indexOf('sound://')==0){
    74. var url = "/data" + addr.substring(7);
    75. var mp3 = new Audio(url);
    76. mp3.addEventListener("canplaythrough", (event)=> {
    77. mp3.play();
    78. });
    79. } else {
    80. alert('href='+addr);
    81. }
    82. }
    83. })
    84. }
    85. });
    86. });
    87. script>
    88. body>
    89. html>

    运行 python mdict_eel.py 

    个人感觉:bottle + eel 比 pywebview + cef 要好用些。

  • 相关阅读:
    玩转Mysql系列 - 第21篇:什么是索引?
    2022赣政杯---Writeup
    Spark基础:Kafka分布式消息系统
    大模型遇上数智化,腾讯云与行业专家共探行业AI发展之路
    子数组的最小值之和(java)
    摊还分析在算法设计中的应用
    初学J2V8
    程序员开发必备,开发资源资料分享【4】
    九、池化层
    EN 13967防水用柔性薄板—CE认证
  • 原文地址:https://blog.csdn.net/belldeep/article/details/133426837