加了一堆网盘群如何导出目录结构呢?试试我这个路子吧

tool   baidu   chrome  
发布于 Oct 5, 2024

需求已经在标题里写出来了,作为小仓鼠,知识付费界的韭菜,网盘里 13T 的空间已经存满了,奈何还有一堆网盘分享群里上千T的资源留守空房(影视,音乐,教辅,技术等门类齐全)。

背景

资源太多了,不太好检索,作为爱折腾的程序猿,想了想,是否可以把他们导出来,自己加工一下,方便自己检索和定向索取呢?又或者不想分享出去,只分享一个目录,让别人付费索取,作为自己的资产收费呢?

哈哈哈,感觉挣钱的路子蛮宽啊!说干就干,看看怎么先把目录搞下来吧。

遇事不要慌,度娘闯一闯,不知道姿势不对还是资源稀缺,搜了几篇,不是广告文(卖网盘索引产品的,看来市场还是有的)就是过时不好用了。

算了,作为造轮子的小能手,咱自己造一个吧,说不定能抛转引玉,遇到牛逼的大神给出指导意见。欢迎加好友交流。公众号”新质程序猿”回复:网盘群,拉你探讨网盘致富之路。

为了不干扰大家的思绪,我就直接上自己的设计方案了:网页插件 - 请求网盘接口 - 转存服务器

这个方案仅仅是为了验证能否跑通,至于好不好用,能否接受住挑战,那就是各位大牛的任务了。

废话不说了,上砖块(抛砖引玉)。

安装篡改猴

本来想搬出我的老底 chrome 插件开发能力,在搜索的过程中搜到了 油猴,暴力猴,篡改猴 这么个玩意,你别搜了,就是一个 chrome 插件,直接写我们的脚本就行了,不用从头开发插件了,省事不少 。

第一步,安装篡改猴,官网地址如下:

https://violentmonkey.github.io/

支持插件商店和源码安装方式,不会的可以度娘搜:Chrome插件离线安装,应该很多教程。

Chrome商店(需科学上网):

https://chromewebstore.google.com/detail/jinjaccalgkegednnccohejagnlnfdag

离线包:

https://github.com/violentmonkey/violentmonkey/releases

第二步,打开网盘页面,刷新页面,点击+号,给当前页面增加用户脚本

// ==UserScript==
// @name        New script baidu.com
// @namespace   Violentmonkey Scripts
// @match       https://pan.baidu.com/disk/main*
// @grant       none
// @version     1.0
// @author      -
// @description 2024/7/6 21:33:02
// ==/UserScript==
alert(111)

试着在默认的脚本里加一行脚本,点保存,刷新网盘页面试试,如果弹出了 111 弹框,说明插件脚本运行OK,可以继续进行下一步了。

证明脚本可以在网盘页面正常运行,那继续。

抓取网盘接口

接下来我们来看一下网盘的请求接口。

这个不排除后期厂商会调整接口地址或数据,大家知道逻辑了就可以以不变应万变了。

F12 控制台,选择网络,打开一个群组文件目录,好,第一个入口接口拿到了。

接下来点一个目录进到子目录,好,第二个接口也拿到了。

脚本的逻辑其实很简单,请求接口,处理响应数据,再迭代遍历目录,不断请求接口。

网盘请求总共用到 2 个接口。

  • 列出分享目录 listshare
  • 查看目录下的子目录 shareinfo

我写了一个乞丐版,凑合能用,等待大家进一步优化,注意替换第一个接口的请求地址及从第一个接口中提取出的几个重要参数(用来给第二个接口使用的)

将下面的脚本内容适当修改(注意改成你拥有的群组),贴到上面的暴力猴脚本编辑器中,保存并退出,刷新网盘页面,会出现一个“导出目录”按钮。 注意:一定要改成你自己的参数哟。

// ==UserScript==
// @name         网盘共享文件库目录清单导出
// @version      0.1
// @description  try to take over the world!
// @author       radapp
// @match        https://pan.baidu.com/*
// @grant        none
// @require      https://cdnjs.cloudflare.com/ajax/libs/FileSaver.js/1.3.3/FileSaver.min.js
// @require      https://cdn.bootcdn.net/ajax/libs/jquery/3.1.1/jquery.min.js
// @note         暴力转存网盘目录
// ==/UserScript==

(function () {
    // 获取你某个群组的 listshare 接口数据
    let listshareUrl = 'https://pan.baidu.com/mbox/group/listshare?clienttype=0&app_id=250528&web=1&dp-logid=27017400458903020070&type=2&gid=1005082622835627599&limit=50&desc=1'
    // 提取出来 listshare 接口中的必要参数,下一个 shareinfo 接口会用
    let clienttype = '0'
    let web = '1'
    let type = '2'
    let app_id = '250528'
    let dp_logid = '27017400458903020070'
    let gid = '1005082622835627599'

    // 获取群文件分享列表
    // 第一级目录只取了 50 条,如果不够,你再改逻辑
    function getListShare() {
        $.ajax({
            type: 'GET',
            url: listshareUrl,
            data: {},
            dataType: "json",
            async: false, // 禁用异步
            success: function (res) { // 响应内容可能会变,根据实际情况调整
                // console.log(res)
                if (res.errno !== 0) {
                    console.warn(res);
                    return;
                }
                // 分别递归获取第一级目录的子目录
                let msg_list = res.records.msg_list
                for (const msg of msg_list) {
                    let msg_id = msg.msg_id
                    let from_uk = msg.uk
                    // msg 对象中包含1个或多个file对象
                    let file_list = msg.file_list
                    for (const file_item of file_list) {
                        getShareInfo(msg_id, from_uk, file_item)
                    }
                }
            },
            error: function (err) {
                console.error(err);
            }
        });
    }

    // 阻塞睡眠一会,别请求太快,细水长流
    function sleep(time) {
        return new Promise((resolve) => setTimeout(resolve, time));
    }

    // 保存到自己的服务器后端接口
    function saveToDB(item) {
        $.ajax({
            type: 'POST',
            url: 'http://localhost:8080/api/file',
            data: JSON.stringify(item),
            contentType: "application/json",
            dataType: "json",
            async: true, // 自己的服务器,随便造
            success: function (res) {
                // 可选重试
            },
            error: function (err) {
                // console.error(err);
                // 可选重试
            }
        });
    }

    let count=0
    // 递归获取所有子目录
    async function getShareInfo(msg_id, from_uk, file_item, parent_id) {
        // console.log(file_item)
        let fs_id = file_item.fs_id
        let is_dir = file_item.isdir
        let path = file_item.path
        let server_filename = file_item.server_filename
        let size = file_item.size
        let server_ctime = file_item.server_ctime
        let server_mtime = file_item.server_mtime
        // console.log('开始获取 ' + server_filename + ' 相关资料')

        // 请求参数
        let postItem = {
            fileId: fs_id,
            fileName: server_filename,
            dir: is_dir === 1,
            parentFileId: parent_id,
            path: path,
            size: size,
            createTime: server_ctime * 1000,
            updateTime: server_mtime * 1000
        }
        count++
        console.log("save count:" + count)
        saveToDB(postItem)
        if (count > 100) {
            return
        }
        // 递归遍历目录
        if (is_dir) {
            // console.log(fs_id, server_filename, 'is dir, start get sub items.')
            let page = 1
            let shareinfoUrl = 'https://pan.baidu.com/mbox/msg/shareinfo' +
                '?from_uk=' + from_uk +
                '&msg_id=' + msg_id +
                '&type=' + type +
                '&num=50' +
                '&page=' + page +
                '&fs_id=' + fs_id +
                '&gid=' + gid +
                '&limit=50' +
                '&desc=1' +
                '&clienttype=' + clienttype +
                '&app_id=' + app_id +
                '&web=' + web +
                '&dp-logid=' + dp_logid
            // 请求子级目录文件列表
            // 每次请求停顿 0.5s 避免封控
            // console.log('sleep 500ms', new Date().getTime())
            await sleep(500);
            // console.log('开始获取第' + page + '页', new Date().getTime())
            $.ajax({
                type: 'POST',
                url: shareinfoUrl,
                data: {},
                dataType: "json",
                async: false, // 同步请求,降低频次,避免封控,慢点比封掉好
                success: function (res) {
                    // console.log(res)
                    if (res.errno !== 0) {
                        console.warn(res);
                        return;
                    }
                    // 记录当前目录下的文件
                    let file_list = []
                    res.records.filter(item => {
                        file_list.push(item)
                    })

                    // 如果有多页,继续请求更多页
                    // 递归请求更多文件
                    for (const sub_item of file_list) {
                        getShareInfo(msg_id, from_uk, sub_item, fs_id)
                    }
                },
                error: function (err) {
                    // console.error(err);
                }
            });
        } else {
            // console.log(fs_id, server_filename, 'is file, done.')
        }
    }

    // 添加导出按钮
    function addButton() {
        let myButton = $('<button type="button" class="u-button u-button--default u-button--mini" style="position: fixed;top: 58px;right: 48px;z-index: 9999;">导出目录</button>');
        $('body').append(myButton);
        myButton.click(getListShare);
    }

    addButton();


})()

我的脚步是将数据转发给了本地起的一个后端接口,用来将数据存到数据库了,大家直接看源码吧(乞丐版SpringBoot+JPA实现),没加任何逻辑,相当于裸奔,主要为了验证能跑通。

https://github.com/bytesops/examples4java/tree/main/007-pan-files-share

启动项目,执行页面上的“导出目录”按钮,看看转存的效果。

欢迎大家贡献思路和代码。公众号“新质程序猿”回复:网盘群,进小密圈交流,与大家一起共享你囤的好资料吧。

本次的分享到此结束,希望对你有所帮助。

如果你对我分享的内容感兴趣,欢迎扫码关注公众号:新质程序猿,并设置星标,推送更实时哟!

本文由 黄彦祥 创作,采用 知识共享署名 3.0 中国大陆许可协议 进行许可。
可自由转载、引用,但需署名作者且注明文章出处。