├── requirements.txt ├── translator.jpg ├── test ├── test_google.py ├── test.py ├── test_bing.py └── test_baidu.py ├── setup.py ├── translate.py ├── README.rst └── README.md /requirements.txt: -------------------------------------------------------------------------------- 1 | toolkity>=1.4.7 -------------------------------------------------------------------------------- /translator.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ShichaoMa/translate_html/HEAD/translator.jpg -------------------------------------------------------------------------------- /test/test_google.py: -------------------------------------------------------------------------------- 1 | from translate import Translate 2 | 3 | 4 | with Translate("google") as t: 5 | t.set_logger() 6 | print(t.translate("my name is tom, i come from nanjing, I like eat shit, what about yours?")) -------------------------------------------------------------------------------- /test/test.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | 3 | from translate import Translate 4 | 5 | 6 | class TestTranslate(unittest.TestCase): 7 | 8 | def assertContainEqual(self, first, second, msg=None): 9 | if not first.count(second): 10 | msg = self._formatMessage(msg, "%s is not contain %s"%(first, second)) 11 | self.fail(msg) 12 | 13 | def test_baidu(self): 14 | with Translate("baidu") as t: 15 | t.set_logger() 16 | self.assertContainEqual(t.translate("my name is tom, what about yours?"), "我") 17 | 18 | def test_google(self): 19 | with Translate("google") as t: 20 | t.set_logger() 21 | self.assertContainEqual(t.translate("my name is tom, what about yours?"), "我") 22 | 23 | def test_qq(self): 24 | with Translate("qq") as t: 25 | t.set_logger() 26 | self.assertContainEqual(t.translate("my name is tom, what about yours?"), "我") 27 | 28 | def test_bing(self): 29 | with Translate("bing") as t: 30 | t.set_logger() 31 | self.assertContainEqual(t.translate("my name is tom, what about yours?"), "我") 32 | 33 | 34 | if __name__ == "__main__": 35 | unittest.main() 36 | -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | # -*- coding:utf-8 -*- 2 | try: 3 | from setuptools import setup, find_packages 4 | except: 5 | from distutils.core import setup 6 | 7 | VERSION = '1.2.4' 8 | 9 | AUTHOR = "cn" 10 | 11 | AUTHOR_EMAIL = "cnaafhvk@foxmail.com" 12 | 13 | URL = "https://github.com/ShichaoMa/translate_html" 14 | 15 | NAME = "translate-html" 16 | 17 | DESCRIPTION = "translate html to chinese without tag. " 18 | try: 19 | LONG_DESCRIPTION = open("README.rst").read() 20 | except UnicodeDecodeError: 21 | LONG_DESCRIPTION = open("README.rst", encoding="utf-8").read() 22 | 23 | KEYWORDS = "translate html chinese tag" 24 | 25 | LICENSE = "MIT" 26 | 27 | MODULES = ["translate"] 28 | 29 | setup( 30 | name = NAME, 31 | version = VERSION, 32 | description = DESCRIPTION, 33 | long_description = LONG_DESCRIPTION, 34 | classifiers = [ 35 | 'License :: OSI Approved :: MIT License', 36 | 'Programming Language :: Python', 37 | 'Intended Audience :: Developers', 38 | 'Operating System :: OS Independent', 39 | ], 40 | entry_points={ 41 | 'console_scripts': [ 42 | 'translate = translate:main', 43 | ], 44 | }, 45 | keywords = KEYWORDS, 46 | author = AUTHOR, 47 | author_email = AUTHOR_EMAIL, 48 | url = URL, 49 | license = LICENSE, 50 | py_modules = MODULES, 51 | install_requires=["toolkity>=1.4.7"], 52 | include_package_data=True, 53 | zip_safe=True, 54 | ) -------------------------------------------------------------------------------- /translate.py: -------------------------------------------------------------------------------- 1 | # -*- coding:utf-8 -*- 2 | import os 3 | import random 4 | 5 | from operator import itemgetter 6 | from argparse import ArgumentParser 7 | from toolkit.translator.translate_adapter import TranslateAdapter 8 | 9 | __version__ = "1.2.4" 10 | 11 | 12 | class Translate(TranslateAdapter): 13 | """ 14 | 翻译类 15 | """ 16 | proxy_list = [None] 17 | web_site = None 18 | retry_times = None 19 | translate_timeout = None 20 | 21 | def __init__(self, web_site=None, proxy_list=None, proxy_auth=None, 22 | retry_times=10, translate_timeout=5, load_module=None): 23 | self.web_site = web_site.split(",") 24 | self.proxy = {} 25 | self.proxy_auth = proxy_auth 26 | self.retry_times = retry_times 27 | self.translate_timeout = translate_timeout 28 | 29 | if proxy_list and os.path.exists(proxy_list): 30 | self.proxy_list = [i.strip() for i in open(proxy_list).readlines() if (i.strip() and i.strip()[0] != "#")] 31 | if load_module: 32 | self.load(load_module) 33 | super(Translate, self).__init__() 34 | 35 | def proxy_choice(self): 36 | if self.proxy_list and self.proxy_list[0]: 37 | proxy = "http://%s%s" % ("%s@" % self.proxy_auth if self.proxy_auth else "", random.choice(self.proxy_list)) 38 | return {"http": proxy, "https": proxy} 39 | 40 | 41 | def main(): 42 | parser = ArgumentParser() 43 | parser.add_argument("-ws", "--web-site", default="baidu,qq,google,bing", 44 | help="Which site do you want to use for translating, split by `,`?") 45 | parser.add_argument("-pl", "--proxy-list", 46 | help="The proxy.list contains proxy to use for translating. default: ./proxy.list") 47 | parser.add_argument("-pa", "--proxy-auth", 48 | help="Proxy password if have. eg. user:password") 49 | parser.add_argument("-rt", "--retry-times", type=int, default=10, 50 | help="If translate failed retry times. default: 10") 51 | parser.add_argument("-tt", "--translate-timeout", type=int, default=5, help="Translate timeout. default: 5") 52 | parser.add_argument("-lm", "--load-module", 53 | help="The module contains custom web site functions which may use for translate. eg: trans.qq") 54 | parser.add_argument("src", nargs="+", help="The html you want to translate. ") 55 | data = vars(parser.parse_args()) 56 | src = data.pop("src") 57 | with Translate(**dict(filter(itemgetter(1), data.items()))) as translator: 58 | translator.set_logger() 59 | print(translator.translate(" ".join(src))) 60 | 61 | 62 | if __name__ == "__main__": 63 | main() 64 | -------------------------------------------------------------------------------- /test/test_bing.py: -------------------------------------------------------------------------------- 1 | """ 2 | function() { 3 | var n = 0, t, i, r; 4 | if (this.length === 0) 5 | return n; 6 | for (t = 0, 7 | r = this.length; t < r; t++) 8 | i = this.charCodeAt(t), 9 | n = (n << 5) - n + i | 0; 10 | return n 11 | } 12 | """ 13 | import struct 14 | 15 | 16 | def shift_left_for_js(num, count): 17 | rs = num << count 18 | if rs > 2147483647 or rs <= -2147483647: 19 | rs = struct.unpack("i", struct.pack("l", rs)[:4])[0] 20 | return rs 21 | 22 | 23 | def hash_code(text): 24 | code = 0 25 | for i in text: 26 | i = ord(i) 27 | code = shift_left_for_js(code, 5) - code + i | 0 28 | return code 29 | 30 | 31 | import requests 32 | 33 | session = requests.Session() 34 | 35 | headers = { 36 | #'origin': 'https://cn.bing.com', 37 | 'accept-encoding': 'gzip, deflate, br', 38 | # 'cookie': 39 | # 'mtstkn=ylt9lqygf4d6xwjSxncfOcMX8VexOyMzprKU%2F8gaXe1zA1vPe%2FuLVXFOjulDsQ5t; ' 40 | # 'MicrosoftApplicationsTelemetryDeviceId=1167bc09-a9a1-5df1-f0f8-e9a69d79c782; ' 41 | # 'MicrosoftApplicationsTelemetryFirstLaunchTime=1516933299794; ' 42 | # 'srcLang=-; ' 43 | # 'destLang=en; ' 44 | # 'smru_list=; ' 45 | # 'dmru_list=en; ' 46 | # 'destDia=en-US; ' 47 | # 'sourceDia=en-US; ' 48 | # '_EDGE_S=F=1&SID=292F83786B416E1704D488FB6AF66FE4;' 49 | # ' _EDGE_V=1; MUID=2AF83BF9F6EC6D223FBB307AF75B6C44; ' 50 | # 'MUIDB=2AF83BF9F6EC6D223FBB307AF75B6C44; ' 51 | # 'SRCHHPGUSR=WTS=63652530099; ' 52 | # 'SRCHD=AF=NOFORM; ' 53 | # 'SRCHUID=V=2&GUID=93C164FE09F84B84930B7A6AB73CB22C&dmnchg=1; ' 54 | # 'SRCHUSR=DOB=20180126; ' 55 | # '_SS=SID=292F83786B416E1704D488FB6AF66FE4', 56 | #'pragma': 'no-cache', 57 | 'user-agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.132 Safari/537.36', 58 | #'content-type': 'application/json; charset=UTF-8', 59 | 'accept': 'application/json, text/javascript, */*; q=0.01', 60 | #'cache-control': 'no-cache', 61 | #'authority': 'cn.bing.com', 62 | #'referer': 'https://cn.bing.com/translator/?ref=TThis&IG=7A2F68129A754A71A90F7C015A199621&IID=SERP.5493&&text=&from=&to=en' 63 | } 64 | # 65 | # session.get("https://cn.bing.com/translator/", headers=headers) 66 | # 67 | # resp = session.post("https://cn.bing.com/translator/api/Translate/TranslateArray?from=-&to=zh-CHS", headers=headers, json=[{"id": hash_code("my"), "text": "my"}]) 68 | # 69 | # from toolkit import debugger 70 | # debugger() 71 | # print(resp.text) 72 | # print(hash_code("name my")) 73 | from translate import Translate 74 | 75 | with Translate("bing") as t: 76 | t.set_logger() 77 | print(t.translate("my name is tom, i come from nanjing, I like eat shit, what about yours?")) -------------------------------------------------------------------------------- /test/test_baidu.py: -------------------------------------------------------------------------------- 1 | """ 2 | i = null 3 | 4 | function names(r) { 5 | var o = r.match(/[\uD800-\uDBFF][\uDC00-\uDFFF]/g); 6 | if (null === o) { 7 | var t = r.length; 8 | t > 30 && (r = "" + r.substr(0, 10) + r.substr(Math.floor(t / 2) - 5, 10) + r.substr(-10, 10)) 9 | } else { 10 | for (var e = r.split(/[\uD800-\uDBFF][\uDC00-\uDFFF]/), C = 0, h = e.length, f = []; h > C; C++) 11 | "" !== e[C] && f.push.apply(f, a(e[C].split(""))), 12 | C !== h - 1 && f.push(o[C]); 13 | var g = f.length; 14 | g > 30 && (r = f.slice(0, 10).join("") + f.slice(Math.floor(g / 2) - 5, Math.floor(g / 2) + 5).join("") + f.slice(-10).join("")) 15 | } 16 | var u = void 0 17 | , l = "" + String.fromCharCode(103) + String.fromCharCode(116) + String.fromCharCode(107); 18 | u = null !== i ? i : (i = window[l] || "") || ""; 19 | for (var d = u.split("."), m = Number(d[0]) || 0, s = Number(d[1]) || 0, S = [], c = 0, v = 0; v < r.length; v++) { 20 | var A = r.charCodeAt(v); 21 | 128 > A ? S[c++] = A : (2048 > A ? S[c++] = A >> 6 | 192 : (55296 === (64512 & A) && v + 1 < r.length && 56320 === (64512 & r.charCodeAt(v + 1)) ? (A = 65536 + ((1023 & A) << 10) + (1023 & r.charCodeAt(++v)), 22 | S[c++] = A >> 18 | 240, 23 | S[c++] = A >> 12 & 63 | 128) : S[c++] = A >> 12 | 224, 24 | S[c++] = A >> 6 & 63 | 128), 25 | S[c++] = 63 & A | 128) 26 | } 27 | for (var p = m, F = "" + String.fromCharCode(43) + String.fromCharCode(45) + String.fromCharCode(97) + ("" + String.fromCharCode(94) + String.fromCharCode(43) + String.fromCharCode(54)), D = "" + String.fromCharCode(43) + String.fromCharCode(45) + String.fromCharCode(51) + ("" + String.fromCharCode(94) + String.fromCharCode(43) + String.fromCharCode(98)) + ("" + String.fromCharCode(43) + String.fromCharCode(45) + String.fromCharCode(102)), b = 0; b < S.length; b++) 28 | p += S[b], 29 | p = n(p, F); 30 | return p = n(p, D), 31 | p ^= s, 32 | 0 > p && (p = (2147483647 & p) + 2147483648), 33 | p %= 1e6, 34 | p.toString() + "." + (p ^ m) 35 | } 36 | 37 | function n(r, o) { 38 | for (var t = 0; t < o.length - 2; t += 3) { 39 | var a = o.charAt(t + 2); 40 | a = a >= "a" ? a.charCodeAt(0) - 87 : Number(a), 41 | a = "+" === o.charAt(t + 1) ? r >>> a : r << a, 42 | r = "+" === o.charAt(t) ? r + a & 4294967295 : r ^ a 43 | } 44 | return r 45 | } 46 | """ 47 | import re 48 | import math 49 | 50 | 51 | import ctypes 52 | 53 | def int_overflow(val): 54 | maxint = 2147483647 55 | if not -maxint-1 <= val <= maxint: 56 | val = (val + (maxint + 1)) % (2 * (maxint + 1)) - maxint - 1 57 | return val 58 | 59 | 60 | def unsigned_right_shitf(n, i): 61 | # 数字小于0,则转为32位无符号uint 62 | if n<0: 63 | n = ctypes.c_uint32(n).value 64 | # 正常位移位数是为正数,但是为了兼容js之类的,负数就右移变成左移好了 65 | if i<0: 66 | return -int_overflow(n << abs(i)) 67 | return int_overflow(n >> i) 68 | 69 | 70 | def n(r, o): 71 | for t in range(0, len(o) - 2, 3): 72 | a = o[t + 2] 73 | a = ord(a) - 87 if a >= "a" else int(a) 74 | a = unsigned_right_shitf(r, a) if "+" == o[t + 1] else r << a 75 | r = r + a & 4294967295 if "+" == o[t] else r ^ a 76 | return r 77 | 78 | from translate import Translate 79 | 80 | with Translate("baidu") as t: 81 | t.set_logger() 82 | print(t.translate("my name is tom, i come from nanjing, I like eat shit, what about yours?")) -------------------------------------------------------------------------------- /README.rst: -------------------------------------------------------------------------------- 1 | # 超简单超好用的外语转中文翻译程序 2 | 适合翻译html,其中html标签不会被翻译,仅翻译标签之间的有效字符 3 | 4 | ## INSTALL 5 | ``` 6 | pip install translate-html 7 | ``` 8 | 9 | ## USAGE 10 | ``` 11 | usage: translate.py [-h] [-ws WEB_SITE] [-pl PROXY_LIST] [-pa PROXY_AUTH] 12 | [-rt RETRY_TIMES] [-tt TRANSLATE_TIMEOUT] 13 | [-lm LOAD_MODULE] 14 | src 15 | 16 | positional arguments: 17 | src The html you want to translate. 18 | 19 | optional arguments: 20 | -h, --help show this help message and exit 21 | -ws WEB_SITE, --web-site WEB_SITE 22 | Which site do you want to use for translating, split 23 | by `,`? default: baidu,youdao 24 | -pl PROXY_LIST, --proxy-list PROXY_LIST 25 | The proxy.list contains proxy to use for translate. 26 | default: ./proxy.list 27 | -pa PROXY_AUTH, --proxy-auth PROXY_AUTH 28 | Proxy password if have. eg. user:password 29 | -rt RETRY_TIMES, --retry-times RETRY_TIMES 30 | If translate failed retry times. default: 10 31 | -tt TRANSLATE_TIMEOUT, --translate-timeout TRANSLATE_TIMEOUT 32 | Translate timeout. default: 5 33 | -lm LOAD_MODULE, --load-module LOAD_MODULE 34 | The module contains custom web site functions which 35 | may translate. eg: trans.google 36 | ``` 37 | 38 | ## HELLOWORLD 39 | ### demo1 40 | 直接翻译 41 | ``` 42 | ubuntu@dev:~/myprojects/translate_html$ translate my 43 | 我的 44 | ubuntu@dev:~/myprojects/translate_html$ translate "
You can install httpbin as a library from PyPI and run it as a WSGI app. For example, using Gunicorn:
88 | ... 89 | ...$ pip install httpbin
90 | ... $ gunicorn httpbin:app
91 | ...
92 | ...
93 | ... 你可以安装httpbin从PyPI图书馆作为一个WSGI应用程序运行。例如,使用gunicorn:
美元httpbin pip安装gunicorn美元httpbin:APPYou can install httpbin as a library from PyPI and run it as a WSGI app. For example, using Gunicorn:
95 | ...:$ pip install httpbin
96 | ...: $ gunicorn httpbin:app
97 | ...:
98 | ...: 你可以安装httpbin从PyPI图书馆作为一个WSGI应用程序运行。例如,使用gunicorn:
美元httpbin pip安装gunicorn美元httpbin:APP