# Source: https://github.com/CN-Grace/QinglongScripts/blob/main/Bilibili.py # Raw: https://raw.githubusercontent.com/CN-Grace/QinglongScripts/main/Bilibili.py # Repo: CN-Grace/QinglongScripts # Path: Bilibili.py # UploadedAt: 2026-05-23T15:48:24Z # SHA256: 3f2f0084618aefdba5d3f7361244ebec508c7db5a09cbe80d0b8170bb5d2d27f # Category: web版/抓包 # Evidence: web/H5关键词 + cookie/token/header #!/usr/bin/env python3 """ cron: 0 0 * * * new Env("B站每日任务") Bilibili 每日任务脚本 - 漫画签到 - 投币任务(支持指定投币数和投币来源) - 观看视频任务 - 分享视频任务 - 银瓜子兑换硬币(可选) - 获取今日经验、当前经验、预计升级天数 """ import os import time import requests from utils import log_info, log_success, log_warning, log_error, beijing_time_str from notifier import send as notify_send # ==================== 用户配置 ==================== BILIBILI_COOKIE = os.environ.get("BILIBILI_COOKIE", "") COIN_NUM = int(os.environ.get("BILIBILI_COIN_NUM", "0")) COIN_TYPE = int(os.environ.get("BILIBILI_COIN_TYPE", "1")) SILVER2COIN = os.environ.get("BILIBILI_SILVER2COIN", "false").lower() == "true" report_data = {} # ---------- Bilibili API ---------- def get_nav(session): """获取用户导航信息""" url = "https://api.bilibili.com/x/web-interface/nav" ret = session.get(url=url).json() data = ret.get("data", {}) return data.get("uname"), data.get("mid"), data.get("isLogin"), data.get("money"), data.get("vipType"), data.get("level_info", {}).get("current_exp") def get_today_exp(session): """获取今日经验明细""" url = "https://api.bilibili.com/x/member/web/exp/log?jsonp=jsonp" today = beijing_time_str("%Y-%m-%d") try: data_list = session.get(url=url).json().get("data", {}).get("list", []) return list(filter(lambda x: x["time"].split()[0] == today, data_list)) except Exception: return [] def manga_sign(session, platform="android"): """漫画签到""" try: url = "https://manga.bilibili.com/twirp/activity.v1.Activity/ClockIn" ret = session.post(url=url, data={"platform": platform}).json() if ret["code"] == 0: return "✅ 签到成功" elif ret.get("msg") == "clockin clockin is duplicate": return "✅ 今天已经签到过了" else: msg = f"❌ 签到失败: {ret.get('msg', '未知错误')}" log_error(msg) return msg except Exception as e: msg = f"❌ 签到异常: {e!s}" log_error(msg) return msg def report_task(session, bili_jct, aid, cid, progres=300): """上报视频观看进度""" url = "http://api.bilibili.com/x/v2/history/report" return session.post(url=url, data={"aid": aid, "cid": cid, "progres": progres, "csrf": bili_jct}).json() def share_task(session, bili_jct, aid): """分享视频""" url = "https://api.bilibili.com/x/web-interface/share/add" return session.post(url=url, data={"aid": aid, "csrf": bili_jct}).json() def get_followings(session, uid, pn=1, ps=50, order="desc", order_type="attention"): """获取关注的 up 主列表""" params = {"vmid": uid, "pn": pn, "ps": ps, "order": order, "order_type": order_type} return session.get(url="https://api.bilibili.com/x/relation/followings", params=params).json() def space_arc_search(session, uid, pn=1, ps=30, tid=0, order="pubdate", keyword=""): """获取指定 up 主的视频投稿""" params = {"mid": uid, "pn": pn, "Ps": ps, "tid": tid, "order": order, "keyword": keyword} ret = session.get(url="https://api.bilibili.com/x/space/arc/search", params=params).json() data_list = [ {"aid": one.get("aid"), "cid": 0, "title": one.get("title"), "owner": one.get("author")} for one in ret.get("data", {}).get("list", {}).get("vlist", [])[:2] ] return data_list, 2 def coin_add(session, bili_jct, aid, num=1, select_like=1): """给视频投币""" url = "https://api.bilibili.com/x/web-interface/coin/add" return session.post(url=url, data={"aid": aid, "multiply": num, "select_like": select_like, "cross_domain": "true", "csrf": bili_jct}).json() def live_status(session): """获取直播瓜子状态""" ret = session.get(url="https://api.live.bilibili.com/pay/v1/Exchange/getStatus").json() data = ret.get("data", {}) return {"coin": data.get("coin", 0), "gold": data.get("gold", 0), "silver": data.get("silver", 0)} def get_region(session, rid=1, num=6): """获取分区视频列表""" url = f"https://api.bilibili.com/x/web-interface/dynamic/region?ps={num}&rid={rid}" ret = session.get(url=url).json() return [{"aid": one.get("aid"), "cid": one.get("cid"), "title": one.get("title"), "owner": one.get("owner", {}).get("name")} for one in ret.get("data", {}).get("archives", [])] def silver2coin(session, bili_jct): """银瓜子兑换硬币""" url = "https://api.live.bilibili.com/xlive/revenue/v1/wallet/silver2coin" return session.post(url=url, data={"csrf": bili_jct}).json() def main(): global report_data report_data = {} bilibili_cookie = {item.split("=")[0]: item.split("=")[1] for item in BILIBILI_COOKIE.split("; ")} bili_jct = bilibili_cookie.get("bili_jct") session = requests.session() requests.utils.add_dict_to_cookiejar(session.cookies, bilibili_cookie) session.headers.update({ "user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36 Edg/91.0.864.64", "Referer": "https://www.bilibili.com/", "accept-language": "zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6", "Connection": "keep-alive", }) uname, uid, is_login, coin, vip_type, current_exp = get_nav(session=session) if not is_login: log_error("登录失败,请检查 cookie") return "登录失败,请检查 cookie" log_success(f"登录成功,用户名: {uname},UID: {uid},当前硬币: {coin}") report_data["账号"] = uname # 漫画签到 manhua_msg = manga_sign(session=session) log_info(f"漫画签到: {manhua_msg}") report_data["漫画签到"] = manhua_msg # 获取分区视频列表 aid_list = get_region(session=session) # 计算今日已投币数 today_exp_list = get_today_exp(session=session) coins_av_count = len(list(filter(lambda x: x.get("reason") == "视频投币奖励", today_exp_list))) need_coin_num = COIN_NUM - coins_av_count need_coin_num = need_coin_num if need_coin_num < coin else coin log_info(f"今日已投币 {coins_av_count} 个,目标投币 {COIN_NUM} 个,还需投 {need_coin_num} 个") # 根据 coin_type 选择投币来源 if COIN_TYPE == 1: following_list = get_followings(session=session, uid=uid) count = 0 for following in following_list.get("data", {}).get("list", []): mid = following.get("mid") if mid: tmplist, tmpcount = space_arc_search(session=session, uid=mid) aid_list += tmplist count += tmpcount if count > need_coin_num: log_info("已获取足够关注用户的视频") break else: aid_list += get_region(session=session) # 投币循环 success_count = 0 if need_coin_num > 0: for one in aid_list[::-1]: ret = coin_add(session=session, aid=one.get("aid"), bili_jct=bili_jct) if ret.get("code") == 0: need_coin_num -= 1 log_success(f"成功给《{one.get('title')}》投一个币") success_count += 1 elif ret.get("code") == 34005: log_warning(f"投币《{one.get('title')}》失败: {ret.get('message')},继续下一个") continue else: log_error(f"投币《{one.get('title')}》失败: {ret.get('message')},跳过投币") break if need_coin_num <= 0: break coin_msg = f"今日成功投币 {success_count + coins_av_count}/{COIN_NUM} 个" else: coin_msg = f"今日成功投币 {coins_av_count}/{COIN_NUM} 个" log_info(coin_msg) report_data["投币任务"] = coin_msg # 观看视频任务 if aid_list: first = aid_list[0] report_ret = report_task(session=session, bili_jct=bili_jct, aid=first.get("aid"), cid=first.get("cid")) report_msg = f"✅ 观看《{first.get('title')}》300秒" if report_ret.get("code") == 0 else "❌ 观看任务失败" log_success(report_msg) if report_ret.get("code") == 0 else log_error(report_msg) share_ret = share_task(session=session, bili_jct=bili_jct, aid=first.get("aid")) share_msg = f"✅ 分享《{first.get('title')}》成功" if share_ret.get("code") == 0 else "❌ 分享失败" log_success(share_msg) if share_ret.get("code") == 0 else log_error(share_msg) else: report_msg = "⚠️ 无视频可观看"; share_msg = "⚠️ 无视频可分享" log_warning(report_msg); log_warning(share_msg) report_data["观看视频"] = report_msg report_data["分享任务"] = share_msg # 银瓜子兑换硬币 s2c_msg = "⚪ 未开启兑换" if SILVER2COIN: silver2coin_ret = silver2coin(session=session, bili_jct=bili_jct) if silver2coin_ret.get("code") == 0: s2c_msg = "✅ 银瓜子兑换硬币成功" log_success(s2c_msg) else: s2c_msg = f"❌ 兑换失败: {silver2coin_ret.get('message', '未知错误')}" log_error(s2c_msg) report_data["瓜子兑换"] = s2c_msg # 获取直播瓜子状态 live_stats = live_status(session=session) report_data["硬币数量"] = live_stats["coin"] report_data["金瓜子数"] = live_stats["gold"] report_data["银瓜子数"] = live_stats["silver"] # 再次获取用户信息,更新经验 uname, uid, is_login, new_coin, vip_type, new_current_exp = get_nav(session=session) today_exp = sum(map(lambda x: x.get("delta", 0), get_today_exp(session=session))) update_data = (28800 - new_current_exp) // (today_exp if today_exp else 1) if today_exp else "未知" report_data["今日经验"] = today_exp report_data["当前经验"] = new_current_exp report_data["升级还需"] = f"{update_data}天" log_success("========== 任务执行汇总 ==========") for k, v in report_data.items(): log_info(f"{k}: {v}") return report_data def build_report(data): """构建签到报告""" lines = ["🎯 Bilibili 每日任务报告", "", f"👤 账号: {data.get('账号', '未知')}", ""] tasks = [ ("📖 漫画签到", data.get("漫画签到", "")), ("📺 观看视频", data.get("观看视频", "")), ("🔗 分享任务", data.get("分享任务", "")), ("💰 投币任务", data.get("投币任务", "")), ("💱 瓜子兑换", data.get("瓜子兑换", "")), ] for name, value in tasks: lines.append(f"{name}: {value}") lines.append("") lines.append("📊 数据统计") lines.append(f"⭐ 今日经验: {data.get('今日经验', 0)}") lines.append(f"📈 当前经验: {data.get('当前经验', 0)}") lines.append(f"⏳ 升级还需: {data.get('升级还需', '未知')}") lines.append("") lines.append("🥜 瓜子库存") lines.append(f"🪙 硬币数量: {data.get('硬币数量', 0)}") lines.append(f"✨ 金瓜子数: {data.get('金瓜子数', 0)}") lines.append(f"🥈 银瓜子数: {data.get('银瓜子数', 0)}") lines.append("") lines.append("─" * 18) lines.append(f"🕒 执行时间: {beijing_time_str()}") return "\n".join(lines) if __name__ == "__main__": report = main() if report and isinstance(report, dict): tg_text = build_report(report) notify_send("Bilibili 每日任务报告", tg_text)