用起來長這樣
環境:
VirtualBox+Ubuntu 18.04.02
最近逛Ubuntu應用商店,看到網友做了這麼一個東東,感覺想法挺不錯的。學習Linux經常要閱讀英文文檔,手上有個控制檯輸出的翻譯工具,CTRL-TAB切換到終端,只需敲打相關的命令就可以馬上弄明白詞義。整個過程連鼠標都不用碰,確實會比GUI翻譯工具效率高出不少。
當然也有網友自己寫了個linux終端翻譯神器
,用一個文件來實現這個功能(用了很少的庫),只是輸出格式上還有待考究,而且沒有讀音標註。不過可以當成一個精簡的範例來學習。
這裏說一下yd應用安裝下來是不能使用的,報錯原因是main.py一處語法錯誤(引號不成對),文件目錄顯示2017年之後就沒人維護了。想着源碼都有,乾脆自己動手改。
順便說一下,這是snap商城的東西,安裝目錄都是隻讀的,所以還不能硬上。
環境搭建流程
-
將 /snap/yd/2/lib/python2.7/site-packages/youdao/ 這個目錄拷貝到$HOME下。
-
把main.py那處語法錯誤改了。
-
安裝所需要的庫,必要的時候加上版本號
pip install termcolor
pip install requests
pip install peewee==2.9.1
pip install bs4
pip install lxml==3.7.3 -
main.py中有個和snap相關的目錄要改,並且在這個目錄下創建/dicts空目錄。
SNAP = ‘/home/USER_NAME/youdao’
-
在$HOME/.bashrc中加入自定義命令
alias yd=‘python /home/USER_NAME/youdao/main.py’
-
source $HOME/.bashrc
然後就可以盡情地玩耍了。
功能描述
今天看了下代碼,把用到的庫的作用也整明白了(原來這就是爬蟲),剛好看到main.py的幫助文檔是空的。
def show_help():
desc = '''
== 說明 ==
* 功能描述
獲取查詢結果有兩種方式:
1. 使用api的方式,直接返回json字符串
2. 使用頁面方式,則需要借用BeautifulSoup解析返回的html
PS. 如果以上查詢都失敗(比如給句子加上標點),則使用有道翻譯
查詢記錄保存在peewee數據庫中,所有基於db的操作都與此有關
離線字典保存的目錄,由config.config['stardict']指定
* 可選參數
-a 使用有道api查詢,參考官網 http://fanyi.youdao.com/openapi?path=data-mode
-n 不用數據庫中緩存的查詢記錄
-l 列出查詢記錄及累計次數
-d [key] 刪除制定文本的查詢記錄,包括髮音文件
-c 刪除所有的查詢記錄,包括髮音文件
-v 查詢並播放發音,可使用 yd -v 重複播放上一查詢記錄的發音
-s [path] 指定離線字典的目錄,默認爲/dicts
-y 完全的在線查詢。既不使用數據庫查詢記錄,也不使用離線字典
'''
print desc
修復get_translation函數
[spider.py]
def get_translation(self, word):
"""
通過web版有道翻譯抓取翻譯結果
:param word:str 關鍵字
:return:list 翻譯結果
"""
r = requests.get(self.translation_url+word)
if r.status_code != requests.codes.ok:
return None
pattern = re.compile(r'"translateResult":\[(\[.+\])\]')
m = pattern.search(r.text)
result = json.loads(m.group(1))
return [item['tgt'] for item in result]
可能因爲有道翻譯版本升級過,這裏的get_translation並不好使,輸入以下命名會有tb。
ron@ron-Z68AP-D3:~$ yd 'Judge a book by its cover.'
[Judge a book by its cover.]
有道翻譯:
Traceback (most recent call last):
File "/home/ron/youdao/main.py", line 236, in <module>
main()
File "/home/ron/youdao/main.py", line 233, in main
query(keyword, use_db, use_api, play_voice, use_dict)
File "/home/ron/youdao/main.py", line 117, in query
show_result(result)
File "/home/ron/youdao/main.py", line 45, in show_result
print colored('\t'+'\n\t'.join(result['translation']), 'cyan')
TypeError: can only join an iterable
加個標點符號,api和web兩個方式就跪了
預期是拿到翻譯’以貌取人’。
既然原版的url訪問方式不可行,就自己嘗試實現這個功能好了。
[spider.py]
translation_url = u'http://fanyi.youdao.com/translate_o?smartresult=dict&smartresult=rule'
def md5(self, str_data):
"""
md5加密
"""
md5_obj = hashlib.md5()
byte_data = str_data.encode('utf-8')
md5_obj.update(byte_data)
return md5_obj.hexdigest()
def get_translation(self, word):
"""
通過web版有道翻譯抓取翻譯結果
:param word:str 關鍵字
:return:list 翻譯結果
"""
client = 'fanyideskweb' #判斷是網頁還是客戶端
# 由於網頁是用的js的時間戳(毫秒)跟python(秒)的時間戳不在一個級別,所以需要*1000
salt = str(int(time.time()*1000))
# 網上不同的攻略取的魔數是不一樣的,可能對應不同的版本吧
c = "@6f#X3=cCuncYssPsuRUE"
# c = "rY0D^0'nM0}g5Mm1z%1G4"
# c = "ebSeFb%=XZ%T[KZ)c(sy!"
# 根據md5的方式:md5(u + d + f + c),拼接字符串生成sign參數。
sign = self.md5(client + word + salt + c)
# bv用到瀏覽器的版本編號
navigatorAppVersion = '5.0 (X11)'
bv = self.md5(navigatorAppVersion)
data = {
'i':word,
'from':'AUTO',
'to':'AUTO', #判斷是自動翻譯還是人工翻譯
'smartresult':'dict',
'client':client,
'salt':salt, #當前時間戳
'sign':sign, #獲取加密串
'ts':salt,
'bv':bv,
'doctype':'json',
'version':'2.1',
'keyfrom':'fanyi.web',
'action':'FY_BY_REALTIME', #判斷按回車提交或者點擊按鈕提交的方式
'typoResult':'false',
}
headers = {
'Accept': 'application/json, text/javascript, */*; q=0.01',
'Accept-Encoding': 'gzip, deflate', #
'Accept-Language': 'zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2',
'Connection': 'keep-alive',
'Content-Length': '259', #
'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8',
'Host': 'fanyi.youdao.com',
'Origin':'http://fanyi.youdao.com/', #請求頭最初是從youdao發起的,Origin只用於post請求
'Referer':'http://fanyi.youdao.com/', #Referer則用於所有類型的請求
'User-Agent':'Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:67.0) Gecko/20100101 Firefox/67.0',
'X-Requested-With': 'XMLHttpRequest',
}
r = requests.post(self.translation_url, headers=headers, data=data)
pattern = re.compile(r'"translateResult":\[(\[.+\])\]')
m = pattern.search(r.text)
result = json.loads(m.group(1))
return [item['tgt'] for item in result]
效果
參考文獻:
Python網絡爬蟲(八) - 利用有道詞典實現一個簡單翻譯程序
解答了大部分問題,但是我的瀏覽器裏多了兩個參數ts bv。
有道翻譯的爬取
很不爽這裏面沒有說清楚爲什麼替換了url。不過有意思的是itchat這個玩意。
破解有道翻譯反爬蟲機制
代碼直接可用,只是加標點會有tb。
ron@ron-Z68AP-D3:~$ python3 test.py
請輸入Judge a book by its cover.
判斷一本書的好壞灣。
Traceback (most recent call last):
File "test.py", line 68, in <module>
youdao(input("請輸入"))
File "test.py", line 64, in youdao
for i in strs_datas['smartResult']['entries']:
KeyError: 'smartResult'
ron@ron-Z68AP-D3:~$ python3 test.py
請輸入Judge a book by its cover
通過封面來判斷一本書的好壞
以貌取人