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

  • 相关阅读:
    Xamarin体验:使用C#开发iOS/Android应用
    SSM整合
    ros2工作空间
    Java扩展Nginx之二:编译nginx-clojure源码
    CSRF 跨站请求伪造
    移动硬盘误删除要如何恢复呢?
    Qt在Windows系统下检索U盘的插拔
    可视化开源自定义表单的特点表现在哪里?
    保护 Web 服务器安全性
    什么是V2X?如何通过V2X技术实现5G智慧交通?(二)
  • 原文地址:https://blog.csdn.net/belldeep/article/details/133426837