FollowingListOfBili

To get the following list

// ==UserScript==
// @name         FollowingListOfBili
// @namespace    http://tampermonkey.net/
// @version      0.1
// @description  To get the following list
// @author       Ouphi
// @match        https://space.bilibili.com/*/fans/follow*
// @icon         data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==
// @grant        none
// @license      MPL
// ==/UserScript==


/**
 * 全局or常用的变量名
 * 变量命名前缀:    n--num,    e--element, t--text
 *                  btn--button,    patt--pattern
 * 特殊变量:
 *          顾名思义:uid, fuids, fuid, href
 *          临时变量:i, j, k
 *          一些函数内变量,定义与使用相隔不远,可直观查看,不再赘述
 **/

var cnt = 0

// 页面固定信息
var href        =   "https://space.bilibili.com/208259/fans/follow" // 默认网址
var uid         =   "208259"            // 默认uid
var patt_uid    =   /.+\/([0-9]+)\/.*/  // 匹配uid的正则式

// 新增内容
var n_pages         =   -1          // 关注列表的页数
var fuids           =   new Array() // 关注人uid信息的列表
var btn_next        =   null        // “下一页”按钮元素
var btn_down        =   null        // 新增按钮,点击后可遍历内容
var e_father_down   =   null        // 新增按钮的父元素,用于确定位置

init()

// 设置初始页面,获取信息
function init(){
    console.log('2  ----    加载成功')

    // 获取页面信息
    href = window.location.href
    uid = regGroup(patt_uid, href)
    console.log('2  ----    当前用户:' + '\r' + uid)

    // 等待页面加载后,显示下载按钮
    btn_down = document.createElement('button')
    console.log(btn_down)
    waitingSetButton(btn_down)
}


function run(flag, next_flag, element, method, text, page) {

    console.log('2  ----    flag, next_flag :   ' +  flag + "," + next_flag)
    console.log('2  ----    page   :   ' + page)

    // 每隔0.1s判断一次加载进度
    if(flag == 0){
        var tmp = checkElement(document, method, text)
        if(tmp == null || (next_flag == 2 && checkUpdatingPage(page) == 0)){
            setTimeout(function(){run(0, next_flag, element, method, text, page)}, 100)
        }
        else
            run(next_flag, next_flag, element, method, text, page)
    }

    // 初始化,得到页数与next按钮
    if(flag == 1){
        if(run1GetAndResetPage() == 0) // 下一步
            run(0, 2, document, 'class', 'cover', 1)
        else    // 出现异常,等待加载
            setTimeout(function(){run(0, 1, document, 'class', 'be-pager-total', 1)}, 100)
    }

    // 遍历每一页,得到最终关注列表
    if(flag == 2){
        if(run2GetFollowingUids() != 0) return

        if(page == n_pages) // 最后一页
            run(4, 4, element, method, text, page)
        else // 继续加载下一页
            run(3, 3, element, method, text, page)
    }

    // 加载下一页
    if(flag == 3) {
        if(run3GoNextPage(page) != 0) return

        run(0, 2, document, 'class', 'cover', page + 1)
    }

    // 最后一页,保存数据
    if(flag == 4) {
        run4SaveDataAndReset()
    }
}

/***
 * 运行流程相关函数
 ***/

// TODO:验证关注列表为0的状况
// 1.得到页面信息,并返回到第一页
function run1GetAndResetPage(){
    var t_pages = document.getElementsByClassName("be-pager-total")[0].textContent
    n_pages = regGroup(/.+([0-9]+).+/, t_pages)
    console.log('2  ----    ' + '关注总页数:' + '   ' + n_pages)

    // 二次检测,因为出现了=0的状态
    if(n_pages == 0) return 1

    // 回到第一页,获取“下一页“按钮,以继续
    backFirstPage()
    btn_next = document.getElementsByClassName("be-pager-next")[0].children[0]
    return 0
}

// 2.得到当前页的uids
function run2GetFollowingUids(){
    var followings = document.getElementsByClassName("cover")
    for(var j = 0; j < followings.length; j++){
        var fuid = regGroup(patt_uid, followings[j].attributes['href'].nodeValue)
        fuids[fuids.length] = fuid
    }
    return 0
}

// 3.点击下一页
function run3GoNextPage(page){
    btn_next.click()

    // 一个其实没必要的冗余判断
    if(page + 1 > n_pages) return 1

    return 0
}

// 4.保存数据并解锁下载按钮
function run4SaveDataAndReset(){
    // 结束,将得到的uids文件保存到本地
    console.log('2  ----\n')
    console.log('fuids  :   ' + fuids.length + '\n' + fuids)

    // 得到uid文本内容,并表示为二进制数据
    // 第一行是关注总数目
    var t_fuid = fuids.length + '\n' + fuids.join('\n')
    // 由于bili的限制,不能用blob(blob的url简单),暂用data代替(url中包括完整文件)
    downloadFile(t_fuid)

    // 解锁下载按钮,可以重新下载
    resetButton(btn_down)
    console.log('2  ----    ' + '结束下载')
    return 0
}


/****
 * 按钮相关函数
 ****/

 function waitingSetButton(btn){
    console.log(btn)

    var elements = document.getElementsByClassName("follow-main")
    if(elements == null || elements == undefined || elements.length == 0){
        setTimeout(function(){waitingSetButton(btn)}, 100)
    }
    else{
        setButton(btn)
    }
}

function setButton(btn){
    console.log(btn)
    // setTimeout不能嵌套
    e_father_down = document.getElementsByClassName("follow-main")[0]
    btn.innerHTML = '下载列表'
    btn.style.width = '100px'
    btn.style.height = '30px'
    btn.style.fontSize = '16px'
    btn.style.color = '#FFFFFF'
    btn.style.background = '#99CCFF'
    btn.style.borderRadius = '7px'
    btn.style.borderWidth = '0px'
    btn.id = 'download-following-list-button'
    btn.onclick = function(){clickButton(btn)}
    e_father_down.insertBefore(btn, e_father_down.childNodes[1])
}

function clickButton(btn){
    btn.disabled = true
    btn.style.background = '#999999'
    // 此处不传btn参数,默认为btn_down;如果需要复用,需要改写
    run(0, 1, document, 'class', 'be-pager-total', 1)
}

function resetButton(btn){
    fuids.length = 0
    btn.disabled = false
    btn.style.background = '#99CCFF'
}


/****
 * 元素处理函数
 *****/

// 保存信息
function downloadFile(text){
    // var fuid_href = 'data:text/txt;charset=utf-8,\ufeff' + encodeURIComponent(fuid_text)
    // 如果想下载为文件,可以使用上面的代码(bilibili不支持blob下载),并将元素p改为元素a,最后加个click就好了
    var p = checkElement(document, 'id', 'following-list-text')
    if(p != null) p.remove()

    // 利用a元素,为二进制数据设置临时url,实现下载
    var p_father = document.body
    p = document.createElement('p')
    p.id = 'following-list-text'
    p.textContent = text
    // 如果需要直观查看,可以将这行注释掉,或改为block
    p.style.display = 'none'
    p_father.appendChild(p, p_father)
}

// 返回第一页
function backFirstPage(){
    // 回车事件
    var event = new Event('keyup')
    event = Object.assign(event, {
        ctrlKey: false,
        metaKey: false,
        altKey: false,
        which: 13,
        keyCode: 13,
        key: 'Enter',
        code: 'Enter'
    })

    // 重新跳转到起始页
    var e_banner = document.getElementsByClassName("be-pager-options-elevator")[0]
    var e_input = e_banner.getElementsByClassName("space_input")[0]
    e_input.value = '1'
    // e_input.focus()
    e_input.dispatchEvent(event)
}



/****
 * 等待相关函数
 ****/

// 检查所需元素是否已加载成功
 function checkElement(element, method, text){
    if(element == null) return null

    var result = null
    switch(method){
        case 'class':
            result = element.getElementsByClassName(text)
            break
        case 'tag':
            result = element.getElementsByTagName(text)
            break
        case 'id':
            result = element.getElementById(text)
            break
        default:
            result = element.getElementsByClassName(text)
            break
    }

    if(result != null && result != undefined && result.length != 0){
        return result
    }else{
        return null
    }
}

// 检查页面转换(解决有时会出现链接变了,元素能获取,但还未来得及更新的状况)
function checkUpdatingPage(page){

    var e_page_num = document.getElementsByClassName('be-pager-item be-pager-item-active')[0]

    var following = document.getElementsByClassName("cover")[0]
    var fuid = regGroup(patt_uid, following.attributes['href'].nodeValue)

    if(page.toString() == e_page_num.textContent && fuids.indexOf(fuid) == -1){
        return 1
    }
    return 0

}

/****
 * 一些小函数
 ****/


// 正则匹配
function regGroup(patt, text){
    var matched_str = text.match(patt)
    var result = RegExp.$1
    return result
}

QingJ © 2025

镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址