某福利网站文件下载

从Python爬虫到数据爆破

Posted by JovenHe on January 13, 2021

前几天一位朋友分享了一个福利网站,让我帮忙批量下载文件。本着互帮互助的精神,正好练习一下两年前学完就忘的爬虫知识

严重声明 本文的意图只有一个就是通过分析网站学习更多的逆向技术,如果有人利用本文知识和技术进行非法操作进行牟利,带来的任何法律责任都将由操作者本人承担,和本文作者无任何关系,最终还是希望大家能够秉着学习的心态阅读此文。

Python相关下载就不做多描述了

直接进入首页,打开开发者工具

很容易定位到每一个福利和翻页的位置

进入单个福利下载位置,点击下载,得到请求

其实就是第一个请求进行校验后,第二个就是GET请求下载,所以着重是第一个请求

先直接Postman跑一下,确定参数和有无header

可以看到就三个参数

第一个请求直接查看Initiator面板中的请求调用栈。

找到关键调用位置

对应到页面上就是

参数就在页面js中声明了

下面就用python来搞一下

from urllib.error import HTTPError

import requests
from bs4 import BeautifulSoup
import re
import json
import decode

def getTest(url):
    kv = {'user-agent': 'Mozilla/5.0'}
    res = requests.get(url, kv)
    page = BeautifulSoup(res.text, 'html.parser')
    #查找页面每一个资源地址
    items = page.find_all(class_='waitpic')
    for item in items:
        #资源地址
        print(item.parent['href'])
        #截取地址的id
        pid=re.findall(r"\d+?\d*",item.parent['href'])[0]
        res1 = requests.get(item.parent['href'], kv)
        #资源详情页面
        one = BeautifulSoup(res1.text, 'html.parser')
        #下载按钮
        Mypassdown=one.find('a', class_='Mypassdown')
        if Mypassdown is None:
            continue
        data_down = Mypassdown.get('data-down')
        body = {'pid': pid, 'down': data_down,'action':'Post_down_ajax'}
        check=requests.post('https://www.第一个请求地址.xyz/wp-admin/admin-ajax.php',body)
        result=json.loads(check.text)
        if result is not None:
            print(result)
	#下一页
    next=page.find(class_='next page-numbers')

    if next is None:
        pass
    else:
        url = (next['href'])
        getTest(url)


if __name__ == '__main__':
    url="https://www.福利.xyz/"
    getTest(url)

以上就实现了每一页资源的自动请求,请求完成后翻页。

执行后就是统一的校验通过,并得到data数据

再来看校验的js代码中,post请求结束后执行了MYdownresult(result);,所以直接看MYdownresult的逻辑

可以看到就是拿到data数据解析后使用Cx_urlopen函数进行下载。所以直接分析$.CxJM.atob函数

既然得到了以上js,其实可以直接使用在线运行工具看效果

可以看到运行后直接解析出了我们想要的地址

下面就直接分析解密逻辑得到python代码就可以了

import re

def i(a,c,d) :
    jisuan="".join(a)
    g = 0
    index = 0
    i = len(jisuan)
    j = ""
    k = 0
    l =0
    m=0
    while ( i > index):
        l = ord(jisuan[index])
        if(256 > l ):
            l=(d[l])
        else:
            l=-1
        g = (g << 6) + l
        k += 6
        while (k >= 8 ):
            k -= 8
            m = g >> k
            j += c[m]
            g ^= m << k
        index+=1

    return j


def decode(data):
    data=data.replace("*!agf", "=")
    data=data.replace("&a^f", "b")

    b = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'
    c = ""
    d = [-1] * 256
    e = [-1] * 256
    f = 0
    h = ""
    for num in range(0,256):
        f=num
        h = chr(f)
        c+=str(h)
        e[f] = f
        try:
            d[f] = b.index(str(h))
        except:
            d[f] =-1
    data="".join(re.findall('[a-zA-Z0-9]+', data, re.S))
    return (i(data,c,d))

直接在main中引用并执行decode.decode(result[‘data’])

完整代码如下:


from urllib.error import HTTPError

import requests
from bs4 import BeautifulSoup
import re
import json
import decode

def getTest(url):
    kv = {'user-agent': 'Mozilla/5.0'}
    res = requests.get(url, kv)
    page = BeautifulSoup(res.text, 'html.parser')
    #查找页面每一个资源地址
    items = page.find_all(class_='waitpic')
    for item in items:
        #资源地址
        #print(item.parent['href'])
        #截取地址的id
        pid=re.findall(r"\d+?\d*",item.parent['href'])[0]
        res1 = requests.get(item.parent['href'], kv)
        #资源详情页面
        one = BeautifulSoup(res1.text, 'html.parser')
        print(one.title.text)
        #下载按钮
        Mypassdown=one.find('a', class_='Mypassdown')
        if Mypassdown is None:
            continue
        data_down = Mypassdown.get('data-down')
        body = {'pid': pid, 'down': data_down,'action':'Post_down_ajax'}
        check=requests.post('https://www.第一个请求地址.xyz/wp-admin/admin-ajax.php',body)
        result=json.loads(check.text)
        if result is not None:
        	#print(result)
            if result['status'] == 1:
                print(decode.decode(result['data']))
	#下一页
    next=page.find(class_='next page-numbers')

    if next is None:
        pass
    else:
        url = (next['href'])
        getTest(url)


if __name__ == '__main__':
    url="https://www.福利.xyz/"
    getTest(url)

运行效果如下,过多的标题不敢截

至此解决资源下载路径问题,下载的话,直接拿到浏览器下载或者网上找python下载代码即可

总结

之前也就学过一点点python和js的皮毛,通过代码的粗略程度也能知道。也就知道哪个库是解析的,哪个库是请求的,都是一边搜索一边写。一开始并没想分析网页的点击请求,因为下载地址都是zip/2021/01/10/9592.zip这种格式,很明显是拼接的年月日,而且资源详情页有预览图的地址就有这个年月,我可以直接遍历1-31拼接后得到url,通过request后的status是否是200来判断这个url是否有效。但如此一来又没有解谜的趣味性,而且从讲解来看,总不能说答案是遍历出来的吧,只好从听众的角度一步步解密到结果。

希望能对他人有所帮助