title: python实战爬虫有道翻译与解决有道翻译反爬虫问题
date: 2020-03-22 20:21:12
description: 最近在学Python,一直没有尝试过实战。于是昨天试了试爬虫初学者的第一战场:有道翻译。与教程中不一样的是现在的有道翻译有了反爬虫机制,最后通过查询百度与借鉴其他人的博客实现~
tags:
不需要打开有道翻译网页就能在本地使用,还是很方便的。所以学习爬虫确实还是一个比较有意思且实用的过程,另一方面,现在的网站或多或少都有反爬机制,这样斗智斗勇的感觉也挺有趣的。
当然反爬机制也让我更明白了Python爬虫还需要再多多学习,毕竟有道的反爬机制对于我这个初学者来说都不太简单那其他更加复杂的网站的反爬机制将会更有挑战性~
可以看到右边出现的为Request Method:POST,且在Data栏中可以看到i:后接的是待翻译内容,再看看Preview中就有翻译过来的内容,可知我们需要找的POST内容就是这个了。接下来就是可以准备写代码了,具体的内容介绍在代码注释中可见:
import urllib.request
import urllib.parse
import json
#引入需要的模块
url= 'http://fanyi.youdao.com/translate_o?smartresult=dict&smartresult=rule'
#需要打开网页的链接,这个在Request URL栏
while True:
content = input("请输入你想要翻译的内容~\n")
head = {}
head['User-Agent'] = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.122 Safari/537.36'
#模拟浏览器访问,简单的防止反爬机制。这个在Request Headers中的User-Agent栏。
data = {}
data['i'] = content
data['from'] = 'AUTO'
data['to'] = 'AUTO'
data['smartresult'] = 'dict'
data['client'] = 'fanyideskweb'
data['salt'] = '15847864360501'
data['sign'] = 'f762faa6901c6cf473fce719f8238ca8'
data['ts'] = '1584786436050'
data['bv'] = '0ed2e07b89acaa1301d499442c9fdf79'
data['doctype'] = 'json'
data['version'] = '2.1'
data['keyfrom'] = 'fanyi.web'
data['action'] = 'FY_BY_REALTlME'
#将Form Data数据存入data字典中。
data = urllib.parse.urlencode(data).encode('utf-8')
#将data以utf-8的形式编码
req = urllib.request.Request(url,data,head)
#以代码中的data与head形式访问代码中的url链接
response = urllib.request.urlopen(req)
#打开url网页并传送data与head
html = response.read().decode('utf-8')
#读取打开的网页并进行utf-8解码
target = json.loads(html)
#识别json
print(html)
#print("翻译的结果是:%s"%(target['translateResult'][0][0]['tgt']))
print("********************************************************")
#输出结果
大家执行完代码后会发现报错:{“errorCode”:50},其实代码是没有问题的,只是有道加入了反爬机制。所以接下来需要做的是如何反反爬机制。
解决方案一:可以在上述的代码中将
url= http://fanyi.youdao.com/translate_o?smartresult=dict&smartresult=rule 中的_o去除,即解除网页反爬虫机制。(其实是解除了salt、sign参数的作用)
解决方案二:依旧需要实地考察有道网站,我们多次尝试翻译。可以发现在Data数据中变化的是salt、sign和ts。可以猜测实现反爬机制的关键就在这三个加密的参数~接下来先介绍这三个参数的作用:
1、salt:加密信息,根据数据的特点可以猜测与时间戳有关
2、sign:签名字符串
3、ts:毫秒时间戳
再稍微介绍一下其他数据的功能:
1、i:待翻译内容
2、from:源语言的语种(这里是AUTO,即可以进行多语言互译不局限于英汉互译)
3、to:翻译后的语种(AUTO同上)
4、smartresult: 固定值
5、client:客户端
6、bv:md5值
7、doctype:文档类型
8、version:版本
9、keyfrom:键来源
10、action:操作动作
11、typoResult:打印错误
开始分析sign、salt和ts具体获取方式。先去网页的源代码中查看,并没有此参数,于是考虑是否在js文件中生成这三个参数。最后在fanyi.min.js文件中找了这三个结果。当然js文件的内容格式比较可怕,建议将其格式化后再用sublimetext进行查找salt参数。接下来可见代码片段:
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,
tgt: e.tgt,
modifiedTgt: e.modifiedTgt,
from: e.from,
to: e.to
},
success: function(e) {},
error: function(e) {}
})
}
从上述js代码中可见salt的获取方式,可知确实为时间戳:
i = r + parseInt(10 * Math.random(), 10)
其中r为ts获取方式:
r = “” + (new Date).getTime()
sign的获取方式为:
sign = n.md5(“fanyideskweb” + e + i + “Nw(nmmbP%A-r6U3EUn]Aj”)
其中前后两个为固定值,只有e与i在改变。e为待翻译内容,i为salt。
弄明白了以上三个参数的来源,接下来可以开始动手写代码。
import random
import time
import requests
import hashlib
import json
def generateSaltSign(e):
navigator_appVersion = "5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.169 Safari/537.36"
t = hashlib.md5(navigator_appVersion.encode("utf-8")).hexdigest()
r = str(int(time.time()*1000))
i = r + str(random.randint(1,10))
return {
"ts": r,
"bv": t,
"salt": i,
"sign": hashlib.md5(str("fanyideskweb" + e + i + "97_3(jkMYg@T[KZQmqjTK").encode("utf-8")).hexdigest()
}
def spider(i):
url = 'http://fanyi.youdao.com/translate_o?smartresult=dict&smartresult=rule'
r = generateSaltSign(i)
data = {
"i": i,
"from": "AUTO",
"to": "AUTO",
"smartresult": "dict",
"client": "fanyideskweb",
"salt": r["salt"],
"sign": r["sign"],
"ts": r["ts"],
"bv": r["bv"],
"doctype": "json",
"version": "2.1",
"keyfrom": "fanyi.web",
"action": "FY_BY_REALTlME",
}
#data = parse.urlencode(data).encode('utf-8')
headers = {
"Cookie": "[email protected];",
"Referer": "http://fanyi.youdao.com/",
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.169 Safari/537.36",
}
response = requests.post(url=url, data=data, headers=headers)
html = response.text
target = json.loads(html)
print("翻译的结果是:%s"%(target['translateResult'][0][0]['tgt']))
print("********************************************************")
#print(html)
if __name__ == '__main__':
while True:
i = input("请输入你想要翻译的内容~\n")
spider(i)
1、第一个函数根据js文件模仿网页生成salt、sign和ts参数。
2、第二个函数是开始准备爬虫的请求函数,这里有两个关键的内容。data与headers。一个是需要发送给网站信息,一个是请求头文件。模拟浏览器正常访问。
最后展示一个成功运行结果图。
最近在开始学习Python,所以这一周没有打理博客了。现在慢慢准备上手一些爬虫的实例。如果好玩的话会继续分享,也算是见证自己的成长~
谢谢大家观看,因为是Python初学者所以或多或少会有错误,如果博客中有表达问题还请在评论中指正!