• 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 要好用些。

  • 相关阅读:
    conductor 3.7以上 jedisCommands ArrayIndexOutOfBoundsException 解决分析
    猿创征文 |【JavaScript】-- js知识点大总结
    Qt之Model/View架构
    动态规划题目
    盘点常见的动态内存的错误
    多模数据库 | 星环科技多模数据库ArgoDB“一库多用“,构建高性能湖仓集一体平台
    Redis缓存(笔记一:缓存介绍和数据库启动)
    【工作小技巧】刚入职的软件测试工程师怎么快速上手新岗位
    2007-2008期末试题B卷
    Python基础入门篇【42】--python中的内置库os与sys模块
  • 原文地址:https://blog.csdn.net/belldeep/article/details/133426837