小記:作為一個有追求的碼農,“懶”,不一定是一個貶義詞。有時候“懶”,才是進步的動力!
背景
經常遇到這樣的情況,發現一本眼饞的技術書?,卻發現只有英文版。慢慢啃嗎?真的很痛苦。於是靈光一閃,我需要這樣一個小工具,點選執行可以批量的完成翻譯任務。於是,去吧皮卡丘!
技術選型
- 翻譯一直信任某歌(科學上網);
- 作為一名小前端,希望用JS一桶天下;
辛路例程
嘗試一:
用某歌翻譯的API,翻山越嶺,翻江倒海的查到了API的用法,確實很好用。但是在嘗試過程中發現,還需要VISA註冊。於是撲街?!
嘗試二:
用cheerio做個爬蟲?做了一半才想起來,翻譯出的資料是JS嵌入的,cheerio是無法抓取到的,被自己蠢哭?!
嘗試三:
祭出大招,使用無頭瀏覽器,模擬人工翻譯過程,啥過程?英文輸入->翻譯->將中文輸入拷貝到指定文件?。
Show Me the CODE!
const puppeteer = require('puppeteer');
const path = require('path');
const fs = require('fs');
const util = require('util');
const appendFile = util.promisify(fs.appendFile);
const CONFIG = {
input: 'React/ch09.txt',
out:'out.txt',
url: 'https://translate.google.cn/#en/zh-CN/'
};
const inputPath = path.join(__dirname,CONFIG.input);
const outPath = path.join(__dirname,CONFIG.out);
const trans = async ()=>{
try {
//開啟瀏覽器,進入谷歌翻譯網頁
const browser = await puppeteer.launch({headless: false});
const page = await browser.newPage();
await page.goto(CONFIG.url);
fs.writeFileSync(outPath,'');
//讀取文件
let fr = fs.readFileSync(inputPath,"utf-8");
let tmpArr = [];
fr.split('\n').forEach((line,index)=>{
let tmp = line.trim();
tmp.length > 0 && tmpArr.push(' '+tmp)
});
for(let i=0; i<tmpArr.length; i++){
let tmpInput = tmpArr[i];
await page.type('#source', tmpInput,{delay: 10});
page.click('#src-translit');
await page.waitFor(1500);
let transOutput = await page.evaluate(() => {
let text='';
if(document.querySelector('#result_box span')){
[...document.querySelectorAll('#result_box span')].forEach((nod)=>{
text+=nod.innerText;
})
}
return text;
});
console.log(i,tmpInput);
await appendFile(outPath,tmpInput+'\n');
await appendFile(outPath,transOutput+'\n');
await page.waitFor(500);
page.click('#gt-clear');
}
await page.waitFor(1000);
browser.close();
}catch (e) {
console.log(e);
}
};
trans();
複製程式碼
娓娓道來
- 無頭瀏覽器選用的是puppeteer,因為想接觸一下這個PhantomJS的繼承者。
- 作為指令碼執行在node環境中,當然充分利用Node的原生API了(fs,util,path)。
- 使用了async/await, 讓非同步程式碼看著更優雅一點。
- 將非同步的fs.appendFile Promise化。
- Puppeteer的API,就簡單用了幾個:
- puppeteer.launch 開啟瀏覽器
- browser.newPage 新建頁面
- page.goto 跳轉到制定網址
- page.type 模擬使用者輸入
- page.click 模擬點選事件,引數為被點選元素的選擇器
- page.waitFor 等待,為什麼要等待?JS單執行緒,你懂得,慢,拖拉機一樣慢!
- browser.close 關閉瀏覽器,點選紅叉退出。
- 最重要的就是page.evaluate了,通過回撥函式,輕鬆操作返回頁面的dom。
大概就這些,第一次發文,歡迎各位過路大神拍磚。
附git地址:https://github.com/gavin103/gotrans
後續將繼續改進,敬請期待~