由於實際情況需要,最近需要用到谷歌翻譯部分,直接使用網頁web的url請求就是最好的選擇,下來先做原理的分析。
1、選擇任意可以F12開啓開發者模式的瀏覽器;
2、找到谷歌翻譯URL的地址:https://translate.google.cn
進入谷歌翻譯的主頁,然後去嘗試翻譯一箇中文
進入瀏覽器的F12,分析瀏覽器發生哪些url的請求,我們分析到有不少的url請求,我們去尋找有返回翻譯結果的URL請求
那麼這個url就是有效的,有返回原文和譯文的結果,然後檢視下直接的url是怎麼樣的
這裏可以的到發送的Url。
Request URL:
分析上面的url,可以得到參數不少
除了上面指出來的,其他的參數,暫時對我們用處不大,可以參考如下:
獲取上面的URL我們可以直接在瀏覽器存取到json的結果的,那麼結果證明,我們只需要上面URL就可以實現文字的存取就好了。
綜合網上的資料顯示,實現谷歌翻譯有兩種方法,歸納起來就是帶不帶token驗證。
1、一種就是不帶token驗證的就是隻使用下面 下麪的URL
https://translate.google.cn/translate_a/single?client=gtx&sl=zh-CN&tl=en&dt=t&q=%E4%BD%A0%E5%A5%BD
https://translate.google.cn/translate_a/single?client=at&sl=zh-CN&tl=en&dt=t&q=%E4%BD%A0%E5%A5%BD
上面兩個URL都可以存取到翻譯結果,對比之前的可以發現少了很多參數,最大的區別就是client的不同,使用at和gtx都可以不需要token驗證,dt=t表示只要翻譯結果,q是翻譯的文字,被urlencode了,但是使用的時候發現,這種方式只要次數一多,就會被遮蔽掉,返回error的結果,那麼這樣的話不能用。
2、另一種就是帶上token的驗證Url結果,就是client=webapp,在加上tk,這個tk是動態計算出來的。
大致的原理就是,在我們開啓谷歌翻譯首頁的時候,會伺服器動態下發tkk,我們姑且稱爲token key吧。經過試驗發現這個tkk不是實時變化的,一段時間內都是有效,但是有效時間多久沒有有效的驗證過(至少我們測試階段是可以寫死一個tkk使用的)。右鍵可以開啓原始碼,搜尋tkk可以找到(也有網友找到了計算的例子想了想,這種和直接下發沒差。
然後很多熱心網友發計算tk的演算法出來,不過都是JS版本的(我們Lua專案移植起來很難啊),下面 下麪的演算法經過傳入瀏覽器裏面獲取的ttk和翻譯的文字計算出來的tk,和瀏覽器裏面獲取的tk是一致的,說明演算法是Ok的,驗證了演算法可用性(菜鳥教學有線上JS編輯器,就省去了弄JS環境驗證演算法了)
var b = function (a, b) {
var tmp_c, tmp_c2;
for (var d = 0; d < b.length - 2; d += 3) {
var c = b.charAt(d + 2),
tmp_c2 = c,
c = "a" <= c ? c.charCodeAt(0) - 87 : Number(c),
tmp_c = c,
c = "+" == b.charAt(d + 1) ? a >>> c : a << c;
a = "+" == b.charAt(d) ? a + c & 4294967295 : a ^ c;
}
return a
}
var tk = function (a,TKK) {
for (var e = TKK.split("."), h = Number(e[0]) || 0, g = [], d = 0, f = 0; f < a.length; f++) {
var c = a.charCodeAt(f);
128 > c ? g[d++] = c : (2048 > c ? g[d++] = c >> 6 | 192 : (55296 == (c & 64512) && f + 1 < a.length && 56320 == (a.charCodeAt(f + 1) & 64512) ? (c = 65536 + ((c & 1023) << 10) + (a.charCodeAt(++f) & 1023), g[d++] = c >> 18 | 240, g[d++] = c >> 12 & 63 | 128) : g[d++] = c >> 12 | 224, g[d++] = c >> 6 & 63 | 128), g[d++] = c & 63 | 128)
}
a = h;
for (d = 0; d < g.length; d++) a += g[d], a = b(a, "+-a^+6");
a = b(a, "+-3^+b+-f");
a ^= Number(e[1]) || 0;
0 > a && (a = (a & 2147483647) + 2147483648);
a %= 1E6;
return a.toString() + "." + (a ^ h)
}
要移植到lua的話,有幾個問題:
1、lua沒有位運算;
2、lua沒有JS一樣的length,charCodeAt,charAt方法,Lua中文佔了三個位元組不能直接用string.byte,lua不能直接獲取unicode編碼
那麼,現在就要實現lua的位運算,以及計算其他不支援的效果
這個網址介紹了Lua的位運算相關操作https://www.jianshu.com/p/115bc9e5b6a6
位運算的例子在這裏可以有
https://github.com/lilien1010/lua-bit/blob/master/bit.lua
那麼現在就可以翻譯到Lua程式碼了
Js的b方法翻譯到下面 下麪lua
function rl(a, b)
local blen = string.len(b)
local byte_a = string.byte("a", 1)
local byte_yb = string.byte("+", 1)
for i = 1, blen - 2, 3 do
local d = i
local c = string.byte(b, d + 2)
if byte_a <= c then
c = c - 87
else
c = tonumber(string.sub(b, d + 2, d + 2))
end
if byte_yb == string.byte(b, d + 1) then
c = bit.rshift(a, c)
else
c = bit.lshift(a, c)
end
if byte_yb == string.byte(b, d) then
a = bit.band(a + c, 4294967295)
else
a = bit._xor(a, c)
end
end
return a
end
Js的tk方法翻譯到Lua爲下面 下麪的方法
--獲取編碼
function getCharCodeAt( chars )
-- body
local m = 0
if chars then
local char = chars.char
local allByte = bit.charCodeAt(char)
m = allByte[1]
end
return m
end
function TranslateGoogle.token(a, tkk)
local tkkSplit = splitString(tkk, "%.")
local k = ""
local b = tonumber(tkkSplit[1])
local b1 = tonumber(tkkSplit[2])
local jd = "."
local sb = "+-a^+6"
local zb = "+-3^+b+-f"
local e = {}
local f = 1
local splitChars = splitToTable(a)
local alen = table.getn(splitChars)
for i = 1, alen do
local g = i
local chars = splitChars[g]
local m = getCharCodeAt( chars )
if 128 > m then
e[f] = m
f = f + 1
else
if 2048 > m then
e[f] = bit._or(bit.rshift(m, 6), 192)
f = f + 1
else
local next_chars = splitChars[g + 1]
local next_m = getCharCodeAt( next_chars )
if 55296 == bit.band(m, 64512) and g + 1 < alen and 56320 == (bit.band(next_m, 64512)) then
m = 65536 + (bit.lshift(bit.band(m, 1023), 10))
i = i + 1
m = m + (bit.band(next_m, 1023))
e[f] = bit._or(bit.rshift(m, 18), 240)
f = f + 1
e[f] = bit._or(bit.band(bit.rshift(m, 12), 63), 128)
f = f + 1
else
e[f] = bit._or(bit.rshift(m , 12), 224)
f = f + 1
e[f] = bit._or(bit.band(bit.rshift(m, 6), 63), 128)
f = f + 1
end
end
e[f] = bit._or(bit.band(m, 63), 128)
f = f + 1
end
end
a = b
for f = 1, #e do
a = a + e[f]
a = rl(a, sb)
end
a = rl(a, zb)
a = bit._xor(a, b1 or 0)
if 0 > a then
a = bit.band(a, 2147483647) + 2147483648
end
a = a % 1E6
return string.format("%s%s%s", tostring(a), jd, bit._xor(a, b) )
end
這裏方法splitString是裁切ttk的點號前後的數位,和splitToTable是裁切字串字元的,就是替換Js方法的chatAt,爲了讓中文也是正常的被裁切出來,這裏就不一一列舉出來具體的實現方法了。
最後提下ttk的獲取方法,可以通過存取https://translate.google.cn的返回程式碼,然後通過匹配出tkk("tkk:\'%d+.%d+\'")這個正則,然後就可以獲取動態的tkk了,這樣是爲了防止tkk失效的情況,至少每次都可以獲取最新的tkk使用,通過實驗證明,一天之內tkk應該是有效的
總結:整個過程中lua實現tk演算法是比較麻煩的,Js比較容易實現的操作,在lua裏面沒有現成的介面,上面的演算法經過測試可以投產使用了