免費、無限制地使用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 List

再用這個腳本篩選能用的 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 網站的改動而影響運作,所以這次就不作嘗試了