pinhai 发表于 2020-2-26 19:54

【原创源码】【python】淘豆网文档下载探索

本帖最后由 pinhai 于 2020-2-26 23:13 编辑

一、引子因发现有人悬赏下载淘豆网(taodocs.com)文档,之前看过python下载文泉的文档,就想试试看能不能用python下载淘豆网付费文档。
二、分析以https://www.taodocs.com/p-55966379.html为例,浏览器为火狐。ctrl+shift+E打开开发工具-网络,刷新该页面,试一下“图像”选项,观察左侧请求,不难发现该页面里面加载的文档都是图片,分辨率810*1146,至此确定下载思路为下载每个页面的图片,最后合成为pdf格式。
三、探索1.要想下载图片就必须知道图片地址,查看上图所点选的请求,发现消息头为https://file.taodocs.com:808/img/Hj5pnzEjlNUzKb8@8S9qCO38LfhgpL2T,非常简单,前半部分为服务器地址https://file.taodocs.com:808/img/,后面为一个字符串,查看图片地址问题简化为查找字符串生成方式。多次打开该页面,发现针对同一个页面,该字符串是固定不变的,更进一步简化了探索过程。通过调试器查找该字符串,没有结果,也正常,如果能在源码中找到该字符串,这个问题也过于简单了。
2.既然在源码中没有,那应该是从服务器动态获取的,重新翻看各个请求,发现这样一个请求
https://file.taodocs.com:808/?from=pc_55966379&furl=lBk9LJ9uXl6xoMR8lbVBog==&callback=jQuery112405711252286986038_1582691611656&_=158269161165,其响应结果为
jQuery112405711252286986038_1582691611656({"imgs":["i8iHNYeTqVJnoWn94KhuiUcGAbR7NkEda7Pz/A2BXR6Klbsjxc6VBFlNSo2v+E+gPbaY0kGjILRUfWGVklmq1Q==","i8iHNYeTqVJnoWn94KhuiUcGAbR7NkEda7Pz/A2BXR5qt+SMkv+qjTc0lEgGxV7hMMSI+gTcr2AiNP8TFOBijg==","i8iHNYeTqVJnoWn94KhuiUcGAbR7NkEda7Pz/A2BXR7A4Dh7vPZP21hM7cvADzC9TKG2FdbWuk9LnmXlFAkXgg=="],"next":"lBk9LJ9uXl59juySZznxSh6QvU@bBUhr","pageNum":10,"ts":28.779500000000002});其中imgs标签很可疑,但不是地址,可能经过了加密。翻看代码,发现(其实找了好久)js代码中对imgs变量进行了一个处理,处理函数是EiePQRNA,查看定义为:

function EiePQRNA(_0x2abb91) { var _0x53a94f = { 'ZWphd': '**********' }; var _0x2d16f9 = _0x53a94f['ZWphd']; var _0x6048e2 = L8LXdspqSjEiePQRNA['AES']['decrypt'](_0x2abb91, L8LXdspqSjEiePQRNA['enc']['Utf8']['parse'](_0x2d16f9), { 'mode': L8LXdspqSjEiePQRNA['mode']['ECB'], 'padding': L8LXdspqSjEiePQRNA['pad']['Pkcs7'] })['toString'](L8LXdspqSjEiePQRNA['enc']['Utf8']); return _0x6048e2; }
可见加密方式为AES,加密模式为ECB,秘钥也是明文,在此隐去了,没有偏移量,拿到在线解密网站试一下,结果正是我们要找的图片地址。

好了,既然图片地址找到了,我们就要构造请求了,看上述请求发现,55966379容易,就是文档的编号,在网址中可以方便接取,furl是什么?我们需要看一下,重新看上述请求的响应,除了imgs保存了加密过的图片地址外,还有一个next参数,长度和我们furl长度一致,理解一下next,就是下一个的意思,再看imgs中只存了3个地址,可以猜想到网页是分段加载的,next中存储的正是下一个请求的furl参数。这样就串起来了,只要构造出第一个reuqest,后面就可以递归调用了。那么第一个request如何构造呢?
3.继续翻看网络请求,发现第一个涉及获取图片地址的请求和后面的请求别无二致,也有furl参数,那么他的furl从哪里来呢?看到https://www.taodocs.com/showProduct.aspx?fn=docinfo&id=55966379请求比较可疑,他返回了一个参数,叫nextPageStr,将他带入获取图片地址请求中(callback和_参数不管),利用重发功能重新发起请求,发现可得正常响应。

4.至此,我们理顺了网站加载所有文档页面的过程:
①使用https://www.taodocs.com/showProduct.aspx?fn=docinfo&id=55966379获取nextPageStr。
②使用nextpagestr作为furl构造https://file.taodocs.com:808/?from=pc_55966379&furl=lBk9LJ9uXl6xoMR8lbVBog==&callback=jQuery112405711252286986038_1582691611656&_=158269161165获取图片地址imgs和next参数,imgs通过json解包并通过EiePQRNA函数解密后获取图片实际地址下载显示。
③使用next参数作为下一个请求的furl,直到next为空,结束请求。
5.题外话,第一次分析时,该网站的请求图片请求并不是发送到https://file.taodocs.com:808,而是https://view.taodocs.com:808,并且返回的imgs也是明码,没有加密,要更加容易一些,试验代码也是基于https://view.taodocs.com:808的,等我要来写这篇帖子时发现不一样了,黑人问号脸 ??,害我又找了半天。ps,view.taodocs.com:808依然可用,且无需解密。
四,实践
啥也别说了,撸代码(header直接从firefox中复制)import requests
import time
import base64
from Crypto.Cipher import AES
headers1 = {
'Host': 'file.taodocs.com',
'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; Win64; x64; rv:73.0) Gecko/20100101 Firefox/73.0',
'Accept': '*/*',
'Accept-Language': 'zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2',
'Accept-Encoding': 'gzip, deflate, br',
'Connection': 'keep-alive',
'Referer': 'https://www.taodocs.com/p-107648150.html',
'Pragma': 'no-cache',
'Cache-Control': 'no-cache',
}
headers2={'Host': 'www.taodocs.com',
'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; Win64; x64; rv:73.0) Gecko/20100101 Firefox/73.0',
'Accept': '*/*',
'Accept-Language': 'zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2',
'Accept-Encoding': 'gzip, deflate, br',
'Connection': 'keep-alive',
'Referer':'https://www.taodocs.com/p-107648150.html',
'Cache-Control': 'max-age=0',
'TE': 'Trailers',}
def getimgs(url):
    pid = url.split('-')[:-5]#截取pid
    print(pid)
    response=requests.get('https://www.taodocs.com/showProduct.aspx?fn=docinfo&id=' + pid, headers=headers2)
    nextstr = response.json()['nextPageStr']#获取第一个nextstr
    title = response.json()['data']['Title']#获取文档标题
    print(title)
    imglist=[]
    i=1
    while(nextstr):#循环获取nextstr,直到nextstr为空
      url2='https://file.taodocs.com:808/?from=pc_'+pid+'&furl='+nextstr#构造请求      
      response1 = requests.get(url2, headers=headers1).json()      
      try:
            imglist=response1['imgs']#获取imgs            
      except:
            print("=================================wait===================================")
            time.sleep(30)#遇错后延迟,主要是服务器有时间间隔限制
            response1 = requests.get(url2, headers=headers1).json()
            imglist=response1['imgs']      
      for img in imglist:
            imgjiemi=aes_decode(img, '*********')#解密,这里我把秘钥隐去了
            url = 'https:' + imgjiemi
            print(url)
            response = requests.get(url)
            imgbody = response.content
            with open('e:/1/' + title+str(i+imglist.index(img) )+ '.jpg', 'wb') as f:
                f.write(imgbody)#下载保存,没有合成pdf,主要是累了
      i=i+len(imglist)
      nextstr=response1['next']      
      
def aes_decode(data, key):#解密函数
    try:
      aes = AES.new(str.encode(key), AES.MODE_ECB)# 初始化加密器
      decrypted_text = aes.decrypt(base64.decodebytes(bytes(data, encoding='utf8'))).decode("utf8")# 解密
      decrypted_text = decrypted_text[:-ord(decrypted_text[-1])]# 去除多余补位
    except Exception as e:
      print(e)
    return decrypted_text
urltoStart='https://www.taodocs.com/p-55966379.html'
getimgs(urltoStart)


六、总结
这个帖子是我来到吾爱的第一个帖子,费了不少劲,python也是纯自学,请各位前辈多多鼓励!写这个帖子一是分享,二是记录学习过程,希望不足之处,各位帮助提高!

风在此停止 发表于 2020-3-19 00:47

本帖最后由 风在此停止 于 2020-3-19 01:12 编辑

楼主你好我找到了我的EiePQRNA定义:

function EiePQRNA(_0x2abb91) {
var _0x53a94f = { 'ZWphd': '1234567812345678' };
var _0x2d16f9 = _0x53a94f['ZWphd'];
var _0x6048e2 = L8LXdspqSjEiePQRNA['AES']['decrypt'](_0x2abb91, L8LXdspqSjEiePQRNA['enc']['Utf8']['parse'](_0x2d16f9), { 'mode': L8LXdspqSjEiePQRNA['mode']['ECB'], 'padding': L8LXdspqSjEiePQRNA['pad']['Pkcs7'] })['toString'](L8LXdspqSjEiePQRNA['enc']['Utf8']);
return _0x6048e2; }
请问密码就是1234567812345678吗?
还有你的在线解密网站是什么?我百度的好像不好使。
我的第一页密文是:
jQuery1124011299194684837466_1584549001674({"imgs":["n865nL8mjQYiYc0y3+sfNps0MJaelT/I/y/dtjX5/t99d4gF1A4UE+b0znDl9TWdrx4/L9iiHpHoBKV1E0ytNA==","n865nL8mjQYiYc0y3+sfNps0MJaelT/I/y/dtjX5/t9RP4BrwAXdRjVGuxTCw/wQfHkiAAkSWMKP8fhdNDogpg==","n865nL8mjQYiYc0y3+sfNps0MJaelT/I/y/dtjX5/t9uRrX8frb8Qf0CCim2iUYxoskg6a784enn+hN1wg1t0A=="],"next":"@HSlfKLl6OOPEq9pzTs9GmW5foLT01Bx","pageNum":101,"ts":29.686700000000002});

但我不知道它怎么解密出:sSBsJQxhv6_H0BtpFfEin_Knuq6cm1Nk

https://static.52pojie.cn/static/image/hrline/1.gif

已解决:http://tool.chacuo.net/cryptaes

chensure 发表于 2020-2-26 22:26

谢谢。。。。别人的代码是最好的老师

pinhai 发表于 2020-2-27 08:06

感谢版主鼓励!@wushaominkk

godmodel 发表于 2020-2-27 10:56

感谢分享

vagrantear 发表于 2020-2-27 12:23

学习了 谢谢

知意执意 发表于 2020-2-27 12:57

感谢分享

虎虎生威 发表于 2020-2-27 15:38

小白怎样才能用上?请教

pinhai 发表于 2020-2-27 16:09

虎虎生威 发表于 2020-2-27 15:38
小白怎样才能用上?请教

如果是页数少的,可以直接在浏览器网络调试里面找到对应的图片下载即可。页数多的话,1要安装python,2要安装pip包,3要安装requests和cypto包,4要找到密钥(在网页的源码中)替换源码中的密钥,5将源码中的urltostart换成你需要下载的网址,再运行就可以了。看起来很麻烦,但都可以百度出来,再有不懂还可以一起讨论。
其实分享这个主要是为了分享分析网站的过程,就像解开一个网站开发者打包好的神秘礼物一样,不是为了最后的文档。
如果只是为了1份文档,不需要以上这么麻烦,直接在悬赏区悬赏就可以了,自有人为你下载好。多谢回复。

虎虎生威 发表于 2020-2-27 16:26

pinhai 发表于 2020-2-27 16:09
如果是页数少的,可以直接在浏览器网络调试里面找到对应的图片下载即可。页数多的话,1要安装python,2要 ...

谢谢大哥,我要晕倒

zero66 发表于 2020-2-28 13:33

不错,学习下。{:1_918:}
页: [1] 2 3
查看完整版本: 【原创源码】【python】淘豆网文档下载探索