| |
| |
| |
| |
| |
| import getopt, sys |
| import json |
| import re |
| import http.client |
| import hashlib |
| import urllib |
| import urllib.request |
| import urllib.parse |
| import random |
| import os |
| from io import StringIO |
| |
| try: |
| import pyperclip |
| except ImportError: |
| pyperclip = {} |
| |
| zhPattern = re.compile(u'[\u4e00-\u9fa5]+') |
| |
| appid = '20151113000005349' |
| secretKey = 'osubCEzlGjzvw8qdQc41' |
| |
| jsonPath = jsonPath_base = (os.path.realpath(sys.argv[0]))+'.json' |
| |
| |
| |
| if not ( appid and secretKey ) : |
| print("你需要在脚本中设置 appid 和 secretKey", file=sys.stderr) |
| print("API接口申请: http://api.fanyi.baidu.com/api/trans/product/index", file=sys.stderr) |
| sys.exit(2) |
| |
| option = {} |
| globalVar = {'num':0} |
| httpClient = None |
| stdinfo = sys.stderr |
| |
| |
| def main(): |
| if os.path.isfile(jsonPath) : |
| getConfig(jsonPath) |
| |
| try: |
| opts,args = getopt.getopt(sys.argv[1:], "hnf:t:DTc", ["help", "from=", "to=", "dict", "text", "num", "debug","web=","clip"]) |
| |
| except Exception as e: |
| print("参数错误", file=sys.stderr) |
| sys.exit(2) |
| |
| for opt,arg in opts: |
| if opt in ("-h", "--help"): |
| usage() |
| sys.exit(0) |
| elif opt in ("-c","--clip"): |
| if not pyperclip : |
| print('-c 选项需 pyperclip 模块支持', file=sys.stderr) |
| sys.exit(2) |
| |
| option['clip'] = True |
| args = [pyperclip.paste()] |
| elif opt in ("-n","--num"): |
| option['num'] = True |
| elif opt in ("-f", "--form"): |
| option['from'] = arg |
| if 'to' in option and arg.lower() != 'zh' : option['to']='zh' |
| elif opt in ("-t", "--to"): |
| option['to'] = arg |
| if 'from' in option and arg.lower() != 'zh' : option['from']='zh' |
| elif opt in ("-D","--dict"): |
| option['dict'] = True |
| elif opt in ("-T","--text"): |
| option['text'] = True |
| elif opt in ("--debug"): |
| option['debug'] = True |
| elif opt in ("--web"): |
| if arg == 'baidu': |
| os.system("start http://fanyi.baidu.com/") |
| elif arg == 'google': |
| os.system("start https://translate.google.cn/") |
| elif arg == 'youdao': |
| os.system("start http://fanyi.youdao.com/") |
| elif arg == 'iciba': |
| os.system("start http://fy.iciba.com/") |
| elif arg == 'haici': |
| os.system("start http://fanyi.dict.cn/") |
| else: |
| print("--web baidu | google | youdao | iciba | haici") |
| sys.exit(0) |
| else: |
| print("%s ==> %s" %(opt, arg)) |
| |
| if 'debug' in option: |
| print("Opts:\r\n%s" % opts, file=stdinfo) |
| print("Args:\r\n%s" % args, file=stdinfo) |
| print("Option:\r\n%s" % option, file=stdinfo) |
| |
| fromLang = option['from'] if 'from' in option else 'auto' |
| toLang = option['to'] if 'to' in option else 'zh' |
| |
| |
| try: |
| if len(args)==0 : |
| if sys.stdin.isatty(): |
| usage() |
| else: |
| q = re.sub(r'\r?\n','\r\n',sys.stdin.read()) |
| choiceMode(q, fromLang, toLang) |
| |
| sys.exit(0) |
| |
| if len(args)==1 : |
| choiceMode(args[0], fromLang, toLang) |
| sys.exit(0) |
| |
| |
| if 'dict' in option: |
| for arg in args: |
| |
| if fromLang == 'auto' and zhPattern.search(arg) : |
| toLang = 'en' |
| |
| print('[Dict Mode] %s -> %s\r\n' % (fromLang, toLang), file=stdinfo) |
| |
| words = re.split(r'\s+',arg) |
| for word in words: |
| word = word.strip() |
| trans_dict(word, fromLang, toLang) |
| print('\r\n'); |
| sys.exit(0) |
| else: |
| q = '\r\n'.join(args) |
| |
| if fromLang == 'auto' and zhPattern.search(q) : |
| toLang = 'en' |
| |
| print('[Text Mode] %s -> %s\r\n' % (fromLang, toLang), file=stdinfo) |
| trans_text(q, fromLang, toLang) |
| |
| except Exception as e: |
| print(e, file=sys.stderr) |
| sys.exit(1) |
| |
| |
| |
| def trans_dict(word, fromLang, toLang): |
| resp=urllib.request.urlopen(compose_request(word)) |
| if(resp.status==200): |
| handle_result(resp.read().decode('utf-8')) |
| else: |
| print('Rquest Error: \r\n HTTP Status: %d \r\n Reason: %s \r\n', resp.status, resp.reason) |
| |
| |
| def trans_text(q, fromLang, toLang): |
| salt = random.randint(32768, 65536) |
| |
| sign = appid+q+str(salt)+secretKey |
| m1 = hashlib.md5() |
| m1.update(bytes(sign, encoding = "utf8") ) |
| sign = m1.hexdigest() |
| |
| myurl = '/api/trans/vip/translate?appid='+appid+'&q='+urllib.parse.quote(q)+'&from='+fromLang+'&to='+toLang+'&salt='+str(salt)+'&sign='+sign |
| |
| try: |
| httpClient = http.client.HTTPConnection('api.fanyi.baidu.com') |
| httpClient.request('GET', myurl) |
| |
| |
| response = httpClient.getresponse() |
| ret = response.read() |
| retstr = str(ret,'utf-8') |
| retobj= json.loads(retstr) |
| |
| if 'num' in option: |
| str_template='[%05d] -----------------------------------------\r\n%s' |
| else: |
| str_template='%0.s-------------------------------------------------\r\n%s' |
| |
| if 'error_code' in retobj and retobj['error_code'] != '52000' : |
| print(" 错误码: " + retobj['error_code'], file=sys.stderr) |
| print(" 说明: " + retobj['error_msg'], file=sys.stderr) |
| sys.exit(retobj['error_code']) |
| else : |
| for trans_result in retobj['trans_result']: |
| globalVar['num']=globalVar['num']+1 |
| print(str_template % (globalVar['num'], trans_result['src']), file=stdinfo) |
| print(trans_result['dst']) |
| |
| except Exception as e: |
| print(e, file=sys.stderr) |
| finally: |
| if httpClient: |
| httpClient.close() |
| |
| |
| def getConfig(configPath): |
| config_default = {} |
| config = config_default |
| |
| if os.path.isfile(configPath) : |
| try : |
| fp = open(configPath,"r") |
| config = json.load(fp) |
| fp.close() |
| except Exception as e: |
| config = config_default |
| |
| global appid, secretKey |
| |
| if 'appid' in config and 'secretKey' in config and config['appid'] and config['secretKey'] : |
| appid = config['appid'] |
| secretKey = config['secretKey'] |
| |
| |
| def usage(): |
| argshelp = ''' |
| -f lang --from lang |
| 指定翻译前的语言为 lang,可选项详见百度翻译api文档 |
| |
| -t lang --to lang |
| 指定翻译后的语言为 lang,可选项详见百度翻译api文档 |
| |
| -T --text |
| 以文本形式翻译 |
| |
| -D --dict |
| 以字典形式翻译 |
| |
| -n --num |
| 以数字形式翻译 |
| |
| -c --clip |
| 从剪贴板获取要翻译的内容 |
| |
| --web name |
| 用浏览器打开翻译页面(不支持长文本),name 为所用的翻译引擎 |
| 可选项为 baidu/google/youdao/iciba/haici |
| |
| --debug |
| 调试模式 |
| |
| -h --help |
| 显示简单的帮助信息''' |
| |
| print("Usage:%s [-f lang] [-t lang] [--web name] [-c] [-n|-T|-D] args...." % os.path.basename(sys.argv[0])) |
| print(argshelp) |
| |
| if os.path.isfile(jsonPath) : |
| print("\r\n 配置文件: \"%s\"" % jsonPath) |
| print(" 该文件用于设置要使用的 appid 和 secretKey") |
| print(" 接口申请地址:\"http://api.fanyi.baidu.com/api/trans/product/index\"") |
| else : |
| print("\r\n 当前无配置文件,默认使用测试 ID") |
| print(" 接口申请地址:\"http://api.fanyi.baidu.com/api/trans/product/index\"") |
| print("\r\n 如需自定义 appid 和 secretKey,请以 JSON 格式保存到配置文件:") |
| print(" \"%s\"" % jsonPath) |
| print("\r\n 配置文件的格式为:") |
| print(" {'appid': '你的 APPID', 'secretKey': '你的秘钥'}") |
| |
| |
| class Result: |
| def __init__(self, src, dest, meanings=None): |
| self.src=src |
| self.dest=dest |
| self.meanings=meanings |
| |
| def parse_from_json(json_data): |
| trans_data=json_data['trans_result']['data'][0] |
| try: |
| means=None |
| if 'simple_means' in json_data['dict_result']: |
| dict_data=json_data['dict_result']['simple_means']['symbols'][0]['parts'] |
| means=list() |
| for item in dict_data: |
| tmp=item['means'] |
| if isinstance(tmp[0],dict): |
| for t_item in tmp: |
| means.append(t_item['word_mean']) |
| else: |
| means.append(tmp) |
| except KeyError: |
| means=None |
| |
| return Result(trans_data['src'],trans_data['dst'],means) |
| |
| def show(self,file=sys.stdout): |
| if 'num' in option: |
| str_template='<<<translate\r\n %05d:\t %s ---> %s\r\n\r\n<<<meaning' |
| else: |
| str_template='<<<translate\r\n %0.s%s ---> %s\r\n\r\n<<<meaning' |
| |
| globalVar['num']=globalVar['num']+1 |
| |
| print(str_template % (globalVar['num'], self.src, self.dest), file=stdinfo) |
| [print(" %s" % meaning) for meaning in self.meanings] |
| |
| |
| def handle_result(content): |
| json_data=json.loads(content) |
| Result.parse_from_json(json_data).show() |
| |
| def compose_request(word): |
| TRANS_URL='http://fanyi.baidu.com/v2transapi' |
| ORIGIN_HOST='fanyi.baidu.com' |
| |
| r""" |
| compose urllib.request.Request object accordingly |
| |
| """ |
| body=StringIO() |
| body.write('from=zh&to=en' if zhPattern.search(word) else 'from=en&to=zh') |
| body.write('&') |
| body.write(urllib.parse.urlencode({'query': word }, encoding='utf-8')) |
| body.write('&transtype=trans&simple_means_flag=3') |
| body=body.getvalue() |
| |
| headers={'Content-Type':'application/x-www-form-urlencoded; charset=UTF-8', |
| 'X-Requested-With':'XMLHttpRequest' |
| } |
| |
| return urllib.request.Request(TRANS_URL, body.encode(encoding='utf-8'), headers=headers, origin_req_host=ORIGIN_HOST, method='POST') |
| |
| |
| |
| def choiceMode(q, fromLang, toLang): |
| if fromLang == 'auto' and zhPattern.search(q) : |
| toLang = 'en' |
| |
| word = re.sub(r'\r|\r\n','',q).strip() |
| if re.search(r'\s',word): |
| |
| print('[Text Mode] %s -> %s\r\n' % (fromLang, toLang), file=stdinfo) |
| trans_text(q, fromLang, toLang) |
| else: |
| print('[Dict Mode] %s -> %s\r\n' % (fromLang, toLang), file=stdinfo) |
| trans_dict(word, fromLang, toLang) |
| |
| main()COPY |