有道翻译-爬虫练习
案例分析
1.抓取url请求接口
如图:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-OMdUQcX2-1638268219047)(https://www.ensio.top/img/01.png “抓取url请求接口”)]
顺便输入请求内容,向服务端发送请求后,F12查看url请求接口,预览了一下发现只有:
translate_o?smartresult=dict&smartresult=rule
响应有内容。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-9lrzJ79B-1638268219065)(https://www.ensio.top/img/02.png “响应内容”)]
看一下headers信息为:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-PufRBrRi-1638268219068)(https://www.ensio.top/img/03.png “headers信息”)]
2.观察请求头与请求表单数据的规律
为了以防万一,我特意多试了几个参数
发现了以下为重点
常规:
请求 URL: http://fanyi.youdao.com/translate_o?smartresult=dict&smartresult=rule #urls
请求方法: POST #使用的post请求
状态代码: 200 OK #状态码200 表示OK
远程地址: 220.181.76.84:80 #远程地址
响应头:
略 #一些请求时的状态,服务器系统等等信息,用不上
请求头:
Content-Length: 241 #请求参数的长度 除了这个下面基本不动
Host: fanyi.youdao.com #远程主机
Origin: http://fanyi.youdao.com
Referer: http://fanyi.youdao.com/
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/81.0. 4044.92 Safari/537.36 Edg/81.0.416.50 #游览器一些标识 我的是edg,微软
X-Requested-With: XMLHttpRequest #xml的请求
表单数据:#传递的参数字典内容
i: hello
from: AUTO
to: AUTO
smartresult: dict
client: fanyideskweb
salt: 15866130639860
sign: 5eaba662ba667122522d389452dcb2ae
ts: 1586613063986
bv: 2083a8ac12524fb8e1481a1cf8589e63
doctype: json
version: 2.1
keyfrom: fanyi.web
action: FY_BY_REALTlME
整理一下,其实就下面信息有用
多试了几回发现只有下面这些参数发生了改变:
分析一下
- Content-Length: 241
- 这个应该是请求参数的大小
- i: hello
- 发送的参数
- salt: 15866130639860
- 盐,也就是时间戳
- sign: 5eaba662ba667122522d389452dcb2ae
- 这个,嗯…不太清楚,但是想了一下,看这个有可能是js加密,毕竟是post请求
- 于是F12查了一下js文件
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-fzvqwkyh-1638268219071)(https://www.ensio.top/img/04.png "js文件 ")] - Ctrl+F 经过一个个找了之后发现了这个应该就是我想要的:
define("newweb/common/service", ["./utils", "./md5", "./jquery-1.7"],
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 + "@6f#X3=cCuncYssPsuRUE")
}
};
- sign: n.md5("fanyideskweb" + e + i + "Nw(nmmbP%A-r6U3EUn]Aj")
- 看样子,sign的值应该就是"fanyideskweb" + e + i + "Nw(nmmbP%A-r6U3EUn]Aj"经过md5加密后的值
- "fanyideskweb"与"Nw(nmmbP%A-r6U3EUn]Aj"应该就是个字符串,但是e与i不知道是什么
- 在文件中找了一下,嗯.原来就是sign的上面三行
- var t = n.md5(navigator.appVersion)
- r = "" + (new Date).getTime()
- i = r + parseInt(10 * Math.random(), 10);
- 分析了一下:第一行没用,r应该是时间戳,后面加的应该是0-9随机数
请求 URL: http://fanyi.youdao.com/translate_o?smartresult=dict&smartresult=rule #urls
Content-Length: 241 #请求参数的长度 除了这个下面基本不动
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/81.0. 4044.92 Safari/537.36 Edg/81.0.416.50 #游览器一些标识 我的是edg,微软
i: hello
salt: 15866130639860
sign: 5eaba662ba667122522d389452dcb2ae
3.整理可用信息
- URL: http://fanyi.youdao.com/translate_o?smartresult=dict&smartresult=rule
- url
- Content-Length: 241
- 长度应该是表单内容的长度
- User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/81.0. 4044.92 Safari/537.36 Edg/81.0.416.50 #游览器一些标识 我的是edg,微软
- 防止被反爬虫,加个伪装身份
- i: hello
- 参数
- salt: 15866130639860
- 时间戳
import time
import random
# 15866130639860
"""
salts = time.time()
print(salts)
"""
# 15866130639860
# 1586616469.5321376
# 原本分析的是时间戳,后来发现和时间戳有点差别
# 想了一下比时间戳多了四位,可能是时间戳 * 10000后取整
"""
salts = int(time.time() *10000)
print(salts)
"""
# 15866130639860
# 15866166617283
# 咳咳咳,后来发现怎么都不对,突然想到计算sign时间,用到一个
# i = r + parseInt(10 * Math.random(), 10);
# 所以可能是时间戳*1000后取整 ,在加上一位0-9随机数
salts = int(time.time() *10000) + random.randint(0,10)
print(salts)
# 15866130639860
# 15866168373469
# 应该是对的,先用着
- sign: 5eaba662ba667122522d389452dcb2ae
- md5加密后的数据
- sign: n.md5(“fanyideskweb” + e + i + “Nw(nmmbP%A-r6U3EUn]Aj”)
- r = “” + (new Date).getTime()
- i = r + parseInt(10 * Math.random(), 10);
- md5加密后的数据
# 看了hashlib库里面正好有个例子
For example, to obtain the digest of the byte string 'Nobody inspects the
spammish repetition':
>>> import hashlib
>>> m = hashlib.md5()
>>> m.update(b"Nobody inspects")
>>> m.update(b" the spammish repetition")
>>> m.digest()
b'\\xbbd\\x9c\\x83\\xdd\\x1e\\xa5\\xc9\\xd9\\xde\\xc9\\xa1\\x8d\\xf0\\xff\\xe9'
More condensed:
>>> hashlib.sha224(b"Nobody inspects the spammish repetition").hexdigest()
'a4337bc45a8fc544c03f52dc550cd6e1e87021bc896588bd79e901e2'
代码
"""
- URL: http://fanyi.youdao.com/translate_o?smartresult=dict&smartresult=rule
- url
- 由于有反爬,一直显示{"errorCode":50},网上有人提示去掉参数_o,爬虫成功
- URL: http://fanyi.youdao.com/translate?smartresult=dict&smartresult=rule
- Content-Length: 241
- 长度应该是表单内容的长度
- User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/81.0. 4044.92 Safari/537.36 Edg/81.0.416.50 #游览器一些标识 我的是edg,微软
- 防止被反爬虫,加个伪装身份
- i: hello
- 参数
- salt: 15866130639860
- 时间戳
- sign: 5eaba662ba667122522d389452dcb2ae
- md5加密后的数据
- sign: n.md5("fanyideskweb" + e + i + "Nw(nmmbP%A-r6U3EUn]Aj")
- r = "" + (new Date).getTime()
- i = r + parseInt(10 * Math.random(), 10);
"""
from urllib import request,parse #
import random
import time
import json
import hashlib
def salt():
salts = int(time.time() * 1000) + random.randint(0, 10)
return salts
def sign(value):
md5 = hashlib.md5()
md5.update(bytes(value,encoding='utf-8'))
sign = md5.hexdigest()
return sign
def yd_spider(data):
url = 'http://fanyi.youdao.com/translate?smartresult=dict&smartresult=rule'
signs = "fanyideskweb" + str(data) + str(salt()) + "sr_3(QOHT)L2dx#uuGR@r" #未经md5加密的
datas = { #不管三七二十一,全部装入
'i': data, #要翻译的内容
'from': 'AUTO',
'to': 'AUTO',
'smartresult': 'dict',
'client': 'fanyideskweb',
'salt': str(salt()), #时间戳,写个函数装一下
'sign': sign(signs), #用hashleib写个函数装一下
'ts': '1586613063986',
'bv': '2083a8ac12524fb8e1481a1cf8589e63',
'doctype': 'json',
'version': '2.1',
'keyfrom': 'fanyi.web',
'action': 'FY_BY_REALTlME'
}
data = parse.urlencode(datas) #用parse将datas表单数据格式化一下
headers = { #为了防止出现各种异常,都装入吧,删除一些不必要的,但是要注意参数长度会变化
'content-length': len(data),
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/81.0.4044.92 Safari/537.36 Edg/81.0.416.50'
}
rsq = request.Request(url, data=bytes(data, encoding='utf-8'), headers=headers)
res = request.urlopen(rsq)
html = res.read().decode()
translate_results = json.loads(html)
# 找到翻译结果
if 'translateResult' in translate_results:
translate_results = translate_results['translateResult'][0][0]['tgt']#取到json数据中的"tgt"的value就是我们想要的
print("\n翻译的结果是:%s" % translate_results)
else:
print(translate_results)
if __name__ == "__main__":
word = input("输入翻译的内容:")
yd_spider(word)
成功
如图:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Snc5qDyd-1638268219078)(https://www.ensio.top/img/07.png “成功”)]
总结
虽然只是最简单的词典爬取,但是还是遇到了很多困难,一一列出,反省一下:
- url请求地址没有找到关键参数,导致一直返回{“errorCode”:50},百度了一下才知道反爬了
- [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-wXsvUUIq-1638268219082)(https://www.ensio.top/img/05.png "{errorCode:50} ")]
- post请求处理不当
- 在找参数表单时候,没有意识到时间戳异样,以致于直接使用时间戳,没有经过处理
- 再遇到js加密的时候,懵逼了许久,才意识到自己要干嘛
- 在找到md5加密的时候,第一印象是:啊,md5呀,再见
- 处理md5加密时候,没有看hashlib库,后来才发现人家底下就有示例…
- data没有使用bytes类型
- json数据提取不熟练,还得借助转换器
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-fEOdYI8k-1638268219087)(https://www.ensio.top/img/08.png “json转换”)]
影修
我是影修,一只蹉跎年华的路人甲~