nilaoda / BBDown

Bilibili Downloader. 一个命令行式哔哩哔哩下载器.
MIT License
9.93k stars 1.29k forks source link

轮询哔哩哔哩API的设想 #915

Open BlueSkyXN opened 3 months ago

BlueSkyXN commented 3 months ago

1. 你使用的BBDown版本是什么?(指明 Release / Actions / DotnetTool)

最新Action

2. 你在什么系统使用本软件?(Win/Linux/Mac)

Win

3. 你使用的完整命令是什么?

BBDown  -info xxx

4. 遇到了什么问题?

我注意到近期明显提升了 https://api.bilibili.com/x/player/wbi/playurl 这个接口的风控水平,很容易触发风控

5. 运行截图(最好开启--debug;注意自行将Cookie/Token等敏感信息隐藏)

风控时的接口返回 {"code":0,"message":"0","ttl":1,"data":{"v_voucher":"voucher_UUID"}} 这样的拦截

我测试后发现,哔哩哔哩的3个API域名似乎风控是不互通的,并不完全一致

域名有

  1. https://api.bilibili.com
  2. https://api.biliapi.com
  3. https://api.biliapi.net

根据之前的经验,我认为他们功能完全一致 也许,可以做一个随机(和开关、指定),参考UA

BlueSkyXN commented 3 months ago
import requests
import random

app = Flask(__name__)

api_urls = [
    'https://api.bilibili.com/x/player/wbi/playurl',
    'https://api.biliapi.net/x/player/wbi/playurl',
    'https://api.biliapi.com/x/player/wbi/playurl'
]

redirect_domains = [
    'https://api.biliapi.net',
    'https://api.biliapi.com'
]

@app.route('/x/player/wbi/playurl', methods=['GET'])
def handle_specific_path():
    query_string = request.query_string.decode('utf-8')
    headers = {key: value for key, value in request.headers if key.lower() != 'host'}

    response = None
    success = False

    for url in api_urls:
        try:
            resp = requests.get(f"{url}?{query_string}", headers=headers)
            if resp.status_code == 200:
                data = resp.json()
                if 'v_voucher' in data.get('data', {}):
                    # 检测到风控信息,尝试下一个URL
                    continue
                else:
                    # 正常响应
                    response = resp
                    success = True
                    break
        except requests.RequestException as e:
            continue

    if success:
        return jsonify(response.json()), response.status_code
    else:
        return jsonify(response.json()), response.status_code

@app.route('/', defaults={'path': ''})
@app.route('/<path:path>', methods=['GET', 'POST', 'PUT', 'DELETE'])
def handle_all_requests(path):
    base_url = random.choice(redirect_domains)
    target_url = f"{base_url}/{path}"

    if request.query_string:
        target_url += f"?{request.query_string.decode('utf-8')}"

    return redirect(target_url, code=302)

if __name__ == '__main__':
    app.run(port=5001)

我目前的策略是在服务器起一个https-python-flask项目,监听 api.bilibili.com,对于这个接口使用代理检测,对于其他接口返回302到备用域名,目前看上去工作是正常的

(话说这三域名在华为云能直接用)

BlueSkyXN commented 3 months ago

目前能确定这个风控实装时间是 2024年7月下旬-2024年8月上旬 因为我在7月中旬随便并发境内外下载从未出现这个限制。(我备份到谷歌网盘时标记的时间是2024年7月18日) 屏幕截图 2024-08-07 105610 当然,这三个api域名是否真的完全一致目前并不确定,但是我还没发现不兼容的情况,需要更多案例数据。

同时我有一个实测案例,就是我在2024年7月18日上午开始进行爬虫抓BV调试,当日10:31完成爬虫设计 屏幕截图 2024-08-07 110041 当日17:36完成UP主原神的全部视频下载,从境外下载,一共1103个视频103GB大小。 屏幕截图 2024-08-07 110050 期间从未出现风控的情况。我本地也把我自己的视频几百个合计大几百G直接下载下来,期间未出现风控。

moonbow721 commented 3 months ago

最近因为下载视频需求比较大,老被风控,返回v_voucher那样的拦截。目前只能设置一些代理服务器,期待实装!