鱼C论坛

 找回密码
 立即注册
查看: 1228|回复: 2

[已解决]python爬虫有道翻译:post响应相关问题

[复制链接]
发表于 2021-10-6 16:14:57 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能^_^

您需要 登录 才可以下载或查看,没有账号?立即注册

x
本帖最后由 非凡 于 2021-10-6 16:25 编辑

我在C语言中文网读到一篇文章,讲爬虫有道翻译
http://c.biancheng.net/python_spider/case05.html
我截取以下一段内容:

通过控制台抓包,我们得知了 POST 请求的参数以及相应的参数值,如下所示:
1.jpg
并发现以下了规律: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,与我需要解决问题无多大关系,就不复制过来了,感兴趣可以访问原链接。
2.jpg
通过上述方法就找到了 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三个参数值在网页中确实每次都是变化的,为什么用代码去爬的时候又不需要去考虑它的变化也能爬成功呢?
最佳答案
2021-10-6 18:26:23
虽然浏览器根据js提交了其他参数,然而参数有没有用,有没有被web服务器用来做校验或授权,这个要看服务器侧的设置。
就目前的现象看,对于有道翻译,我们只需要提交数据中的i即可,其他无从可知。
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

发表于 2021-10-6 18:26:23 | 显示全部楼层    本楼为最佳答案   
虽然浏览器根据js提交了其他参数,然而参数有没有用,有没有被web服务器用来做校验或授权,这个要看服务器侧的设置。
就目前的现象看,对于有道翻译,我们只需要提交数据中的i即可,其他无从可知。
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2021-10-7 11:03:23 | 显示全部楼层
suchocolate 发表于 2021-10-6 18:26
虽然浏览器根据js提交了其他参数,然而参数有没有用,有没有被web服务器用来做校验或授权,这个要看服务器 ...

感谢回答
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|手机版|Archiver|鱼C工作室 ( 粤ICP备18085999号-1 | 粤公网安备 44051102000585号)

GMT+8, 2025-1-13 03:11

Powered by Discuz! X3.4

© 2001-2023 Discuz! Team.

快速回复 返回顶部 返回列表