python 爬取有道翻译,踩坑之旅

通过python 来抓取有道翻译的内容

第一步:

先打开有道翻译的网页:http://fanyi.youdao.com/

第二步:

通过按F12,进入调试模式,找到Network→XHR,就可以找到请求翻译的接口,如下图:

image.png

第三步:

点开Name底下的链接,如果Name底下为空的话,证明你没有请求翻译,在网页上请求一下翻译就出来了,点开就可以看见请求的链接,请求方式,请求头,以及请求的参数,如下图:

image.png
image.png

如上,这些信息都是我们python请求需要用到的,有了这些信息,就可以编写我们的python代码了。

第四步:

编写相应的python代码。

首先,可以看到请求方式是post请求,那么我们就先写post请求方法:

import requests
def post(url,header=None,data=None):
    if header is None:
        header = {
            "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/81.0.4044.138 Safari/537.36"
        }
    result = requests.post(url,header,data)
    return result.text

然后,通过我们得到的请求的url,请求的参数,请求的头部,就可以编写我们的请求的方法:

def getTranslate(data):
    salt = get_salt()
    jsonStr = post(
        url='<http://fanyi.youdao.com/translate_o?smartresult=dict&smartresult=rule>',
        headers = {
        'Cookie': 'OUTFOX_SEARCH_USER_ID=1389460813@123.125.1.12',
        'Referer': '<http://fanyi.youdao.com/>',
        'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OSX10_14_2) AppleWebKit/537.36(KHTML, like Gecko) Chrome/75.0.3770.100 Safari/537.36'
    },data=json.dumps({
        'i':data,
            'from':'zh-CHS',
            'to':'en',
            'smartresult':'dict',
            'client':'fanyideskweb',
            'salt':'15901129623685',
            'sign':'7ebd4fe242ddf38339c8cc2ef09875bb',
            'ts':'1590110946423',
            'bv':'8abdac95d8a218e4fd5735f7cd2ab169',
            'doctype':'json',
            'version':'2.1',
            'keyfrom':'fanyi.web',
            'action':'FY_BY_REALTlME'

    },ensure_ascii=False))
    print(jsonStr)

调用方法后,会看到返回的是{"errorCode":50}

证明我们请求的接口没有成功,参数和请求头都没问题,那么我们翻翻反爬虫手册:https://www.jianshu.com/p/ea6f47ad2042

从而判断出,是有道翻译接口通过加密方式阻止了访问,导致访问失败。分析Form Data,发现salt,sign,ts这三个参数是动态变化的,那问题就出在这三个参数身上,通过请求网页发现,每次都调用了fanyi.min.js这个js,很有可能就是通过js加密方式。我们找到这个js,吧里面的内容复制出来,通过js解析网站:https://tool.oschina.net/codeformat/js

找到了js的关键代码:

function(e, t) {
var n = e("./jquery-1.7");
e("./utils");
e("./md5");
var r = function(e) {
var t = n.md5(navigator.appVersion),
r = "" + (new Date).getTime(),
i = r + parseInt(10 * Math.random(), 10);
return {
ts: r,
bv: t,
salt: i,
sign: n.md5("fanyideskweb" + e + i + "Nw(nmmbP%A-r6U3EUn]Aj")
}
};
t.recordUpdate = function(e) {
var t = e.i,
i = r(t);
n.ajax({
type: "POST",
contentType: "application/x-www-form-urlencoded; charset=UTF-8",
url: "/bettertranslation",
data: {
i: e.i,
client: "fanyideskweb",
salt: i.salt,
sign: i.sign,
ts: i.ts,
bv: [i.bv](<http://i.bv/>),
tgt: e.tgt,
modifiedTgt: e.modifiedTgt,
from: e.from,
to: [e.to](<http://e.to/>)
},
success: function(e) {},
error: function(e) {}
})
}

可以看出关键代码:

r = "" + (new Date).getTime(),
i = r + parseInt(10 * Math.random(), 10);
ts: r,
salt: i,
sign: n.md5("fanyideskweb" + e + i + "Nw(nmmbP%A-r6U3EUn]Aj")

那我们通过编写python相关方法去替换着三个值就行了,方法如下:

def get_salt():
    import time, random
    salt = int(time.time() * 1000) + random.randint(0, 10)
    return salt

def get_md5(v):
    import hashlib
    md5 = hashlib.md5()  # md5对象,md5不能反解,但是加密是固定的,就是关系是一一对应,所以有缺陷,可以被对撞出来
    md5.update(v.encode('utf-8'))  # 要对哪个字符串进行加密,就放这里
    value = md5.hexdigest()  # 拿到加密字符串
    return value

def get_sign(key, salt):
    sign = 'fanyideskweb' + key + str(salt) + 'n%A-rKaT5fb[Gy?;N5@Tj'
    sign = get_md5(sign)
    return sign

def get_ts(self):
    # 根据当前时间戳获取ts参数
    s = int(time.time() * 1000)
    return str(s)

然后就可以编写完整的程序了:

import requests
import json
import hashlib
import random
import time

def get(url,header=None,data=None):
    if header is None:
        header = {
            "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/81.0.4044.138 Safari/537.36"
        }
    result = requests.get(url,header,data)
    return result.text

def post(url,header=None,data=None):
    if header is None:
        header = {
            "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/81.0.4044.138 Safari/537.36"
        }
    result = requests.post(url,header,data)
    return result.text

def get_salt():
    import time, random
    salt = int(time.time() * 1000) + random.randint(0, 10)
    return salt

def get_md5(v):
    import hashlib
    md5 = hashlib.md5()  # md5对象,md5不能反解,但是加密是固定的,就是关系是一一对应,所以有缺陷,可以被对撞出来
    md5.update(v.encode('utf-8'))  # 要对哪个字符串进行加密,就放这里
    value = md5.hexdigest()  # 拿到加密字符串
    return value

def get_sign(key, salt):
    sign = 'fanyideskweb' + key + str(salt) + 'n%A-rKaT5fb[Gy?;N5@Tj'
    sign = get_md5(sign)
    return sign

def get_ts(self):
    # 根据当前时间戳获取ts参数
    s = int(time.time() * 1000)
    return str(s)

from urllib import request,parse

def youdao(key):
    # 请求地址
    url = '<http://fanyi.youdao.com/translate_o?smartresult=dict&smartresult=rule>'

    salt = get_salt()

    # 请求体
    data = {
        "i": key,
        "from": "AUTO",
        "to": "AUTO",
        "smartresult": "dict",
        "client": "fanyideskweb",
        "salt": str(salt),  ### 很长的随机串,防止用字典反推
        "sign": get_sign(key, salt),  ## 签名:js加密
        "doctype": "json",
        "version": "2.1",
        "keyfrom": "fanyi.web",
        "action": "FY_BY_REALTIME",
        "typoResult": "false"
    }
    # 数据编码
    data = parse.urlencode(data).encode()
    headers = {
        'Cookie': 'OUTFOX_SEARCH_USER_ID=1389460813@123.125.1.12',
        'Referer': '<http://fanyi.youdao.com/>',
        'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OSX10_14_2) AppleWebKit/537.36(KHTML, like Gecko) Chrome/75.0.3770.100 Safari/537.36'
    }
    req = request.Request(url=url, data=data, headers=headers)
    rsp = request.urlopen(req)
    html = rsp.read().decode()
    print(html)

if __name__ == '__main__':
    youdao('你好')

运行结果如下图:

image.png
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 214,377评论 6 496
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,390评论 3 389
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 159,967评论 0 349
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,344评论 1 288
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,441评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,492评论 1 292
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,497评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,274评论 0 269
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,732评论 1 307
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,008评论 2 328
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,184评论 1 342
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,837评论 4 337
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,520评论 3 322
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,156评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,407评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,056评论 2 365
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,074评论 2 352