免費、無限制地使用Google翻譯API
2023-07-29
在日常生活中經常使用的 Google 翻譯,它的 API 與 免費的 APP 或網頁版不同,要支付的費用不是我這些為興趣而使用的人、能夠不以為意地付錢的,所以這次就分享一下截至目前為止還能免費使用的方法~
@vitalets/google-translate-api
@vitalets/google-translate-api 這個 NodeJS 模組雖然隨著 Google 翻譯網站的更新,限制變得比以前多,但是至少還能夠正常運作,如果沒有 NodeJS,建議使用 pnpm 安裝
npm install @vitalets/google-translate-api
解決 rate limit 問題
模組的用法本身十分簡單,但太頻繁地使用會遇到 TooManyRequestsError (code 429)
的錯誤
以前我幾乎沒有遇到過 (至少 limit 沒那麼低),但最近只要短時間使用十幾次左右 IP 便會被 block 掉,而解決方法就是交替使用不同的 proxy agent
來降低相同 IP 的使用頻率,因此我們還需要 http-proxy-agent
模組
npm install http-proxy-agent
然後我們可以在模組建議的網站 https://free-proxy-list.net/ 取得免費 proxy 列表,先拷貝這些 IP
再用這個腳本篩選能用的 proxy,如果不介意回傳速度的話,可以把 timeout
調高一點,而我個人常用於即時翻譯,所以才設定得比較嚴格一點
const { translate } = require("@vitalets/google-translate-api");
const { HttpProxyAgent } = require("http-proxy-agent");
// 把複製的ip貼到這裡
const PROXY_LIST = [
"139.59.1.14:8080",
"103.83.232.122:80",
...
];
const TIMEOUT_MS = 2000;
async function checkProxy(ip) {
return new Promise(async (rs, rj) => {
try {
const { text } = await translate("cappa", {
to: "zh-tw",
// 篩選2秒內有response的地址
fetchOptions: { agent: new HttpProxyAgent(ip), timeout: TIMEOUT_MS },
});
return rs(ip);
} catch (err) {
rs("");
}
});
}
async function run(addrs) {
const tasks = [];
for (let i = 0; i < addrs.length; i++) {
const ip = addrs[i];
if (ip.startsWith("http")) {
tasks.push(checkProxy(ip));
} else {
const httpAddr = `http://${ip}`;
const httpsAddr = `https://${ip}`;
tasks.push(checkProxy(httpAddr));
tasks.push(checkProxy(httpsAddr));
}
}
return (await Promise.all(tasks)).filter((ip) => ip);
}
(async () => {
const filteredProxyList = await run(PROXY_LIST);
// 再次檢查確保地址能使用
const validProxyList = await run(filteredProxyList);
console.log(validProxyList);
})();
儲存為 index.js
並執行,最後可能只有幾個地址能使用
> node ./index.js
[
'http://103.83.232.122:80',
'http://123.30.154.171:7777',
'http://207.2.120.19:80',
'http://116.203.28.43:80',
'http://103.49.202.252:80',
'http://47.88.62.42:80',
'http://94.130.232.43:80',
'http://212.107.31.118:80'
]
應用例子
取得地址以後,我們便可以順序使用以降低被 block 的機率,還可以在檢測到 TooManyRequestsError
的時候自動使用下一個地址
const { translate } = require("@vitalets/google-translate-api");
const { HttpProxyAgent } = require("http-proxy-agent");
const PROXY_LIST = [
"http://103.83.232.122:80",
"http://123.30.154.171:7777",
"http://207.2.120.19:80",
"http://116.203.28.43:80",
"http://103.49.202.252:80",
"http://47.88.62.42:80",
"http://94.130.232.43:80",
"http://212.107.31.118:80",
];
const TIMEOUT_MS = 5000;
let currentProxy = 0;
function getAgent() {
let idx = currentProxy++;
if (idx >= PROXY_LIST.length - 1) {
currentProxy = 0;
}
const agent = PROXY_LIST[idx];
console.log(agent);
return new HttpProxyAgent(agent);
}
async function translateWithProxy(inputTxt) {
try {
const agent = getAgent();
const { text } = await translate(inputTxt, {
to: "zh-tw",
fetchOptions: { agent, timeout: TIMEOUT_MS },
});
console.log(`'${inputTxt}' > ${text}`);
return text;
} catch (e) {
// 嘗試下一個地址
if (e.name === "TooManyRequestsError") {
console.log("failed.");
translateWithProxy(inputTxt);
}
}
}
(async () => {
for (let i = 0; i < 10; i++) {
await translateWithProxy("hello world!");
}
})();
這次全部成功翻譯
> node ./index.js
http://103.83.232.122:80
'hello world!' > 你好世界!
http://123.30.154.171:7777
'hello world!' > 你好世界!
http://207.2.120.19:80
'hello world!' > 你好世界!
http://116.203.28.43:80
'hello world!' > 你好世界!
http://103.49.202.252:80
'hello world!' > 你好世界!
http://47.88.62.42:80
'hello world!' > 你好世界!
http://94.130.232.43:80
'hello world!' > 你好世界!
http://212.107.31.118:80
'hello world!' > 你好世界!
http://103.83.232.122:80
'hello world!' > 你好世界!
http://123.30.154.171:7777
'hello world!' > 你好世界!
需定期更新
這些共享地址隨時都會失效,所以目前只能定期更新了,慶幸的是從抓取地址到使用腳本篩選也只不過是一分鐘內的事,所以還可以接受吧…當然我們可以全自動化這個流程,但也會受 proxy 網站的改動而影響運作,所以這次就不作嘗試了