前言
我去年7月刚通过日语N2。今年打算考N1。为了加深对日本文化的了解和学习日语,我经常去日本网站。
但毕竟等级有限,难免会遇到生词。日语单词的特点之一是你知道很多单词的意思,但你不知道如何发音。
例如:“简单な构造”中的第一个词:“简单”,明明是“简单、朴素的意思”,但你肯定不知道它的读音是:“[かんそ]①”。
以前遇到这样的词,我会在沪江小D的网页上查,但是这个很麻烦,你要跳转到其他网站,更何况每次弹出的广告沪江入。 .
所以,我就是想找一个可以做单词翻译的插件,可以详细标注读音和获取方法,这样简单易学。
开始折腾
因为之前写过一些过滤广告和辅助网页排序的扩展,作为一个爱折腾的开发者。当然是自给自足。
百度翻译接口
首先想到的是直接使用翻译API进行翻译,然后在当前页面添加提示框显示翻译结果。
首先是百度翻译API:官方文档很简单,只需要注册一个appid,然后发起HTTP请求即可。百度翻译API每月有200W字免费资源,随便用就行。
注册开发者账号,申请appid,然后根据其文档模拟请求。因为签名方法很简单,而且官方给出了demo,所以很容易得到返回数据。
但是返回的数据格式有点不对。
{
"from": "jp",
"to": "zh",
"trans_result": [
{
"src": "合格",
"dst": "合格"
}
]
}
。 . 这个翻译很直接,只有翻译结果,没有发音,很绝望,PASS。
没有办法,只能使用其他平台的API,另外一种就是有道云的翻译API。和百度API一样,注册一个账号,创建一个应用。刚准备用的时候发现有道云的翻译API是收费的,不过不用担心,只要注册就可以获得100元,足够你翻译几千万字了。
有道翻译API
有道云翻译API文档:我发现了一件有趣的事情。百度翻译API和有道云翻译API的调用方式几乎相同。在两个平台给出的demo中,使用什么数据签名方式和数据请求方式,几乎都是一样的。唯一需要注意的是,百度请求的应用识别参数是:appid,也就是:,小心。
很快,百度翻译API得到的返回结果如下。
{
"tSpeakUrl": "http://openapi.youdao.com/ttsapi?q=%E5%90%88%E6%A0%BC&langType=zh-CHS&sign=3118EBCD5EC1D0A416EF32032FE55FAF&salt=1521012839301&voice=4&format=wav&appKey=3a72ad95fe43ac83",
"query": "合格",
"translation": [
"合格"
],
"errorCode": "0",
"dict": {
"url": "yddict://m.youdao.com/dict?le=jap&q=%E5%90%88%E6%A0%BC"
},
"webdict": {
"url": "http://m.youdao.com/dict?le=jap&q=%E5%90%88%E6%A0%BC"
},
"l": "ja2zh-CHS",
"speakUrl": "http://openapi.youdao.com/ttsapi?q=%E5%90%88%E6%A0%BC&langType=ja&sign=3118EBCD5EC1D0A416EF32032FE55FAF&salt=1521012839301&voice=4&format=wav&appKey=3a72ad95fe43ac83"
}
相对于百度,有道云增加了单词的读音地址,但依然没有标注片假名。
另外还有翻译API没有测试日语翻译器,不过这次得换个思路,去扩展商店看看有没有类似的插件。
应用商店
先在扩展应用商店搜索“词翻译”,有一些评价很高的插件。
我已经安装了几个插件,这些插件真的很不错。他们有我需要的所有功能,比如中转英,中转日,还有一些发音。
但是,这些插件都没有标记我正在寻找的单词的片假名发音,这是不可接受的。
对于习惯用沪江小D查词的我来说,作为学习要求,查词应该有各种读音、各种定义、各种词性和用法、例句。
我搜索了很多插件,但没有找到。就在我快要放弃的时候,我试图搜索“沪江”。
其实还有个沪江小D插件,虽然只有一条评论,但还是中规中矩的评论。我还是下载安装了,但是报了各种疯狂的错误,无法使用。
绕道:奋斗
事情终于回到了起点。我习惯用沪江小D的翻译结果,能在沪江小D的翻译中找到答案吗?
沪江小D解析
沪江小D翻译页面:简单
我最初的想法:打开一个调试窗口并观察它查询 Ajax 请求的单词,模拟查询。但是沪江小D并没有使用Ajax异步查询结果,(失望,看不到界面)。
很容易发现,沪江小D的找词就是请求一个页面,然后在一个页面后面拼接词类似:所以我想在插件中构造这个url,然后用ajax请求获取html数据并解析它的 HTML 数据。但是这个页面禁止跨域请求,也就是说服务器设置为禁止跨域请求,不通过。但是我又把这个页面放在了一个里面
Refused to display 'https://dict.hjenglish.com/jp/jc/%E7%B0%A1%E7%B4%A0' in a frame because it set 'X-Frame-Options' to 'sameorigin'.
禁止访问此页面。崩溃!
这时候突然想到沪江小D有手机APP,肯定会请求服务端API!于是我立即使用抓包,激动的输入了这个词,点击查询按钮,中间出现了一个查询请求。它是压缩的。解压后是json格式的返回值。数据中有很多乱七八糟的鬼。哈哈,加密了。
不得不佩服沪江的所作所为!
使用服务器转发
但是,我不会放弃。这不是跨域问题。不管你怎么禁止跨域,浏览器都可以访问!正确的!模拟请求后,不需要其他信息。我在服务器上编写了一个转发器,它请求页面数据并将其返回给插件客户端。由于我的服务器主要是 PHP 环境,所以我使用 PHP 编写的转发器。主要代码如下:
// 允许跨域>_ 'https://dict.hjenglish.com/jp/jc/', // from Japanese to Chinese
'Chinese_Japanese' => 'https://dict.hjenglish.com/jp/cj/', // from Chinese to Japanese
'Chinese_English' => 'https://dict.hjenglish.com/w/', // from Chinese to English
'English_Chinese' => 'https://dict.hjenglish.com/w/', // from English to Chinese
];
// 根据查询语言转换url
protected function buildUrl($query, $from, $to)
{
$url = $this->base_api[$from . '_' . $to];
$url = $url . rawurlencode($query);
return $url;
}
public function translate($query, $from, $to)
{
$url = $this->buildUrl($query, $from, $to);
$response = $this->curlCall($url, '', 'GET');
return $response;
}
// curl模拟发送http请求
public function curlCall($url, $params = null, $method="post", $withCookie = false, $timeout = CURL_TIMEOUT, $headers=array())
{
$ch = curl_init();
$data = '';
$params && $data = http_build_query($params);
if($method == "post" || $method == "POST")
{
curl_setopt($ch, CURLOPT_POSTFIELDS, $data);
curl_setopt($ch, CURLOPT_POST, 1);
}
else
{
if ($data) {
stripos($url, "?") > 0 ? $url .= "&$data" : $url .= "?$data";
}
}
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_TIMEOUT, $timeout);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
// UserAgent 模拟
$useragent = 'Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.100 Safari/537.36';
curl_setopt($ch, CURLOPT_USERAGENT, $useragent);
// 绕过SSL认证
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 0);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 0);
// 设置请求头部
$headers && curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
// 设置cookie
$withCookie && curl_setopt($ch, CURLOPT_COOKIEJAR, $_COOKIE);
$response = curl_exec($ch);
if (false === $response) {
die(curl_error($ch));
}
curl_close($ch);
return $response;
}
}
$translator = new HujianTranslate();
echo $translator->translate($_GET['query'], $_GET['from'], $_GET['to']);
exit();
页面修改
终于可以成功获取到页面数据了,但是这时候遇到了一个选择,去哪里解析
起初,我想在服务器端解析它。 PHP 自己的解析器用于 XML。用于解析HTML时,会出现很多告警。虽然可以正常运行,但是很不舒服,不想重复使用。再写一遍,服务器资源有限。后来解析的任务就交给了客户端。毕竟解析HTML很方便!
以下是查询url上的HTML内容解析函数:
function parseHTML(data) {
var parser = new DOMParser(),
doc = parser.parseFromString(data, 'text/html'),
details = [], items,
word_details = doc.getElementsByClassName('word-details-pane');
// 遍历每种解释含义
for (var i = 0; i
detail.pronounce = {};
items = pronounces.getElementsByTagName('span');
detail.pronounce.kana = items[0].innerHTML;
detail.pronounce.roma = items[1].innerHTML;
detail.pronounce.accent = items[2].innerHTML;
detail.pronounce.audio = items[3].getAttribute('data-src');
// simple 词意解析
detail.meaning = {};
detail.meaning.pos = []; // 词性
detail.meaning.means = []; // 词义
var poses = simple.getElementsByTagName('h2');
for (var j = 0; j
解析功能到位后,我就麻烦了。怎么能显示这么多数据?回到沪江小D的查询展示页面,最后的展示效果和这个差不多!
所以最后还是放弃了使用解析功能,而是直接截取页面中的翻译结果节点,然后重新设置样式。
function parseResponse(data) {
var parser = new DOMParser(),
doc = parser.parseFromString(data, 'text/html'),
content = doc.getElementsByClassName('word-details')[0];
// content 为主要内容区域
document.body.appendChild(content);
}
重新编辑内容包括:
放音频播放器代码:
// 音频播放器
function AudioPlayer() {
var audio = document.createElement('audio');
audio.setAttribute('controls', 'controls');
audio.style.display = 'none';
// audio.setAttribute('src', src);
document.body.appendChild(audio);
this.play = function(src) {
audio.setAttribute('src', src);
audio.play();
return this;
};
this.stop = function() {
audio.pause();
return this;
};
// 播放结束回调
this.end = function(callback) {
var repeat = setInterval(function() {
if (audio.ended) {
clearInterval(repeat);
callback && callback();
}
}, 100);
setTimeout(function() {
clearInterval(repeat);
}, 5000);
};
return this;
}
终于如愿以偿,成功将沪江翻译的内容转换成一个小窗口。下一步是将内容封装到插件中。最终结果如下:
可以下拉显示例句,点击小喇叭发音,点击开始词条切换不同发音。
点此对比沪江小D页面
最后:放弃
封装成插件后,只能自己使用了。毕竟版权是沪江的,我可以联系沪江官方获得授权吗?
于是联系了沪江的客服,了解了一些情况
另外,我还发现了一件很恶心的事情。在沪江翻译的页面上,有一个自带的单词翻译,而且效果很好,并且标注了发音。效果图如下,双击单词会在单词下方显示翻译按钮,双击翻译会在一个小窗口中显示读音和释义。这个过程是ajax请求,但是需要appid和。
所以,我所做的工作一点用都没有。
于是我泪流满面。 . 久久不能说话。
如果我相信沪江小D可以使用自己的API日语翻译器,开发的插件肯定和这个小D的定义差不多,可以看笔名。
收割失败
原创个人博客:我不想说