资讯专栏INFORMATION COLUMN

记一次翻译站经历

seasonley / 3299人阅读

摘要:做这个记录之前,刚完成使用作为公司前端项目的持续交付工具的实践,打算写的教程前先把官方文档扒下来做个翻译站。在实践一番后,卡在不能频密调取翻译这块上,项目无法进行下去。

做这个记录之前,刚完成使用drone作为公司前端项目的持续交付工具的实践,打算写的教程前先把官方文档扒下来做个翻译站。在实践一番后,卡在不能频密调取google翻译这块上,项目无法进行下去。最后觉得经历的过程涉及的内容挺多的所以记录一下同时分享给大家。

这次经历涉及以下知识:

wget抓取网站

使用基于python的翻译工具

使用nodejs调取命令行

使用nodejs读写文件

express添加jwt

基于express实现上传文件

nodejs环境下读取并编辑html文件

我们一点点来说。

wget抓取网站

最初是寻找有什么带可视化的工具来达到目的的,后来在寻找的过程中看到原来wget能实现整站抓取,所以怎样简单怎样来!

# 抓取整站
wget -r -p -np -k -E http://www.xxx.com
# w抓取第一级
wget -l 1 -p -np -k http://www.xxx.com

-r 递归抓取

-k 抓取后修正链接,适合本地浏览

-e robots=off 忽略robots协议,强制抓取(流氓抓取)

-Etext/html类型的文档保存为.html的文件

使用基于python的翻译工具

这个在github上找了几个工具,同时也考虑过使用官方提供的API(微软和google均有提供),最后得出使用soimort/translate-shell(并不想花钱和花时间再看文档上了>w<)

这个trans shell工具提供几个翻译源(google, bing, yandex, apertium),不知道为何能用的只有google Σ(!゚д゚)。google也很有保证了,问题不大。

安装并不复杂,只需要安装gawk,其他在ubuntu系统下默认都有包含的:

GNU Awk

gawk安装

$ sudo apt-get install gawk

尝试:

$ gawk -f <(curl -Ls git.io/translate) -- -shell

安装trans本体,官方文档提供三种方式,方式1不知道为何有bug,方式2并不太熟悉,最后选择方式3

$ git clone https://github.com/soimort/translate-shell
$ cd translate-shell/
$ make
$ [sudo] make install

使用起来也是简单:

$ trans "Saluton, Mondo!"
Saluton, Mondo!

Hello, World!

Translations of Saluton, Mondo!
[ Esperanto -> English ]
Saluton ,
    Hello,
Mondo !
    World!

简短输出方式:

$ trans -brief "Saluton, Mondo!"
Hello, World!

翻译文件:

$ trans -b en:zh -i input.txt -o output.txt
使用trans调取google translate进行翻译不能频频调用,频频调用之后会令后续请求503,被google限制请求!!
使用nodejs调取命令行

完成翻译的调研后,感觉本地实现翻译需要安装各种东西,不如做成web应用好了。用express快速建立网站应用,关于在nodejs下调用命令其实是没啥头绪的,搜索得出结果发现可以使用Child Process模块实现:

const util = require("util")
const exec = util.promisify(require("child_process").exec)
exec(`trans -V`)
    .then(({stdout, stderr}) => {
        if(stdout.indexOf("not installed") > -1) return Error(stdout)
    })
    .then(()=>exec(`trans -b ${language} -i ${input} -o ${output}`))
    .then(({stdout, stderr})=>{
        return {
            input,
            output,
            message: stdout
        }
    })
使用nodejs读写文件

这个就不详细说明了,简单列一下用到的函数:

fs.readFileSync(path)同步读取文件
例子:

const data = fs.readFileSync("./test.txt")
console.log(data.toString())
// testing!

fs.writeFileSync(path, data) 同步写入文件
例子:

try{
  fs.writeFileSync("./test.txt", "testing!!")
}catch(e){
  console.error(e)
}

fs.unlinkSync(path) 同步删除文件
例子:

try{
  fs.unlinkSync("./test.txt")
}catch(e){
  console.error(e)
}

express添加jwt

先说一下jwt,全名叫JSON Web Tokens,是一种开放的,行业标准的RFC 7519方法,用于表示两端之间的应用安全。

RFC是由Internet Society(ISOC)赞助发行的互联网通信协议规范,包含各种各样的协议,同时包含互联网新开发的协议及发展中所有的记录。

jwt这种实现已经成为互联网通讯安全标准,那么在express怎样实现?

首先安装下面两个包:

auth0/node-jsonwebtoken

auth0/express-jwt

npm i -S express-jwt jsonwebtoken

使用:

const { router }  = require("express")
const decode_jwt = require("express-jwt")
const jwt = require("jsonwebtoken")

const secret = "your-secret" //盐

// 登录
router.get("/login", function(req, res, next) {
  /**+[登录逻辑]...**/
  const token = jwt.sign(user, secret)
  res.status(200).send({ user, token })
})

//受限的接口
router.get("/user/star", decode_jwt({secret: secret}), (req, res)=>{
  const { user } = req
  const stars = []
  /**+[获取用户star列表]**/
  res.status(200).send(stars)
})

解释一下,jsonwebtoken包为加密作用, secret作为盐用来混淆内容(出于安全是不能对客户端公开),然后经过express-jwt解密处理http header里带有的authorization: Bearer [token]中的token来获得user信息。这样在/user/star接口中就能获取到用户资料做后续的业务处理了。

基于express实现上传文件

忘了说明这里提及的express版本为4,那么在新版的express 4文档中提及了这么一段关于上传文件的处理说明:

In Express 4, req.files is no longer available on the req object by default. To access uploaded files on the req.files object, use multipart-handling middleware like busboy, multer, formidable, multiparty, connect-multiparty, or pez.

意思是:express 4 版本req.files字段不在有效,需要使用上面提及的中间件提供支持才能实现读取上传来的文件。

看了一番文档,最后选择了multer

下面讲一下如何使用:

安装

npm i -S multer

使用

const multer = require("multer")
const limits = { fieldSize: 1024*1024*3 }
const extname = "html"
//创建本地储存
const storage = multer.diskStorage({
  destination: function (req, file, cb) {
    cb(null, "./uploads");
  },
  //储存文件时自定义文件名称
  filename: function (req, file, cb) {
    cb(null, file.fieldname + "-" + Date.now());
  }
})
//创建上传处理
const uploader = require("multer")({
    storage,
    limits,
    fileFilter(req, file, cb){
      if(path.extname(file.originalname) === `.${extname}`) cb(null, true)
      else cb(new Error(`upload file extname must be ${extname}`))
    }
})
/**
 * 上传接口
 * 只接受http头是`content-type: multipart/form-data`的数据
 * 这里设定获取字段是`file`的内容储存成文件来完成文件上传工作
 **/
router.post("/trans_on_upload", uploader.single("file"), (req, res)=>{
  const { file } = req
  const fileData = fs.readFileSync(file.path)
  console.log(fileData.toString())
  res.status(200)
})

multer接受多种文件上传方式:

uploader.single(fieldname) 接受一个以 fieldname 命名的文件。这个文件的信息保存在 req.file

uploader.array(fieldname[, maxCount]) 接受一个以 fieldname 命名的文件数组。可以配置 maxCount 来限制上传的最大数量。这些文件的信息保存在 req.files。

uploader.fields(fields) 接受指定 fields 的混合文件。这些文件的信息保存在 req.files。fields 应该是一个对象数组,应该具有 name 和可选的 maxCount 属性。
例子:

[
  { name: "avatar", maxCount: 1 },
  { name: "gallery", maxCount: 8 }
]

uploader.none() 只接受文本域。如果任何文件上传到这个模式,将发生 "LIMIT_UNEXPECTED_FILE" 错误。这和 upload.fields([]) 的效果一样。

uploader.any() 接受一切上传的文件。文件数组将保存在 req.files。
警告: 确保你总是处理了用户的文件上传。 永远不要将 multer 作为全局中间件使用,因为恶意用户可以上传文件到一个你没有预料到的路由,应该只在你需要处理上传文件的路由上使用。

multer使用起来有一定限制,并不是所有项目合适使用,所以不做深入说明。

nodejs环境下读取并编辑html文件

这里处理的流程是使用fs.readFileSync(path)读取html文件内容后,希望能以dom方式编辑内容,使用jsdom/jsdom能像在浏览器一样的方式处理DOM,是非常好用的工具。

比如我的需求是获取所有TextNode提取内容进行翻译并替换原来内容,最后导出html内容:

const { JSDOM } = require("jsdom")
const { minify } = require("html-minifier")

//递归获得所有TextNode
const getAllTextNode = (node)=>{
  var all = [];
  for (node=node.firstChild;node;node=node.nextSibling){
    const { parentNode } = node
    if (node.nodeType==3){
      all.push(node)
    }
    else all = all.concat(getAllTextNode(node));
  }
  return all;
}

const html = ""
/**+[获取html内容]**/
const vbrows = new JSDOM(minify(html, {
  collapseWhitespace: true
}))
const { document } = vbrows.window
const textNodes = getAllTextNode(document.body)
textNodes.forEach(textNodes=>{
  const transStr = textNodes.textContent
  /**翻译处理**/
  textNodes.textContent = transStr
})
//翻译结果
console.log("trans result", vbrows.serialize())
总结

完成一个应用涉及的范围其实挺广的,内容如果再深入讨论应该能写更多内容吧。由于手上还有其他工作,只能大致记录关键词和使用的方式,原理方向等有时间再深入研究。

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/43046.html

相关文章

  • 一次bug经历-document.title

    摘要:身为一个前端打字员,一直没有写博客的习惯,但是,今儿是忍不了了,且为自个儿今后提个醒。 身为一个前端打字员,一直没有写博客的习惯,但是,今儿是忍不了了,且为自个儿今后提个醒。 最近用vue全家桶开发了一个网站,眼看一切都顺顺利利的,马上都要领盒饭了,突然发现一个bug,当我点击其他的标签页再点击回来的时候,神奇的事情发生了,网站的title会自动切换到上次所设置的! 瞬间盒饭也不吃了,...

    dockerclub 评论0 收藏0
  • 为人的幸福————一次编写计算程序的经历

    摘要:今天小伙伴们遇到了一个概率问题朝一列米长的列车开一炮,把它分成两段。假设分段点是随机的,问截列车长度都大于米的概率。于是乎写了一个计算程序,结构很简单,循环千万次,很快就得出了正确答案。能用这些小小的程序完成一些繁琐的工作,就感到挺幸福的。 今天小伙伴们遇到了一个概率问题:朝一列100米长的列车开一炮,把它分成两段。再对两段分别开炮,共分成四段。假设分段点是随机的,问4截列车长度都大于...

    MSchumi 评论0 收藏0
  • 为人的幸福————一次编写计算程序的经历

    摘要:今天小伙伴们遇到了一个概率问题朝一列米长的列车开一炮,把它分成两段。假设分段点是随机的,问截列车长度都大于米的概率。于是乎写了一个计算程序,结构很简单,循环千万次,很快就得出了正确答案。能用这些小小的程序完成一些繁琐的工作,就感到挺幸福的。 今天小伙伴们遇到了一个概率问题:朝一列100米长的列车开一炮,把它分成两段。再对两段分别开炮,共分成四段。假设分段点是随机的,问4截列车长度都大于...

    Profeel 评论0 收藏0
  • 一次挂马清除经历:处理一个利用thinkphp5远程代码执行漏洞挖矿的木马

    摘要:再看下的的权限就是的查看下几个站的日志发现是利用最近爆出的远程代码执行漏洞漏洞细节修复一下问题解决但是这个站点是测试站点端口监听的是,难道现在黑客能开始嗅探非常规端口了来源 昨天发现 一台服务器突然慢了 top 显示 几个进程100%以上的cpu使用 执行命令为 : /tmp/php -s /tmp/p2.conf 基本可以确定是被挂马了 下一步确定来源 last 没有登陆记录 先...

    incredible 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<