编程工具:C++ QT
浏览器+分析工具:Firefox
打开有道翻译首页,任意输入一句中文,按F12进入DEBUG模式,点击翻译按钮后按以下截图步骤操作

?得到提交的表单数据

再重复点击几次翻译按钮,可以发现表单数据的salt、sign、lts这几个参数是变化的
点击”调试器“按钮,来到调试页面,按CTRL+SHIFT+F,输入”sign“进行搜索
?
?发现一个sign 的md5值,如果不知道是哪个,可以一个个点击进去查看,必要的时候下断点,再点击翻译试试看是否会被断下,可以断下的话就很大可能是要找的sign值了。

?以下是截取的部分JS代码:
var r = function (e) {
var t = n.md5(navigator.appVersion), //获取浏览器版本,转换为MD5
r = '' + (new Date).getTime(), //获取当前时间
i = r + parseInt(10 * Math.random(), 10); //当前时间尾部加上随机数
return {
ts: r, //当前时间
bv: t, //版本信息MD5值
salt: i, //加上随机数后的时间
sign: n.md5('fanyideskweb' + e + i + 'Y2FYu%TNSbMCxc3t2u^XT') //sign值
}
};
用C++ QT代码实现,其中原网址应为 “https://fanyi.youdao.com/translate_o?smartresult=dict&smartresult=rule” ,需去掉” translate_o “后面的”_o“,否则会出错,具体代码如下:
void Test::YouDaoFanYi()
{
myurl = "https://fanyi.youdao.com/translate?smartresult=dict&smartresult=rule";
QDateTime time = QDateTime::currentDateTime(); //获取当前时间
qint64 t= time.toMSecsSinceEpoch();
string lts= QString::number(t).toStdString();
qsrand(t); //置随机种子
string salt = lts + QString::number(qrand() % 10).toStdString(); //当前时间+随机数
QString s,str;
str = "根据调查,超过90%的同学表示在假期中自身存在拖延";
s.clear();
s.append("fanyideskweb").append(str).append(QString::fromStdString(salt)).append("Y2FYu%TNSbMCxc3t2u^XT");
//计算sign 的 MD5值
MD5 md5 = MD5(s.toStdString());
string youdao_sign = md5.outstr(32).c_str();
//string youdao_sign = md5Str.toStdString();
//qDebug() << md5Str;
//qDebug() << QString::fromStdString(youdao_sign);
data.clear();
data.append("i=");
data.append(MyURLencode(str));
data.append("&from=");
data.append("AUTO");
data.append("&to=");
data.append("AUTO");
data.append("&smartresult=dict&client=fanyideskweb&salt=");
data.append(salt);
data.append("&sign=");
data.append(youdao_sign);
data.append("<s=");
data.append(lts);
data.append("&bv=e2a78ed30c66e16a857c5b6486a1d326&doctype=json&version=2.1&keyfrom=fanyi.web&action=FY_BY_CLICKBUTTION");
}
需加入 “Content_Type” 、 “Cookie” 、 “User_Agent” 这几个请求头信息。
void YoudaoTranslation::on_pushButton_2_clicked()
{
Test test;
test.YouDaoFanYi();
QNetworkRequest request;
request.setUrl(QUrl(QString::fromStdString(test.myurl)));
request.setRawHeader("Content_Type", "application/x-www-form-urlencoded; charset=UTF-8");
request.setRawHeader("Cookie", "YOUDAO_MOBILE_ACCESS_TYPE=1; OUTFOX_SEARCH_USER_ID=-435057197@10.169.0.102; OUTFOX_SEARCH_USER_ID_NCOO=825663831.7448548; fanyi-ad-id=113723; fanyi-ad-closed=1; YOUDAO_FANYI_SELECTOR=ON; JSESSIONID=aaaIQOEW249b2frXGYgSx; ___rl__test__cookies=1627909716667; SESSION_FROM_COOKIE=fanyiweb");
request.setRawHeader("Sec-Fetch-Mode","cors");
request.setRawHeader("User_Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:90.0) Gecko/20100101 Firefox/90.0");
//2. 创建一个管理器
QNetworkAccessManager* manager = new QNetworkAccessManager(this);
//3. 连接请求结束信号
QEventLoop* loop = new QEventLoop;
QTimer timer;
connect(manager, SIGNAL(finished(QNetworkReply*)), this, SLOT(youdaoreply(QNetworkReply*)));
connect(manager, SIGNAL(finished(QNetworkReply*)), loop, SLOT(quit()));
connect(&timer, SIGNAL(timeout()), loop, SLOT(quit()));
//4. 发送post请求
manager->post(request, QString::fromStdString(test.data).toLatin1());
timer.start(5000);
loop->exec();
if (timer.isActive())
{
timer.stop();
//qDebug() << "连接成功!";
}
else
{
QMessageBox::warning(NULL, QObject::tr("错误"), QObject::tr("网络链接超时!"));
//qDebug() << "网络链接超时!";
}
delete loop;
delete manager;
ui.textdisplay->setText(return_str);
}
以下槽函数,处理返回的数据
void YoudaoTranslation::youdaoreply(QNetworkReply* reply)
{
if (reply->error() == QNetworkReply::NoError) { //判断是否请求成功
QString all = reply->readAll(); //读出返回数据
//qDebug() << all;
QString res = youdaoregex(all); //解析出翻译结果
return_str = res;
//qDebug() << return_str;
reply->deleteLater();
}
else {
//qDebug() << reply->errorString() << " error " << reply->error();
QMessageBox::warning(NULL, QObject::tr("错误"), reply->errorString() + "\r\n" + "error code: " + QString::number(reply->error()));
}
}
正则解析函数,获取需要的内容:
QString YoudaoTranslation::youdaoregex(const QString& qstr) { //正则解析函数
string ans;
string str = qstr.toStdString();
string pattern = "\"tgt\":\"(.+?)\"\\}";
regex e("\\[\\[(.*)\\]\\]");
regex r(pattern);
smatch m;
regex_search(str, m, e);
string temp = m[1];
auto res = vector<string>(9);
sregex_iterator pos(temp.cbegin(), temp.cend(), r), end;
for (; pos != end; ++pos) {
res.push_back(pos->str(1));
}
for (int i = 9; i < res.size(); i++)
{
ans = ans + res[i] ;
}
return QString::fromStdString(ans);
}
经验证,对比官方网页翻译结果会有差异,官方网页翻译结果更准确,可能是由于网址 “https://fanyi.youdao.com/translate_o?smartresult=dict&smartresult=rule” ,去掉”_o“后,缺失了相关功能。
以及可以发现 表单数据中的salt和sign值即使为0也可以获得翻译结果,只是翻译结果不是很理想。
这些差异原因有待后续分析。
|