哔哩哔哩直播链接报403解决办法

最近投屏接到客诉说苹果哔哩哔哩客户端投直播会显示播放失败。

我测试发现安卓端哔哩哔哩是正常的,某投屏软件也能正常播放,我对此感到困惑。通过tcpdump分析,发现它的ijk播放器在访问链接时改变了User Agent。

然后我就开始测试了:

headers.put("User-Agent", "Mozilla/5.0.BiliTV/1.7.2"); //正常
headers.put("User-Agent", "Bilibili Freedoooooom/MarkII");//正常
headers.put("User-Agent", "Linux Androi");//正常
headers.put("User-Agent", "Android");//403 forbidden
headers.put("User-Agent", "stagefright");//403 forbidden
headers.put("User-Agent", "a");//正常
headers.put("User-Agent", "Androi");//正常
headers.put("User-Agent", "stagefrigh");//正常

经测试发现含有Android或者stagefright都会导致访问403,其他都正常。

而安卓默认的User Agent就包含了Android和stagefright。

AString MakeUserAgent() {
    AString ua;
    ua.append("stagefright/1.2 (Linux;Android ");
#if (PROPERTY_VALUE_MAX < 8)
#error "PROPERTY_VALUE_MAX must be at least 8"
#endif
    char value[PROPERTY_VALUE_MAX];
    property_get("ro.build.version.release", value, "Unknown");
    ua.append(value);
    ua.append(")");
    return ua;
}

解决

既然知道了问题原因,那么解决起来就很简单了,当判断是哔哩哔哩的直播链接时,改变播放器的user agent。

ijk播放器

mIjkPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_FORMAT, "user_agent", "Bilibili Freedoooooom/MarkII");

MediaPlayer播放器

headers.put("User-Agent", "Bilibili Freedoooooom/MarkII");
mPlayer.setDataSource(this, Uri.parse(videoUrl), headers);

注意,由于谷歌的bug,安卓5.0和5.1不支持该设置

[MediaPlayer ignores User-Agent header 37018604] - Issue Tracker

…/MediaHTTP.cpp · Gerrit Code Review

其他

当然也可以通过本地代理来解决,拦截播放请求就可以随意改变user agent了,这也可以解决安卓5.0以下MediaPlayer不支持某些tls版本的问题。

参考链接:

哔哩哔哩视频403Forbidden原因

浅度剖析B站的新 -352 风控策略 - A Salty Blog

获取和处理直播的 m3u8 视频流需要结合网络请求、解析以及可能的视频流下载或转码操作。以下是实现步骤和技术要点: ### 获取直播的 m3u8 视频流 1. **分析直播页面源码或通过接口获取直播流地址** 哩的直播流通常通过特定 API 提供,例如: ``` https://api.live.bilibili.com/xlive/web-room/v2/index/getRoomPlayInfo ``` 该接口可以通过房间号(room_id)获取直播间的播放信息,其中包含 m3u8 格式的播放地址。 2. **使用 Python 发送 HTTP 请求并提取 m3u8 地址** 通过 `requests` 库发送 GET 请求,并解析返回的 JSON 数据以提取 m3u8 流地址。以下是一个示例代码片段: ```python import requests def get_bilibili_live_stream(room_id): url = "https://api.live.bilibili.com/xlive/web-room/v2/index/getRoomPlayInfo" params = { "room_id": room_id, "protocol": "0,1", "format": "0,1,2", "codec": "0,1", "qn": 10000, "platform": "web", "ptype": 8 } headers = { "User-Agent": "Mozilla/5.0" } response = requests.get(url, params=params, headers=headers) data = response.json() stream_url = data['data']['play_url'] return stream_url ``` 该函数将返回直播间对应的 m3u8 视频流地址。 3. **验证 m3u8 地址是否有效** 使用 `m3u8` 模块检查返回的 m3u8 链接是否可解析: ```python import m3u8 def validate_m3u8(url): playlist = m3u8.load(url) if playlist.is_variant: for sub_playlist in playlist.playlists: print(f"Found variant stream: {sub_playlist.uri}") else: print("Stream is valid and contains segments:") for segment in playlist.segments: print(segment.uri) ``` ### 处理 m3u8 视频流 1. **使用 ffmpeg 下载 m3u8 并转换为 MP4 文件** 在本地安装好 `ffmpeg` 后,可以使用命令行工具直接下载并合并 m3u8 流为 MP4 文件: ```bash ffmpeg -i "直播流地址.m3u8" -c copy output.mp4 ``` 如果需要在 Python 中调用 ffmpeg,则可以使用 `subprocess` 模块: ```python import subprocess def download_and_convert(stream_url, output_file="output.mp4"): command = [ "ffmpeg", "-i", stream_url, "-c", "copy", output_file ] subprocess.run(command) ``` 2. **实时录制直播流** 可以设置一个定时任务或循环脚本,持续监控直播状态并在直播结束后自动保存文件。 3. **多清晰度处理** 若直播提供多种清晰度选项(如高清、超清等),可以在请求参数中调整 `qn` 参数值,例如: - `qn=10000` 表示最高画质 - `qn=400` 表示标清 4. **处理加密 m3u8 流** 如果直播流被 AES-128 加密,则需额外处理解密过程。`ffmpeg` 支持自动检测并解密,前提是提供正确的密钥 URL 或嵌入在 m3u8 文件中。 ### 示例整合:完整流程代码 ```python import requests import m3u8 import subprocess def get_bilibili_live_stream(room_id): url = "https://api.live.bilibili.com/xlive/web-room/v2/index/getRoomPlayInfo" params = { "room_id": room_id, "protocol": "0,1", "format": "0,1,2", "codec": "0,1", "qn": 10000, "platform": "web", "ptype": 8 } headers = { "User-Agent": "Mozilla/5.0" } response = requests.get(url, params=params, headers=headers) data = response.json() stream_url = data['data']['play_url'] return stream_url def validate_m3u8(url): playlist = m3u8.load(url) if playlist.is_variant: for sub_playlist in playlist.playlists: print(f"Found variant stream: {sub_playlist.uri}") else: print("Stream is valid and contains segments:") for segment in playlist.segments: print(segment.uri) def download_and_convert(stream_url, output_file="output.mp4"): command = [ "ffmpeg", "-i", stream_url, "-c", "copy", output_file ] subprocess.run(command) if __name__ == "__main__": room_id = input("请输入直播间号:") stream_url = get_bilibili_live_stream(room_id) print(f"直播流地址:{stream_url}") validate_m3u8(stream_url) download_and_convert(stream_url) ``` ###
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值