当前位置:   article > 正文

【Python网络爬虫】2023年新版有道翻译爬虫破解_有道翻译爬虫2023

有道翻译爬虫2023

一.项目背景

在去年下半年,网页版有道翻译上新,使得原来的爬虫接口失效,目前最新的接口用的是https://dict.youdao.com/webtranslate ,接口情况如下图所示:

接口的请求看似简单,但里面加密请求和返回值解密却非常复杂,本文将会介绍该新版有道翻译的爬虫破解过程。


二.请求参数部分

打开F12开发者工具,查看请求的参数:

通过多次不同请求,我们可以发现,这些参数中需要进行特定修改的有以下几个:

  • i: 这个参数是需要进行翻译的文字
  • from: 从什么语言翻译进行翻译,'auto'表示系统自动识别
  • to: 表示翻译到什么语言,为空则为自动识别
  • sign: 加密签名,具体下面介绍
  • mysticTime: 时间戳,应该是请求时的时间戳

其他的参数都比较容易处理,我们关键留意一下sign这个参数,显然,这个sign的参数是用来进行校验的,这个请求是一个带校验参数的请求,通过检验sign的值与请求中的其他参数的值是否对应来进行请求参数的校验,我们来看一下这个参数是怎么生成的。

通过逆向追踪,可以看到这个这个sign的参数是从app.68a22c0c.js里面的第2000多行的这个k函数里面生成的,k函数中的sign调用了上面的w函数,w函数又调用了再上面的A函数,然后可以看到,这里的A函数里面是对参数e进行了md5的哈希,并转化为十六进制,而这个e参数的生成,其实是在w函数中进行多参数字符组合而来的,这里的多参数包含了d、e、u、t,通过打断点的方式,可以跟踪到这四个参数分别其实就是对应一些固定的header参数,唯一有变化的参数正是对应上面的mysticTime时间戳。

核心代码:

  1. r = 'fanyideskweb'
  2. i = 'webfanyi'
  3. e = 'fsdsogkndfokasodnaso'
  4. t = int(round(time.time() * 1000))
  5. p = f"client={r}&mysticTime={t}&product={i}&key={e}"
  6. sign = hashlib.md5(p.encode('utf8')).hexdigest()

三.返回值解密部分

针对post请求返回数据进行解密,通过进行逆向解密,可以看到app.68a22c0c.js这个文件中有相应的解码过程

可以看到,这里用到的是AES加密算法中的CBC模型进行解密,点进去createDecipheriv函数:

其中,CBC解密的key为e参数,iv为n参数,然后我们回到前面的传参部分:

通过打断点进行分析,可以看到,参数a是一个16长度的列表,c参数也是一样,都由一个alloc函数进行构建,alloc函数的第二个参数为一个j函数,j函数中接受一个参数传入

o参数为

"ydsecret://query/key/B*RGygVywfNBwpmBaZg*WT7SIOUP2T0C9WHMZN39j^DAdaZhAnxvGcCY6VYFwnHl"

n参数为

"ydsecret://query/iv/C@lZe2YzHtZ2CYgaXKSVfsb7Y4QWHjITPPZ0nQp87fBeJ!Iv6v^6fvi2WN@bYpJ4"

另一方面,查看o参数和n参数的定义,这两个参数其实是固定的:

在知道了j函数参数的内容之后,再点进去j函数的定义:

和请求头的参数构建一样,这里也是将传入的参数进行md5的转换,不过没有转为16进制

就这样一步一步地进行挖掘,返回值部分的核心代码如下:

  1. def translate(text, key, iv):
  2. iv = hashlib.md5(iv).digest()
  3. key = hashlib.md5(key).digest()
  4. # CBC模式解密
  5. AES_decrypt = AES.new(key=key, mode=AES.MODE_CBC, iv=iv)
  6. # 返回数据转为byte
  7. t = base64.b64decode(text, b'-_')
  8. # 解码
  9. decrypted_data = AES_decrypt.decrypt(t)
  10. # 解码数据拆分
  11. unpadded_message = unpad(decrypted_data, AES.block_size).decode()
  12. # 解码数据转为json数据结构
  13. json_data = json.loads(unpadded_message)
  14. res = json_data['dictResult']['ce']['word']['trs'][0]['#text']
  15. return res
  16. decodekey = b'ydsecret://query/key/B*RGygVywfNBwpmBaZg*WT7SIOUP2T0C9WHMZN39j^DAdaZhAnxvGcCY6VYFwnHl'
  17. decodeIv = b'ydsecret://query/iv/C@lZe2YzHtZ2CYgaXKSVfsb7Y4QWHjITPPZ0nQp87fBeJ!Iv6v^6fvi2WN@bYpJ4'
  18. text = make_request('你好', to='')
  19. translate(text, decodekey, decodeIv)

四.完整代码

完整代码如下:

  1. import hashlib
  2. import base64
  3. import time
  4. import json
  5. import js2py
  6. import requests
  7. from Crypto.Cipher import AES
  8. from Crypto.Util.Padding import unpad, pad
  9. headers = {
  10. 'Accept': 'application/json, text/plain, */*'
  11. ,'Accept-Encoding': 'gzip, deflate, br'
  12. ,'Accept-Language': 'zh-CN,zh;q=0.9'
  13. ,'Connection': 'keep-alive'
  14. ,'Content-Length': '252'
  15. ,'Content-Type': 'application/x-www-form-urlencoded'
  16. ,'Cookie': 'OUTFOX_SEARCH_USER_ID=-128580344@10.169.0.83; OUTFOX_SEARCH_USER_ID_NCOO=1344989105.8974342; _ntes_nnid=9b83b473d066e2e23751e2d758891587,1641266653081; search-popup-show=-1; __yadk_uid=Uby0XrclZI18dTgSjb55uEGqfHqTXOfo'
  17. ,'Host': 'dict.youdao.com'
  18. ,'Origin': 'https://fanyi.youdao.com'
  19. ,'Referer': 'https://fanyi.youdao.com/index.html'
  20. ,'Sec-Fetch-Dest': 'empty'
  21. ,'Sec-Fetch-Mode': 'cors'
  22. ,'Sec-Fetch-Site': 'same-site'
  23. ,'User-Agent': 'Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4240.198 Safari/537.36'
  24. }
  25. def make_request(word, to = ''):
  26. form = {
  27. 'from': 'auto'
  28. ,'to': to
  29. ,'dictResult': 'true'
  30. ,'keyid': 'webfanyi'
  31. ,'client': 'fanyideskweb'
  32. ,'product': 'webfanyi'
  33. ,'appVersion': '1.0.0'
  34. ,'vendor': 'web'
  35. ,'pointParam': 'client,mysticTime,product'
  36. ,'keyfrom': 'fanyi.web'
  37. }
  38. r = 'fanyideskweb'
  39. i = 'webfanyi'
  40. e = 'fsdsogkndfokasodnaso'
  41. t = int(round(time.time() * 1000))
  42. p = f"client={r}&mysticTime={t}&product={i}&key={e}"
  43. sign = hashlib.md5(p.encode('utf8')).hexdigest()
  44. form['i'] = word
  45. form['sign'] = sign
  46. form['mysticTime'] = t
  47. url = 'https://dict.youdao.com/webtranslate'
  48. res = requests.post(url=url, headers=headers, data=form)
  49. return res.text
  50. def translate(text, key, iv):
  51. iv = hashlib.md5(iv).digest()
  52. key = hashlib.md5(key).digest()
  53. # CBC模式解密
  54. AES_decrypt = AES.new(key=key, mode=AES.MODE_CBC, iv=iv)
  55. # 返回数据转为byte
  56. t = base64.b64decode(text, b'-_')
  57. # 解码
  58. decrypted_data = AES_decrypt.decrypt(t)
  59. # 解码数据拆分
  60. unpadded_message = unpad(decrypted_data, AES.block_size).decode()
  61. # 解码数据转为json数据结构
  62. json_data = json.loads(unpadded_message)
  63. res = json_data['dictResult']['ce']['word']['trs'][0]['#text']
  64. return res
  65. if __name__ == '__main__':
  66. decodekey = b'ydsecret://query/key/B*RGygVywfNBwpmBaZg*WT7SIOUP2T0C9WHMZN39j^DAdaZhAnxvGcCY6VYFwnHl'
  67. decodeIv = b'ydsecret://query/iv/C@lZe2YzHtZ2CYgaXKSVfsb7Y4QWHjITPPZ0nQp87fBeJ!Iv6v^6fvi2WN@bYpJ4'
  68. text = make_request('你好', to='')
  69. translate(text, decodekey, decodeIv)

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/Li_阴宅/article/detail/855686
推荐阅读
相关标签
  

闽ICP备14008679号