|
马上注册,结交更多好友,享用更多功能^_^
您需要 登录 才可以下载或查看,没有账号?立即注册
x
本帖最后由 非凡 于 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)
- # 查看响应结果response html:{"translateResult":[[{"tgt":"hello","src":"你好"}]],"errorCode":0,"type":"zh-CHS2en"}
- result=html["translateResult"][0][0]["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'][0][0]['src']
- 译文 = target['translateResult'][0][0]['tgt']
- print(原文+':'+译文)
复制代码
两段代码实现的效果是一样的,这是为什么?
salt、sign、lts三个参数值在网页中确实每次都是变化的,为什么用代码去爬的时候又不需要去考虑它的变化也能爬成功呢?
虽然浏览器根据js提交了其他参数,然而参数有没有用,有没有被web服务器用来做校验或授权,这个要看服务器侧的设置。
就目前的现象看,对于有道翻译,我们只需要提交数据中的i即可,其他无从可知。
|
|