0. 写在最前
此专栏是记录以下一些我自己在本科写的一些小工具,仅仅用作学习为目的,绝不会有任何盈利,如果损害到了开发者的利益,请立即联系我进行删除,本人邮箱:zh00612@126.com
1. 介绍
现在有很多的网盘网站,在搜索资源时往往是需要会员才能得到网盘资源的真实地址,但其实它里面的地址在包中是暴露的,仅仅是需要普通用户就可以得到资源,只需要的到里面的接口就可以了
2. 代码和功能展示
main.py
import threading
import PySimpleGUI as sg
from ui import main_layout, serach, win_icon, info_window
from luopanso import table_datas
import pyperclip
class UI():
def __init__(self):
self.top_window = sg.Window('网盘搜索神器v1.0', main_layout, finalize=True,
grab_anywhere=False, alpha_channel=1, icon=win_icon)
self.datas = [[]]
def run_task(self):
self.datas = table_datas(self.values.get('-input-'))
self.top_window.write_event_value('-THREAD-', '*** The thread says.... "I am finished" ***')
def circle_event(self):
search_layout_active = False
# 由于搜索时间过长,体验较差,因此通过多线程加入加载条
# 线程标志位
thread = None
# 设置加载条刷新频率
timeout = 100
while True:
# 循环读取窗口信息,事件和值
self.event, self.values = self.top_window.read(timeout=100)
# 如果触发关闭事件就关闭窗口
if self.event in (sg.WIN_CLOSED, 'Exit'):
break
elif self.event == "serach" and not search_layout_active:
if not self.values.get('-input-'):
sg.popup_error('请输入关键字再搜索!', keep_on_top=True)
else:
thread = threading.Thread(target=self.run_task,
daemon=True)
thread.start()
if self.event == '-THREAD-':
# 结束线程
thread.join(timeout=0)
# 结束加载条
sg.popup_animated(None)
# 清除标志位
thread, timeout = None, None
search_window = info_window(self.datas)
search_layout_active = True
if thread is not None:
sg.popup_animated(sg.DEFAULT_BASE64_LOADING_GIF, background_color='white', transparent_color='white',
time_between_frames=10, message='正在搜索网盘资源....', text_color="blue", font="5px")
elif search_layout_active:
search_event, search_value = search_window.read(timeout=1000)
if search_event in (sg.WIN_CLOSED, 'Exit'):
search_layout_active = False
search_window.close()
elif search_event == '_table_':
url = search_window['_table_'].get()[int(search_value['_table_'][0])][-1]
pyperclip.copy(url)
sg.popup_quick_message('url已经复制到剪切板!,请在浏览器打开', text_color='#2ecc71', font='3px', keep_on_top=True)
self.top_window.close()
if __name__ == '__main__':
ui = UI()
ui.circle_event()
luopanso.py
import time
from dataclasses import dataclass
from typing import List
import requests
@dataclass
class Info(object):
id: str
filename: str
update_time: str
size: str
def get_millisecond():
"""
:return: 获取精确毫秒时间戳,13位
"""
millis = int(round(time.time() * 1000))
return millis
def hum_convert(value) -> str:
units = ["B", "KB", "MB",
"GB", "TB", "PB"]
size = 1024.0
for i in range(len(units)):
if (value / size) < 1:
return "%.2f%s" % (value, units[i])
value = value / size
class LuoPanSo(object):
def __init__(self):
self.headers = {
"Accept": "application/json, text/plain, */*",
"Accept-Language": "zh-CN,zh;q=0.9,en-GB;q=0.8,en;q=0.7",
"Cache-Control": "no-cache",
"Connection": "keep-alive",
"Origin": "https://www.luomapan.com",
"Pragma": "no-cache",
"Referer": "https://www.luomapan.com/",
"Sec-Fetch-Dest": "empty",
"Sec-Fetch-Mode": "cors",
"Sec-Fetch-Site": "cross-site",
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/107.0.0.0 Safari/537.36",
"X-Authorization": 你的cookie,
"sec-ch-ua": "^\\^Google",
"sec-ch-ua-mobile": "?0",
"sec-ch-ua-platform": "^\\^Windows^^"
}
@property
def c_time(self):
millis = int(round(time.time() * 1000))
return millis
def get_info_list(self, key_str):
url = "https://fc-resource-node-api.krzb.net/api/v1/pan/search"
params = {
"version": "v2",
"kw": key_str,
"page": 1
}
response = requests.get(url, headers=self.headers, params=params).json()
return [Info(data['res']['id'], data['res']['filename'],
data['res']['updatetime'], hum_convert(int(data['res']['size'])))
for data in response['resources']]
def check_ok(self, data: Info):
url = "https://fc-resource-node-api.krzb.net/api/v1/pan/checkUrlValidFromBaidu"
params = {
"t": self.c_time,
"version": "v2",
"data": data.id
}
response = requests.get(url, headers=self.headers, params=params).json()
if response.get(data.id):
return True
def resource_detail(self, id):
url = "https://fc-resource-node-api.krzb.net/api/v1/pan/detail"
params = {
"version": "v2",
"id": id,
"size": "15",
"parent": ""
}
response = requests.get(url, headers=self.headers, params=params).json()
if response.get('haspwd'):
return response['pwd']
return None
def get_pan_url(self, id, pwd):
url = "https://fc-resource-node-api.krzb.net/api/v1/pan/url"
params = {
"version": "v2",
"id": id
}
response = requests.get(url, headers=self.headers, params=params).json()
if pwd:
return response['data'] + f'?pwd={pwd}'
return response['data']
def table_datas(key_str: str) -> List[List]:
TableDatas = []
l = LuoPanSo()
datas = l.get_info_list(key_str)
for index, data in enumerate(datas):
pwd = l.resource_detail(data.id)
if l.check_ok(data):
filename = data.filename
size = data.size
update_time = data.update_time
pan_url = l.get_pan_url(data.id, pwd)
TableDatas.append([index + 1, filename, size, update_time, pan_url])
return TableDatas
ui
import PySimpleGUI as sg
serach = b'iVBORw0KGgoAAAANSUhEUgAAAB0AAAAdCAYAAABWk2cPAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAAEnQAABJ0Ad5mH3gAAARcSURBVEhLvZZtUFRVGMf/vCi7G4ZA4CwiyovsophaEBNIKIwgyRq040CIVk7qaM1oM2ZrhrYTzUjJOBqNTfBBRsqKplGcUsmZPiSVgDloIhMLYoIQMPEOu3fv8nT27kHL3cVdRvt9uff8n+fc/71nnvuc40EM/M+4ZGo2jeJOezOEcROsyXKFHMpwFbxnKGwJbjKlaYfhKqo/K0FbUwu7b4AomGHN9pHLEBYdh/DFUVj90lZExD7LZ7iGU9Oq0t344lAJjCNA8rpUpObuYF/oC/IABnu7ceHkUdTV/AbfAKBg9z7k7CjiM13AavpvRgb66M1MNSXPAJUd2MJVx4gWMx3cupJWykDv5j5Do0ODPDI1dqZvZS0hzVzQjbpzXHkwZys+pMwgkP7lNDay2MQp+I/p6bJCWuHtnuEk1WVFlBEI+vroXq44565pV/t10oZ7UOmeDVxxH13OMnqBrdLocD9XHHPX9JhuE2UE2K22W9xsqqecMFC5fjNXHONpLSbBOATDtRYkZMRJxTVdFsTEITQ6CBdP/8gVx0im3e0GdLReRnreLkk0jw9J1+kQHhOPCcsQhvu7uGKP7UsFEyxmAf5zlPirpxerE+Ix1NcpJbhLxKLlGBvpR8/tVq7YI5lKF9YiRFHEnOAgnP21Ab7+wbaQm4hkAesf8PDysgkOkExlCh/MVCjQfcsgieWFr+ET3Ubp3l2a63+Cwi8QQaGRXLFHMg0JX4T5qgScP1EiiU+v0qD2zBn83d0tjd2ho+V3+MhmYZaf85WSTD29ZiJ6mRrXfm6DyTiKxKwCzFfHoHTPi1KSqzT8cJIV5SCSNFlccQL/dYjtKJSr8qZ9ubHS2GQcoPQAPzr0eqY0doW92udIEwISzeNcccx9bfB9WqUAfXtsP1eINscHUP7ieSSYhrnimOMfbKd0f9C5imKuOMeuBRW9mipNrvr4Ha4QXTpfSWbByEf2lOu3kTYKVBAL2rlGTb2dBh5xjJ2pYBLYdrWW0meD3s5eSm3X63jEnoYLX5FOm0K5alBloZL6GlX0ylNetCVJTX1drTzLHqeb+KkyPSqK3mMvBXZKeAJzo55EaCR7usWC9uZG3Gm7gY6bg5D7sl/OB9B9pEJMEsH4J7Ahy4CwhUtwoPJ7zA4M4U+8x5THFdFsRNURHWq+rGatbQTC2AArdU/I5P6QPSZHinY98nYVQ5cdh6aGy9B9GoHEZG+MsQ648fk/EKZaCv3nNXg84L7fx2rqCsMDPdTeXM+q/AoZRwe4OskEFW9fT5p5oEvfLCAaU1NnbTRpI8G2u0QSRRPPs+Gy6YMQRTPtz0+htUpQfXUkU9TUwYzTWG2UvJFtS+I8NNNJ9JvSKY3ty/WnItibqOj2L1GUEQxqvHjvNPLQTa0c3LaO1rAzU21lCH13WEmaMC+61XyFRx+RqSgKdHhnPuXF+pN2oZw1nSIeseHSCX86sFMhDFfrQBMWRC9fwVUbj8zUOcA/k7eHTRyafqUAAAAASUVORK5CYII='
win_icon = b'iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAAEnQAABJ0Ad5mH3gAAAOXSURBVDhPjZRNbFRVFMd/72PmzXQ6hbbQ0tKhIBZsWqRQJNH4nSguuiDBuDJswIWJIYQalcSlqBE1Gq0Lqwti2OBCTcDErozBhAS1XwwkGIt0WtoObScz7cy8+XjzPO/OtNJSG38vN/fmfvzvOeee8zRX4D8YGktzfcImlSkSDhq0twTZvzNUWV2bNQVPfxOj/6c4fs3ApxvoaJRwKZQcCjI6/txm3jsaqexeyQrBv+M5Hn0jijdTr4dwtyVwts7jBgpoWR/GnVqMWD0Lrk0eh8vvt/NAY6ByusyyYOxujs4TowT8Oi92NXL5iQHmrSSGYyLGyU7pTAct46fq0j60iQ3E0mlGPt3D9kbLk1AsC0aODZIvuhwTd959OYL161mazGo0TZTuwdXE+bBNcGAP+nALC9jEvt5XWUXCI7xzYVKJPba7WokpStI8q1Z9ooiWCpJ9fhStOYle0jnz7WT5jKAE+36cIV9wOd/7oJr02F1XQ9HKqfjd14ISU9tH5oURagjy2cWZyikwb96xyYnYwV0hqiydG7Ese0+OsjP8FHW6uu8+tLxJ9tAI9sG/KG1JwoSPoVtpunaE0KPjGbXp6c4a1ZsGhAIGCTdDTiuAIb6vat7juNJrBZNiZF6lV3Q8Wz6ftr1gwcaQKAltzUES57vV+JGb/cRyKSzJxdVoOZ8IGrhWUcUtlXHUvF5bLWkhzC0UVX8vV3e9guQyriNHJPhazkRPB1TTinKJ5qJLfnpJXxcu65id24JqMDCU5O2Xti7H0HPbr+k0+HvkseXLG9iHRsl3TJbFBNfnSKLXkZNbH26tUnN6a4NFdUDn2u0sc6mCehhPzDI1dNNlrpRmtrTIrJsmLn3GKVB0xSa9hDEbRouH8fmhPVI2TCX2h99Pcfa7KVX8P59pVwtrMWhP8cX4ML8kx0lUJdl87llScZOThxvoPdyk9ixXSturwyxmHXoO1NL/2g61uB5v9s1w4Y8ZGusNrnzQUZmtJLbH7x91qmq5+FuCx9+6zm2p7fX46soEliUhSRW5K6FaYsXfxrPwwOtREvLiBcelrSnAkx1hNlYbnD7SjK7/W9e3Zmy6T0Vp2GCqDLnRt5dNNeZKwSU+vzTNxz9Mk0g7eBqJxSKfHG/lRM+Wyo4yY9Mi2hulUURnxdLpc/vXFlxiXNweHMuQlKQ9+symyuxK/pTS7T51jUXbYezLrvUF/y/z4nI8WeChliD/AAH0pMxCJYwVAAAAAElFTkSuQmCC'
# 改变主题
sg.ChangeLookAndFeel('Default1')
# 装饰按钮
def GraphicButton(text: str, key: str, image_data):
text = text.replace('_', ' ')
button = sg.Button('', image_data=image_data, button_color=('white', '#F1F1F1'), font='Any 15', key=key,
border_width=1)
text = sg.Text(text, font='Any 10', size=(15, 1), justification='center', )
return sg.Column([[button], [text]], element_justification='c')
main_layout = [[sg.T('搜索关键字:', font="15px"),
sg.Input(key='-input-', text_color='blue', size=(12, 100),
font="15px"), sg.Button(key='serach', image_data=serach)]]
def info_window(datas) -> sg.Window:
"""
:return: 返回一个sg的window对象
"""
info_layout = [[sg.Table(
values=datas,
headings=['序号', '文件名', '文件大小', '更新时间', '网盘地址(左键单击进行复制)'],
max_col_width=500,
auto_size_columns=True, # 自动调整列宽(根据上面第一次的values默认值为准,update时不会调整)
justification='center', # 字符排列 left right center
key='_table_',
font=('微软雅黑', 10),
text_color='black',
background_color='white',
enable_events=True,
enable_click_events=True,
bind_return_key=True,
tooltip='This is a table')],
]
window = sg.Window('网盘资源详情', info_layout, keep_on_top=True, finalize=True, icon=serach)
return window
界面功能展示
输入关键字点击按钮搜索资源
得到资源列表
左键单击行拿到会帮你把URL复制到粘贴板上
接下来你就可以把url复制到浏览器上拿到网盘资源啦~~~~~~
3. 注意
- 其中header的
X-Authorization
这个参数是需要你自己去抓包拿到的,因为它是jwt验证有过期性,因此你需要定时去更换cookie,本来是想直接过验证的但是它是微信登录验证就不能代码过验证了。 有空的话我再写一下接口是如何找到并且代码是如何调度的