python爬虫有道翻译:post响应相关问题
本帖最后由 非凡 于 2021-10-6 16:25 编辑我在C语言中文网读到一篇文章,讲爬虫有道翻译
http://c.biancheng.net/python_spider/case05.html
我截取以下一段内容:
通过控制台抓包,我们得知了 POST 请求的参数以及相应的参数值,如下所示:
并发现以下了规律:salt、sign、lts 总是变化的,而 bv 等其他参数是不变化的。其中 lts 代表毫秒时间戳,salt 和 lts 之间存在着某种关联,因为两者只有最后一个数字是不同的;而 sign 对应的值是一个加密后的字符串。
如果想要实现实时地抓取翻译结果,就需要将 salt 和 sign 转换为 用 Python 代码表示的固定形式。最后将所有参数放入到 requests.post() 中,如下所示:
response = requests.post(url,data=data,headers=headers)
其中 data 是字典格式参数,它用来构建 POST 请求方法的参数和参数值。
接下来一段是如何寻找页面上的JS代码salat与sign,与我需要解决问题无多大关系,就不复制过来了,感兴趣可以访问原链接。
通过上述方法就找到了 salt 与 sign(两个参数项是在一起的)JS 代码,如下所示:
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 + "Tbh5E8=q6U3EXe+&L[4c@")
}
};
通过上述 JS 代码的简单分析可知: r 变量等同于 lts,salt 变量等同于 i,而 sign 是一个经过 md5 加密的字符串。接下来使用 Python 代码来表示上述参数,如下所示:
#lts毫秒时间戳
str(int(time.time()*1000))
#salt, lts+从0-9的随机数
lts+str(random.randint(0,9))
#sign加密字符串
from hashlib import md5
#word为要翻译的单词等同于js代码中的"e"
string = "fanyideskweb" + word + salt + "Tbh5E8=q6U3EXe+&L[4c@"
s = md5()
#md5的加密串必须为字节码
s.update(string.encode())
#16进制加密
sign = s.hexdigest()
文章中的完整程序实现代码是:
#coding:utf8
import random
import time
from hashlib import md5
import requests
class YoudaoSpider(object):
def __init__(self):
# url一定要写抓包时抓到的POST请求的提交地址,但是还需要去掉 url中的“_o”,
# “_o”这是一种url反爬策略,做了页面跳转,若直接访问会返回{"errorCode":50}
self.url='http://fanyi.youdao.com/translate?smartresult=dict&smartresult=rule'
self.headers={
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/89.0.4389.90 Safari/537.36",
}
# 获取lts时间戳,salt加密盐,sign加密签名
def get_lts_salt_sign(self,word):
lts=str(int(time.time()*1000))
salt=lts+str(random.randint(0,9))
string = "fanyideskweb" + word + salt + "Tbh5E8=q6U3EXe+&L[4c@"
s=md5()
s.update(string.encode())
sign=s.hexdigest()
print(lts,salt,sign)
return lts,salt,sign
def attack_yd(self,word):
lts,salt,sign=self.get_lts_salt_sign(word)
#构建form表单数据
data={
"i": word,
"from": "AUTO",
"to": "AUTO",
"smartresult": "dict",
"client": "fanyideskweb",
"salt": salt,
"sign": sign,
"lts": lts,
"bv": "cda1e53e0c0eb8dd4002cefc117fa588",
"doctype": "json",
"version": "2.1",
"keyfrom": "fanyi.web",
"action": "FY_BY_REALTlME"
}
#使用 reqeusts.post()方法提交请求
res = requests.post(
url=self.url,
data=data,
headers=self.headers,
)
# res.json() 将json格式的字符串转为python数据类型
# 客户端与服务器数据交互以json字符串传递,因此需要将它转换为python数据类型
html=res.json()
print(html)
# 查看响应结果responsehtml:{"translateResult":[[{"tgt":"hello","src":"你好"}]],"errorCode":0,"type":"zh-CHS2en"}
result=html["translateResult"]["tgt"]
print('翻译结果:', result)
def run(self):
try:
word=input('请输入要翻译的单词:')
self.attack_yd(word)
except Exception as e:
print(e)
if __name__ == '__main__':
spider=YoudaoSpider()
spider.run()
关于爬虫爬有道翻译,我在小甲鱼的视频里也看过,但是不同的地方是,关于post里的data集,小甲鱼视频里似乎没像上面一样去考虑salt,sign,lts三个参数的变化问题,直接是将网页里的post响应里的原样复制进去就行了,我操作过,代码如下:
import urllib.request
import urllib.parse
import json
content = input('请输入需要翻译的内容:')
url = 'https://fanyi.youdao.com/translate?smartresult=dict&smartresult=rule'
data = {}
data['i'] = content
data['from']= 'AUTO'
data['to']= 'AUTO'
data['smartresult']= 'dict'
data['client']= 'fanyideskweb'
#此处的salt、sign、lts三个参数值没有变化
data['salt']= '16315470681987'
data['sign']= 'd6b63a7371c65430a325ca72e9cef1dd'
data['lts']= '1631547068198'
data['bv']= '5912a9bc00e8093f5992b73a3708e1b5'
data['doctype']= 'json'
data['version']= '2.1'
data['keyfrom']= 'fanyi.web'
data['action']= 'FY_BY_CLICKBUTTION'
data = urllib.parse.urlencode(data).encode('utf-8') # encode('utf-8')将 Unicode 编码转换成utf-8形式
# 修改headers信息User-Agent参数的方法一:
# 建立head字典,将User-Agent的值修改未正常浏览器访问网页是用的值()
head = {}
head['User-Agent'] ='Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/93.0.4577.63 Safari/537.36 Edg/93.0.961.47'
req = urllib.request.Request(url,data,head) #在Request时传入head参数
# 修改headers信息User-Agent参数的方法二:
req = urllib.request.Request(url,data)
#通过add_header()追加head参数
req.add_header('User-Agent','Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/93.0.4577.63 Safari/537.36 Edg/93.0.961.47')
response = urllib.request.urlopen(req)
html = response.read().decode('utf-8') #以utf-8去解码,转换成 Unicode 编码( Unicode 编码是python的默认编码格式)
print(html) #此时的html是个字符串,是给json语句的字符串
target = json.loads(html) #将字符串载入
原文 = target['translateResult']['src']
译文 = target['translateResult']['tgt']
print(原文+':'+译文)
两段代码实现的效果是一样的,这是为什么?
salt、sign、lts三个参数值在网页中确实每次都是变化的,为什么用代码去爬的时候又不需要去考虑它的变化也能爬成功呢? 虽然浏览器根据js提交了其他参数,然而参数有没有用,有没有被web服务器用来做校验或授权,这个要看服务器侧的设置。
就目前的现象看,对于有道翻译,我们只需要提交数据中的i即可,其他无从可知。 suchocolate 发表于 2021-10-6 18:26
虽然浏览器根据js提交了其他参数,然而参数有没有用,有没有被web服务器用来做校验或授权,这个要看服务器 ...
感谢回答
页:
[1]