├── .gitignore ├── .idea └── inspectionProfiles │ └── Project_Default.xml ├── README.md ├── bilibili.py └── file └── tid.txt /.gitignore: -------------------------------------------------------------------------------- 1 | # Byte-compiled / optimized / DLL files 2 | __pycache__/ 3 | *.py[cod] 4 | *$py.class 5 | 6 | # C extensions 7 | *.so 8 | 9 | # Distribution / packaging 10 | .Python 11 | build/ 12 | develop-eggs/ 13 | dist/ 14 | downloads/ 15 | eggs/ 16 | .eggs/ 17 | lib/ 18 | lib64/ 19 | parts/ 20 | sdist/ 21 | var/ 22 | wheels/ 23 | *.egg-info/ 24 | .installed.cfg 25 | *.egg 26 | MANIFEST 27 | 28 | # PyInstaller 29 | # Usually these files are written by a python script from a template 30 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 31 | *.manifest 32 | *.spec 33 | 34 | # Installer logs 35 | pip-log.txt 36 | pip-delete-this-directory.txt 37 | 38 | # Unit test / coverage reports 39 | htmlcov/ 40 | .tox/ 41 | .coverage 42 | .coverage.* 43 | .cache 44 | nosetests.xml 45 | coverage.xml 46 | *.cover 47 | .hypothesis/ 48 | .pytest_cache/ 49 | 50 | # Translations 51 | *.mo 52 | *.pot 53 | 54 | # Django stuff: 55 | *.log 56 | local_settings.py 57 | db.sqlite3 58 | 59 | # Flask stuff: 60 | instance/ 61 | .webassets-cache 62 | 63 | # Scrapy stuff: 64 | .scrapy 65 | 66 | # Sphinx documentation 67 | docs/_build/ 68 | 69 | # PyBuilder 70 | target/ 71 | 72 | # Jupyter Notebook 73 | .ipynb_checkpoints 74 | 75 | # pyenv 76 | .python-version 77 | 78 | # celery beat schedule file 79 | celerybeat-schedule 80 | 81 | # SageMath parsed files 82 | *.sage.py 83 | 84 | # Environments 85 | .env 86 | .venv 87 | env/ 88 | venv/ 89 | ENV/ 90 | env.bak/ 91 | venv.bak/ 92 | 93 | # Spyder project settings 94 | .spyderproject 95 | .spyproject 96 | 97 | # Rope project settings 98 | .ropeproject 99 | 100 | # mkdocs documentation 101 | /site 102 | 103 | # mypy 104 | .mypy_cache/ 105 | -------------------------------------------------------------------------------- /.idea/inspectionProfiles/Project_Default.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 20 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # python-bilibili-api 2 | bilibili-api 3 | -------------------------------------------------------------------------------- /bilibili.py: -------------------------------------------------------------------------------- 1 | import base64 2 | import json 3 | import re 4 | import sys 5 | import time 6 | 7 | import requests 8 | 9 | 10 | class Channel: 11 | id = None # 频道id 12 | owner = None # 所有者mid 13 | name = None # 频道名称 14 | intro = None # 频道介绍 15 | ctime = None # 频道创建时间 16 | video_count = None # 频道中视频的数量 17 | cover = None # 频道封面 18 | 19 | 20 | class Video: 21 | aid = None # 视频编号 22 | videos = None # 分p数 23 | tid = None # 所属分区编号 24 | copyright = None # 1.自制 2.搬运 25 | pic = None # 封面 26 | title = None # 标题 27 | pubdate = None # 发布日期 28 | ctime = None # 提交日期 29 | description = None # 简介 30 | state = None # 稿件状态 0.正常 -4.撞车(?) 31 | forward = None # 撞车跳转的目标 32 | attribute = None # (?)不详 33 | duration = None # 持续时间,单位为秒 34 | owner_mid = None # 作者mid 35 | stat_view = None # 播放次数 36 | stat_danmaku = None # 弹幕数 37 | stat_reply = None # 回复数 38 | stat_favorite = None # 收藏数 39 | stat_coin = None # 投币数 40 | stat_share = None # 分享数 41 | stat_now_rank = None # 当前排名 42 | stat_his_rank = None # 历史最高排名 43 | stat_like = None # 点赞数 44 | stat_dislike = None # 踩的次数 45 | dynamic = None # 在动态显示的文本 46 | cids = None # 所有分p的cid 47 | access = None # 观看所需权限 48 | 49 | 50 | class VideoPart: 51 | cid = None # 分p的cid 52 | page = None # 分p序号 53 | vfrom = None # 视频来源 54 | part = None # 分p标题 55 | duration = None # 持续时间 56 | vid = None # 不详 57 | weblink = None # 不详 58 | width = None # 视频宽度 59 | height = None # 视频高度 60 | rotate = None # 不详 61 | 62 | 63 | class User: 64 | archive_count = None # 稿件数量 65 | article_count = None # 文章数量 66 | follower = None # 粉丝数量 67 | mid = None # 用户ID 68 | name = None # 用户名称 69 | approve = None # 不详 70 | sex = None # 性别 71 | rank = None # 权限等级 72 | face = None # 头像 73 | DisplayRank = None # 不详 74 | regtime = None # 注册时间 75 | spacesta = None # 账户状态 76 | birthday = None # 生日 77 | place = None # 所在地区 78 | description = None # 不详 79 | article = None # 不详 80 | fans = None # 粉丝数 81 | friend = None # 关注数 82 | attention = None # 关注数 83 | sign = None # 签名 84 | current_level = None # 当前等级 85 | pendant_pid = None # 头像边框ID 86 | pendant_expire = None # 头像边框过期时间 87 | nameplate_nid = None # 勋章ID 88 | Official_role = None # 不详 89 | Official_title = None # 不详 90 | Official_desc = None # 不详 91 | official_verify_type = None # 认证类别0.个人认证 92 | official_verify_desc = None # 认证描述 93 | vip_vipType = None # 大会员类型 94 | vip_dueRemark = None # 不详 95 | vip_accessStatus = None # 不详 96 | vip_vipStatus = None # 大会员状态 97 | vip_vipStatusWarn = None # 不详 98 | 99 | 100 | class Bilibili: 101 | def __init__(self): 102 | self.session = requests.session() 103 | self.csrf = None 104 | 105 | def login(self, username, password): 106 | """ 107 | 调用第三方API,请谨慎使用 108 | 详情见:http://docs.kaaass.net/showdoc/web/#/2?page_id=3 109 | :param username:登录的用户名 110 | :param password:密码 111 | :return: 112 | """ 113 | req = self.post( 114 | url='https://api.kaaass.net/biliapi/user/login', 115 | data={ 116 | 'user': username, 117 | 'passwd': password 118 | } 119 | ) 120 | if req['status'] == 'OK': 121 | login = self.get( 122 | url='https://api.kaaass.net/biliapi/user/sso', 123 | params={ 124 | 'access_key': req['access_key'] 125 | } 126 | ) 127 | if login['status'] == 'OK': 128 | print(login['cookie']) 129 | cookies = {} 130 | for line in login['cookie'].split(';')[:-1]: 131 | name, value = line.strip().split('=') 132 | cookies[name] = value 133 | cookies = requests.utils.cookiejar_from_dict(cookies, cookiejar=None, overwrite=True) 134 | self.session.cookies = cookies 135 | self.csrf = self.session.cookies.get('bili_jct') 136 | return True 137 | else: 138 | return login 139 | 140 | def login_by_cookies(self, path): 141 | with open(path, 'r') as f: 142 | cookies = {} 143 | for line in f.read().split(';'): 144 | name, value = line.strip().split('=', 1) 145 | cookies[name] = value 146 | cookies = requests.utils.cookiejar_from_dict(cookies, cookiejar=None, overwrite=True) 147 | self.session.cookies = cookies 148 | print(cookies) 149 | self.csrf = self.session.cookies.get('bili_jct') 150 | print("Cookies设置成功") 151 | 152 | def isLogin(self): 153 | req = self.get('https://api.vc.bilibili.com/feed/v1/feed/get_attention_list') 154 | code = req['code'] 155 | if code == 0: 156 | print("[提示]登录成功!") 157 | return True 158 | else: 159 | print("[提示]cookies失效!") 160 | print("[提示]登录返回信息为:" + str(req)) 161 | sys.exit(1) 162 | 163 | def post(self, url, data, headers=None, params=None): 164 | while True: 165 | try: 166 | if headers is None: 167 | if params is None: 168 | req = self.session.post(url, data=data,timeout=99999) 169 | else: 170 | req = self.session.post(url, data=data, params=params,timeout=99999) 171 | else: 172 | if params is None: 173 | req = self.session.post(url, data=data, headers=headers,timeout=99999) 174 | else: 175 | req = self.session.post(url, data=data, headers=headers, params=params,timeout=99999) 176 | # print(req.url) 177 | if req.status_code == 200: 178 | try: 179 | return req.json() 180 | except Exception as e: 181 | print("[POST][提示]JSON化失败:"+str(e)+"\n[提示]内容为:"+req.text) 182 | return req.text 183 | else: 184 | print("[提示]状态码为"+str(req.status_code)+"!请检查错误\n[提示]" + req.text) 185 | sys.exit(0) 186 | except Exception as e: 187 | print("[提示]POST出错\n[提示]%s" % str(e)) 188 | 189 | def get(self, url, params=None, headers=None): 190 | while True: 191 | try: 192 | if params is None: 193 | if headers is None: 194 | req = self.session.get(url, timeout=5) 195 | else: 196 | req = self.session.get(url, headers=headers, timeout=5) 197 | else: 198 | if headers is None: 199 | req = self.session.get(url, params=params, timeout=5) 200 | else: 201 | req = self.session.get(url, params=params, headers=headers, timeout=5) 202 | if req.status_code == 200: 203 | try: 204 | # print(req.text) 205 | return req.json() 206 | except Exception as e: 207 | # print("[GET][提示]JSON化失败:" + str(e) + "\n[提示]内容为:" + req.text) 208 | return req.content.decode('utf-8') 209 | else: 210 | print("[提示]状态码为" + str(req.status_code) + "!请检查错误\n[提示]" + req.text) 211 | # sys.exit(0) 212 | time.sleep(1) 213 | except Exception as e: 214 | print("[提示]GET出错\n[提示]%s" % str(e)) 215 | 216 | def options(self, url, params=None, headers=None): 217 | while True: 218 | try: 219 | if params is None: 220 | if headers is None: 221 | req = self.session.options(url, timeout=5) 222 | print() 223 | else: 224 | req = self.session.options(url, headers=headers, timeout=5) 225 | else: 226 | if headers is None: 227 | req = self.session.options(url, params=params, timeout=5) 228 | print(req.url) 229 | else: 230 | req = self.session.options(url, params=params, headers=headers, timeout=5) 231 | if req.status_code == 200: 232 | return True 233 | else: 234 | print("[提示]状态码为" + str(req.status_code) + "!请检查错误\n[提示]" + req.content.decode('utf-8')) 235 | # sys.exit(0) 236 | except Exception as e: 237 | print("[提示]OPTIONS出错\n[提示]%s" % str(e)) 238 | 239 | def put(self, url, data, params=None, headers=None): 240 | while True: 241 | try: 242 | if params is None: 243 | if headers is None: 244 | req = self.session.put(url, data=data) 245 | else: 246 | req = self.session.put(url, data=data, headers=headers) 247 | else: 248 | if headers is None: 249 | req = self.session.put(url, data=data, params=params) 250 | else: 251 | req = self.session.put(url, data=data, params=params, headers=headers) 252 | if req.status_code == 200: 253 | return True 254 | else: 255 | print("[提示]状态码为" + str(req.status_code) + "!请检查错误\n[提示]" + req.content.decode('utf-8')) 256 | # sys.exit(0) 257 | except Exception as e: 258 | print("[提示]PUT出错\n[提示]%s" % str(e)) 259 | 260 | def upload_chunk(self, url, data, params, auth): 261 | while True: 262 | try: 263 | req = self.session.options(url=url) 264 | if req.status_code != 200: 265 | raise RuntimeError('OPTIONS返回码不是200') 266 | req1=self.session.put(url=url, data=data, params=params, headers={'X-Upos-Auth': auth}) 267 | if req1.status_code != 200: 268 | raise RuntimeError('OPTIONS返回码不是200') 269 | return True 270 | except: 271 | print("[提示]上传块失败,重试...") 272 | 273 | def user_info(self): 274 | """ 275 | 获取当前用户的信息 276 | :return: 277 | """ 278 | req = self.get( 279 | url='https://member.bilibili.com/x/web/white' 280 | ) 281 | return req 282 | 283 | def upload_cover(self, path): 284 | """ 285 | 上传封面,返回封面url地址 286 | :param path: 图片路径 287 | :return: 288 | """ 289 | with open(path, 'rb') as f: 290 | req = self.post( 291 | url='https://member.bilibili.com/x/vu/web/cover/up', 292 | data={ 293 | "cover": 'data:image/jpeg;base64,' + base64.b64encode(f.read()).decode('utf-8'), 294 | "csrf": self.csrf 295 | } 296 | ) 297 | if req['code'] == 0 and req['message'] == '0': 298 | return req['data']['url'] 299 | 300 | def report(self, cid, dmid, reason, content=None): 301 | """ 302 | 举报弹幕 303 | :param cid: 弹幕所在cid号 304 | :param dmid: 弹幕id号 305 | :param reason: 1违法违禁 2色情低俗 3赌博诈骗 4人身攻击 5侵犯隐私 306 | 6垃圾广告 7引战 8剧透 9恶意刷屏 10视频无关 307 | 11其他(带content) 12青少年不良信息 308 | :param content: 309 | """ 310 | req = self.post( 311 | url='https://api.bilibili.com/x/dm/report/add', 312 | data={ 313 | 'cid': cid, 314 | 'dmid': dmid, 315 | 'reason': reason, 316 | 'content': '' if content is None else content, 317 | 'csrf': self.csrf 318 | } 319 | ) 320 | if req['code'] == 0: 321 | return True 322 | else: 323 | print(req) 324 | return False 325 | # print("code = 0 举报成功") 326 | # elif req['code'] == 36201: 327 | # # print('code = 36201 弹幕不存在') 328 | # elif req['code'] == 36204: 329 | # print('code = 36204 已举报') 330 | 331 | def stat(self, aid): 332 | """ 333 | 获得稿件的播放数等信息,返回一个元组 334 | [稿件id,播放数,弹幕数,回复,收藏,硬币,分享,点赞, 335 | 目前排名,历史最高排名,是否禁止转载,稿件类型(自制/转载)] 336 | :param aid: 稿件编号,不含av前缀 337 | :return: 列表 338 | """ 339 | req = self.get( 340 | url='https://api.bilibili.com/x/web-interface/archive/stat', 341 | params={'aid': aid} 342 | ) 343 | print(req) 344 | if req['code'] == 0: 345 | return (req['data']['aid'], 346 | req['data']['view'], 347 | req['data']['danmaku'], 348 | req['data']['reply'], 349 | req['data']['favorite'], 350 | req['data']['coin'], 351 | req['data']['share'], 352 | req['data']['like'], 353 | req['data']['now_rank'], 354 | req['data']['his_rank'], 355 | req['data']['no_reprint'], 356 | req['data']['copyright'] 357 | ) 358 | 359 | def upstat(self, mid): 360 | """ 361 | 获得稿件播放总数和专栏浏览总数, 362 | 需要带UA访问 363 | :param mid:用户mid 364 | :return:字典 365 | """ 366 | req = self.get( 367 | url='https://api.bilibili.com/x/space/upstat', 368 | params={'mid': mid}, 369 | headers={'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) ' 370 | 'Chrome/67.0.3396.99 Safari/537.36'} 371 | ) 372 | return { 373 | 'archive': req['data']['archive']['view'], 374 | 'article': req['data']['article']['view'] 375 | } 376 | 377 | def pagelist(self, aid): 378 | """ 379 | 获得稿件的分p,cid等信息的列表,每条信息封装为一个元组 380 | (分p的cid,分p序号,分p标题,持续时间(单位为秒)) 381 | :param s: session 382 | :param aid: 稿件aid,不含av前缀 383 | :return:稿件信息列表 384 | """ 385 | req = self.get( 386 | url='https://api.bilibili.com/x/player/pagelist', 387 | params={'aid': aid} 388 | ) 389 | data = req['data'] 390 | plist = [] 391 | for d in data: 392 | plist.append((d['cid'], 393 | d['page'], 394 | d['part'], 395 | d['duration']) 396 | ) 397 | return plist 398 | 399 | def search_default(self): 400 | """ 401 | 获取搜索框的默认关键字 402 | :return:dict 403 | """ 404 | req = self.get( 405 | url='https://api.bilibili.com/x/web-interface/search/default' 406 | ) 407 | return { 408 | 'type': req['data']['type'], 409 | 'seid': req['data']['seid'], 410 | 'id': req['data']['id'], 411 | 'show_name': req['data']['show_name'], 412 | 'name': req['data']['name'] 413 | } 414 | 415 | def relation_followings(self, vmid): 416 | """ 417 | 获取自己的关注列表,最多40页,最多2000条 418 | 获取用户的关注列表,系统限制访问前5页,分页最大为50,倒序正序各获取250条记录,共500条 419 | 返回元组为(int(vmid), d['mid'], d['mtime']) 420 | 意为这个用户int(vmid)关注了d['mid'],时间为d['mtime'] 421 | :param s: 422 | :param vmid: 423 | :return: 424 | """ 425 | followings = [] 426 | rel = [] 427 | for i in range(1, 41): 428 | req = self.get( 429 | url='https://api.bilibili.com/x/relation/followings', 430 | params={ 431 | 'vmid': vmid, 432 | 'pn': str(i), 433 | 'ps': '50', 434 | 'order': 'desc', 435 | } 436 | ) 437 | data = req['data']['list'] 438 | if len(data) == 0: 439 | break 440 | for d in data: 441 | if d['mid'] not in followings: 442 | followings.append(d['mid']) 443 | rel.append((int(vmid), d['mid'], d['mtime'])) 444 | for i in range(1, 6): 445 | req = self.get( 446 | url='https://api.bilibili.com/x/relation/followings', 447 | params={ 448 | 'vmid': vmid, 449 | 'pn': str(i), 450 | 'ps': '50', 451 | 'order': 'asc', 452 | } 453 | ) 454 | data = req['data']['list'] 455 | for d in data: 456 | if d['mid'] not in followings: 457 | followings.append(d['mid']) 458 | rel.append((int(vmid), d['mid'], d['mtime'])) 459 | return rel 460 | 461 | def relation_followers(self, vmid): 462 | """ 463 | 系统限制访问前五页 464 | 获取用户的粉丝列表,最多5页x50=250条 465 | 查看自己的粉丝列表,最多1000条,分页50,最多20页 466 | 返回元组为(i['mid'], int(vmid), i['mtime']) 467 | 意思为粉丝(i['mid'])关注(这个用户vmid),i['mtime'] 468 | :param vmid: 469 | :return: 470 | """ 471 | followers = [] 472 | rel = [] 473 | for i in range(1, 21): 474 | req = self.get( 475 | url='https://api.bilibili.com/x/relation/followers', 476 | params={ 477 | 'vmid': vmid, 478 | 'pn': str(i), 479 | 'ps': '50', 480 | 'order': 'asc' 481 | } 482 | ) 483 | data = req['data']['list'] 484 | if len(data) == 0: 485 | break 486 | for i in data: 487 | if i['mid'] not in followers: 488 | followers.append(i['mid']) 489 | rel.append((i['mid'], int(vmid), i['mtime'])) 490 | return rel 491 | 492 | def modify(self, fid, act): 493 | """ 494 | 关注/取消关注用户 495 | (不要短时间大量调用,会封禁一段时间) 496 | :param fid: 要进行操作的用户 497 | :param act: 进行的操作1.关注 2.取消关注 3.悄悄关注 4.取消悄悄关注 5.加入黑名单 6.移除黑名单 498 | :return: 499 | """ 500 | req = self.post( 501 | url='https://api.bilibili.com/x/relation/modify', 502 | data={ 503 | 'fid': fid, 504 | 'act': act, 505 | 're_src': '11', 506 | 'csrf': self.csrf 507 | } 508 | ) 509 | if req['code'] == 0: 510 | if act == '1': 511 | print('关注用户' + fid + '成功') 512 | elif act == '2': 513 | print('取消关注用户' + fid + '成功') 514 | else: 515 | print(req) 516 | else: 517 | print(req) 518 | 519 | def followings_group(self): 520 | """ 521 | 获得当前用户的关注分组 522 | (i['tagid'], i['name'], i['count']) 523 | (分组id,分组名称,分组内的用户数) 524 | :return: 525 | """ 526 | req = self.get( 527 | url='https://api.bilibili.com/x/relation/tags' 528 | ) 529 | data = req['data'] 530 | group = [] 531 | for i in data: 532 | group.append((i['tagid'], i['name'], i['count'])) 533 | return group 534 | 535 | def move_followings_to_group(self,fids,tagids): 536 | """ 537 | 将指定用户加入指定关注分组 538 | :param fids: 539 | :param tagids: 分组id,使用followings_group获取,允许传入多个值, 540 | 用逗号分开。例:-10,74801 541 | :return: 542 | """ 543 | req = self.post( 544 | url='https://api.bilibili.com/x/relation/tags/addUsers', 545 | data={ 546 | 'fids': fids, 547 | 'tagids': tagids, 548 | 'csrf': self.csrf 549 | }, 550 | headers={'Referer': 'https://space.bilibili.com/%s/' % fids} 551 | ) 552 | print(req) 553 | if req['code'] == 0: 554 | print("将用户%s加入分组成功!" % fids) 555 | else: 556 | print(req) 557 | 558 | def followings_group_create(self, tag): 559 | """ 560 | 创建新的关注分组 561 | code=0 创建成功 562 | code=22106 该分组已经存在 563 | :param tag: 分组的名字 564 | :return: 565 | """ 566 | req = self.post( 567 | url='https://api.bilibili.com/x/relation/tag/create', 568 | data={ 569 | 'tag': tag, 570 | 'csrf': self.csrf 571 | } 572 | ) 573 | print(req) 574 | if req['code'] == 0: 575 | print("分组创建成功!分组id为:%s" % req['data']['tagid']) 576 | else: 577 | print(req) 578 | 579 | def followings_group_rename(self, tagid, name): 580 | """ 581 | 重命名关注分组 582 | code=0 修改成功 583 | code=22104 该分组不存在 584 | code=-101 账号未登录 585 | code=-400 请求错误 586 | :param tagid: 587 | :param name: 588 | :return: 589 | """ 590 | req = self.post( 591 | url='https://api.bilibili.com/x/relation/tag/update', 592 | data={ 593 | 'tagid': tagid, 594 | 'name': name, 595 | 'jsonp': 'jsonp', 596 | 'csrf': self.csrf 597 | } 598 | ) 599 | print(req) 600 | if req['code'] == 0: 601 | print("分组id:%s已经更名为:%s" % (tagid, name)) 602 | else: 603 | print(req) 604 | 605 | def followings_group_delete(self, tagid): 606 | """ 607 | 删除指定的关注分组 608 | code=0 操作成功(删除不存在的分组也返回code0) 609 | code=-101 账号未登录 610 | code=-400 请求错误 611 | :param tagid: 关注分组id 612 | :return: 613 | """ 614 | req = self.post( 615 | url='https://api.bilibili.com/x/relation/tag/del', 616 | data={ 617 | 'tagid': tagid, 618 | 'jsonp': 'jsonp', 619 | 'csrf': self.csrf 620 | } 621 | ) 622 | if req['code'] ==0: 623 | print("操作成功") 624 | else: 625 | print(req) 626 | 627 | def followings_group_copy_users(self, fids, tagids): 628 | """ 629 | 将多个用户复制到指定关注分组 630 | code=0 操作成功 631 | code=22104 该分组不存在 632 | code=22105 请先公开关注后再添加分组(关注后才能复制到分组) 633 | code=-101 账号未登录 634 | code=-400 请求错误 635 | :param fids: 用户列表(list类型),示例[1234,5678,9012] 636 | :param tagids: 分组id 637 | :return: 638 | """ 639 | req = self.post( 640 | url='https://api.bilibili.com/x/relation/tags/copyUsers', 641 | data={ 642 | 'fids': str(fids)[1:-1].replace(' ', ''), 643 | 'tagids': tagids, 644 | 'jsonp': 'jsonp', 645 | 'csrf': self.csrf 646 | } 647 | ) 648 | if req['code'] == 0: 649 | print("操作成功") 650 | else: 651 | print(req) 652 | 653 | def followings_group_move_users(self, beforeTagids, afterTagids, fids): 654 | """ 655 | 将多个用户移动到指定的关注分组 656 | code=0 操作成功 657 | code=22104 该分组不存在 658 | code=22105 请先公开关注后再添加分组(关注后才能复制到分组) 659 | code=-101 账号未登录 660 | code=-400 请求错误 661 | :param beforeTagids: 移动前所在分组id 662 | :param afterTagids: 目标分组id 663 | :param fids: 需要操作的用户id列表(list类型),示例[1234,5678,9012] 664 | :return: 665 | """ 666 | req = self.post( 667 | url='https://api.bilibili.com/x/relation/tags/moveUsers', 668 | data={ 669 | 'beforeTagids': beforeTagids, 670 | 'afterTagids': afterTagids, 671 | 'fids': str(fids)[1:-1].replace(' ', ''), 672 | 'jsonp': 'jsonp', 673 | 'csrf': self.csrf 674 | } 675 | ) 676 | if req['code'] == 0: 677 | print("操作成功") 678 | else: 679 | print(req) 680 | 681 | def getSubmitVideos(self, mid, pagesize=100, tid=0, page=1, keyword='', order='pubdate'): 682 | """ 683 | 获得用户投稿的视频列表 684 | :param mid: 用户mid 685 | :param pagesize: 分页大小,默认100,最大100 686 | :param tid: 按分区查询,0.查询所有,tid对照见tid.txt 687 | :param page: 查询页数,默认查询第一页 688 | :param keyword: 按关键字查找 689 | :param order: 查询排序方式,默认pubdate(最新发布)/click(点击数)/stow(最多收藏) 690 | :return: 691 | """ 692 | req = self.get( 693 | url='https://space.bilibili.com/ajax/member/getSubmitVideos', 694 | params={ 695 | 'mid': mid, 696 | 'pagesize': pagesize, 697 | 'tid': tid, 698 | 'page': page, 699 | 'keyword': keyword, 700 | 'order': order 701 | } 702 | ) 703 | return req['data']['vlist'] 704 | 705 | def get_album_list(self, mid, page_num=0, page_size=99999, biz='all'): 706 | """ 707 | 获得用户相簿列表 708 | :param mid: 用户mid 709 | :param page_num: 页数,从0开始,默认为0 710 | :param page_size: 分页大小,目前没有限制(WHAT?) 711 | :param biz: 分类查找,默认all,draw(画友),daily(日常),photo(摄影) 712 | :return: 713 | """ 714 | req = self.get( 715 | url='https://api.vc.bilibili.com/link_draw/v1/doc/doc_list', 716 | params={ 717 | 'uid': mid, 718 | 'page_num': page_num, 719 | 'page_size': page_size, 720 | 'biz': biz 721 | } 722 | 723 | ) 724 | print(req) 725 | l = req['data']['items'] 726 | print(l) 727 | print(len(l)) 728 | for i in l: 729 | print(i) 730 | 731 | def get_user_article_list(self, mid, page=1, pagesplit=30, sort='publish_time'): 732 | """ 733 | 获得用户专栏文章列表 734 | :param mid: 用户mid 735 | :param page: 页数,默认第1页 736 | :param pagesplit: 分页大小,默认12,最大30 737 | :param sort: 排序方式,默认publish_time(发布时间)/view(最多观看)/fav(最多收藏) 738 | :return: 739 | """ 740 | req = self.get( 741 | url='https://api.bilibili.com/x/space/article', 742 | params={ 743 | 'mid': mid, 744 | 'pn': page, 745 | 'ps': pagesplit, 746 | 'sort': sort, 747 | 'jsonp': 'jsonp' 748 | } 749 | ) 750 | return req['data']['articles'] 751 | 752 | def get_user_audio_list(self, mid, page=1, pagesplit=30, order=1): 753 | """ 754 | 获得用户音频作品列表 755 | :param mid: 用户mid 756 | :param page: 页数,默认为1 757 | :param pagesplit: 分页大小,默认30,最大为(?) 758 | :param order: 排序方式 1.最新发布 2.最多播放 3.最多收藏 759 | :return: 760 | """ 761 | req = self.get( 762 | url='https://api.bilibili.com/audio/music-service-c/web/song/upper', 763 | params={ 764 | 'uid': mid, 765 | 'pn': page, 766 | 'ps': pagesplit, 767 | 'order': order, 768 | 'jsonp': 'jsonp' 769 | } 770 | ) 771 | return req['data']['data'] 772 | 773 | def get_history_danmaku_index(self, cid, month): 774 | """ 775 | 获得指定月份可用历史弹幕的列表(需要登录) 776 | 返回示例:{"code":0,"message":"0","ttl":1,"data":["2018-08-05","2018-08-09","2018-08-10"]} 777 | :param cid: 视频cid号 778 | :param month: 以年-月组合的字符串,用于查询当月可用的历史弹幕,例:2018-08 779 | :return: 780 | """ 781 | req = self.get( 782 | url='https://api.bilibili.com/x/v2/dm/history/index', 783 | params={ 784 | 'type': 1, # 谜 785 | 'oid': cid, 786 | 'month': month 787 | } 788 | ) 789 | if req['code'] == 0: 790 | return req['data'] 791 | else: 792 | print(req) 793 | 794 | 795 | def get_history_danmaku(self, cid, data): 796 | """ 797 | 获得指定时间的历史弹幕 798 | :param cid: 视频cid 799 | :param data: 指定日期,通过get_history_danmaku_index获取 800 | :return: 801 | """ 802 | req = self.get( 803 | url='https://api.bilibili.com/x/v2/dm/history', 804 | params={ 805 | 'type': 1, # 谜 806 | 'oid': cid, 807 | 'date': data 808 | } 809 | ) 810 | return req 811 | 812 | def get_danmaku(self, cid): 813 | """ 814 | 通过cid获取弹幕 815 | :param cid: 视频cid 816 | :return: 817 | """ 818 | req = self.get( 819 | url='https://comment.bilibili.com/%s.xml' % cid, 820 | params={'platform': 'bilihelper'} 821 | ) 822 | return req 823 | 824 | def get_tag_info(self, tag_id): 825 | """ 826 | 通过tag_id获得tag信息 827 | :param tag_id: 828 | :return: 829 | """ 830 | req = self.get( 831 | url='https://api.bilibili.com/x/tag/info', 832 | params={'tag_id': tag_id} 833 | ) 834 | print(req) 835 | 836 | def get_similar_tags(self, tag_id): 837 | """ 838 | 获得tag的相关tags 839 | :param tag_id: 840 | :return: 841 | """ 842 | req = self.get( 843 | url='https://api.bilibili.com/x/tag/change/similar', 844 | params={'tag_id': tag_id} 845 | ) 846 | print(req) 847 | if req['code'] == 0: 848 | return req['data'] 849 | 850 | def get_tag_video(self, tag_id, page=1, pagesplit=20): 851 | """ 852 | 获得指定tag下的视频,按时间顺序排列 853 | :param tag_id: 854 | :param page: 855 | :param pagesplit: 分页大小,默认20,最大40,但返回数据不一定是40,可能是30~40条数据,不定 856 | :return: 857 | """ 858 | req = self.get( 859 | url='https://api.bilibili.com/x/tag/detail', 860 | params={ 861 | 'jsonp': 'jsonp', 862 | 'pn': page, 863 | 'ps': pagesplit, 864 | 'tag_id': tag_id, 865 | } 866 | 867 | ) 868 | # print(req) 869 | if req['code'] == 0: 870 | return req['data']['news']['archives'] 871 | 872 | def get_user_following_bangumi(self, mid, page=1): 873 | """ 874 | 获得用户订阅的番剧 875 | :param mid: 用户mid 876 | :param page: 查询页数 877 | :return: 878 | """ 879 | req = self.get( 880 | url='https://space.bilibili.com/ajax/Bangumi/getList', 881 | params={ 882 | 'mid': mid, 883 | 'page': page 884 | } 885 | ) 886 | blist = [] 887 | if req['status']: 888 | for b in req['data']['result']: 889 | blist.append(b['season_id']) 890 | return blist 891 | 892 | def get_user_following_tags(self, mid): 893 | """ 894 | 获得用户关注的tag 895 | :param mid: 896 | :return: 897 | """ 898 | req = self.get( 899 | url='https://space.bilibili.com/ajax/tags/getSubList', 900 | params={'mid': mid} 901 | ) 902 | if req['status']: 903 | return req['data']['tags'] 904 | 905 | def get_user_channel_list(self, mid): 906 | """ 907 | 获得用户创建的频道列表 908 | :param mid: 用户mid 909 | :return: Channel对象的list 910 | """ 911 | req = self.get( 912 | url='https://api.bilibili.com/x/space/channel/list', 913 | params={ 914 | 'mid': mid, 915 | 'guest': 'false', # 谜,false 916 | 'jsonp': 'jsonp' 917 | } 918 | ) 919 | clist = [] 920 | if req['code'] == 0: 921 | for c in req['data']['list']: 922 | channel = Channel() 923 | channel.id = c['cid'] 924 | channel.owner = c['mid'] 925 | channel.name = c['name'] 926 | channel.intro = c['intro'] 927 | channel.ctime = c['mtime'] 928 | channel.video_count = c['count'] 929 | channel.cover = c['cover'] 930 | clist.append(channel) 931 | return clist 932 | 933 | def channel_add(self, ch_name, intro='',): 934 | """ 935 | 创建新的频道 936 | code=0 创建成功 937 | code=53001 频道名字数超过限制啦 938 | :param ch_name: 频道名称 939 | :param intro: 频道介绍 940 | :return: 941 | """ 942 | req = self.post( 943 | url='https://api.bilibili.com/x/space/channel/add', 944 | data={ 945 | 'name': ch_name, 946 | 'intro': intro, 947 | 'jsonp': 'jsonp', 948 | 'csrf': self.csrf 949 | } 950 | ) 951 | if req['code'] == 0: 952 | print("[提示]频道<%s>创建成功,频道ID为%s" % (ch_name, req['data']['cid'])) 953 | return req['data']['cid'] 954 | else: 955 | print(req) 956 | 957 | def channel_edit(self, ch_id, name, intro=''): 958 | """ 959 | 修改频道信息 960 | code=0 修改成功 961 | code=53001 频道名字数超过限制啦 962 | code=-400 请求错误 963 | :param ch_id:频道id 964 | :param name: 频道新名称 965 | :param intro: 频道新简介 966 | :return: 967 | """ 968 | req = self.post( 969 | url='https://api.bilibili.com/x/space/channel/edit', 970 | data={ 971 | 'cid': ch_id, 972 | 'name': name, 973 | 'intro': intro, 974 | 'jsonp': 'jsonp', 975 | 'csrf': self.csrf 976 | } 977 | ) 978 | print(req) 979 | if req['code'] == 0: 980 | print("[提示]频道ID:<{}>名称已修改为<{}>,简介为:<{}>".format(ch_id, name, intro)) 981 | 982 | def channel_del(self, ch_id): 983 | """ 984 | 删除指定频道 985 | :param ch_id:频道id 986 | :return: 987 | """ 988 | req = self.post( 989 | url='https://api.bilibili.com/x/space/channel/del', 990 | data={ 991 | 'cid': ch_id, 992 | 'jsonp': 'jsonp', 993 | 'csrf': self.csrf 994 | } 995 | ) 996 | if req['code'] == 0: 997 | print("[提示]频道ID:<{}>已成功删除!".format(ch_id)) 998 | 999 | def channel_video(self, mid, cid, page=1, pagesplit=30, order=0): 1000 | """ 1001 | 获得频道内的视频 1002 | :param mid: 1003 | :param cid: 1004 | :param page: 1005 | :param pagesplit:分页大小,默认30,最大100 1006 | :param order:0.默认排序 1.倒序排序 1007 | :return:视频aid列表 1008 | """ 1009 | req = self.get( 1010 | url='https://api.bilibili.com/x/space/channel/video', 1011 | params={ 1012 | 'mid': mid, 1013 | 'cid': cid, 1014 | 'pn': page, 1015 | 'ps': pagesplit, 1016 | 'order': order, 1017 | 'jsonp': 'jsonp' 1018 | } 1019 | ) 1020 | print(req) 1021 | vlist = [] 1022 | if req['code'] == 0: 1023 | for v in req['data']['list']['archives']: 1024 | vlist.append(v['aid']) 1025 | return vlist 1026 | 1027 | def get_video_info(self, aid): 1028 | """ 1029 | 获得视频详细信息 1030 | code=0 正常 1031 | code=62002 稿件不可见(稿件被删除 state为-100) 1032 | code=-404 啥都木有(稿件下架) 1033 | :param aid: 视频aid 1034 | :return: 1035 | """ 1036 | req = self.get( 1037 | url='https://api.bilibili.com/x/web-interface/view', 1038 | params={'aid': aid} 1039 | ) 1040 | print(req) 1041 | if req['code'] == 0: 1042 | v = Video() 1043 | v.aid = req['data']['aid'] 1044 | v.videos = req['data']['videos'] 1045 | v.tid = req['data']['tid'] 1046 | v.copyright = req['data']['copyright'] 1047 | v.pic = req['data']['pic'] 1048 | v.title = req['data']['title'] 1049 | v.pubdate = req['data']['pubdate'] 1050 | v.ctime = req['data']['ctime'] 1051 | v.description = req['data']['desc'] 1052 | v.state = req['data']['state'] 1053 | if req['data']['state'] == -4: 1054 | v.forward = req['data']['forward'] 1055 | v.attribute = req['data']['attribute'] 1056 | v.duration = req['data']['duration'] 1057 | v.owner_mid = req['data']['owner']['mid'] 1058 | v.stat_view = req['data']['stat']['view'] 1059 | if req['data']['stat']['view'] == -1: 1060 | v.access = req['data']['access'] 1061 | v.stat_danmaku = req['data']['stat']['danmaku'] 1062 | v.stat_reply = req['data']['stat']['reply'] 1063 | v.stat_favorite = req['data']['stat']['favorite'] 1064 | v.stat_coin = req['data']['stat']['coin'] 1065 | v.stat_share = req['data']['stat']['share'] 1066 | v.stat_now_rank = req['data']['stat']['now_rank'] 1067 | v.stat_his_rank = req['data']['stat']['his_rank'] 1068 | v.stat_like = req['data']['stat']['like'] 1069 | v.stat_dislike = req['data']['stat']['dislike'] 1070 | v.dynamic = req['data']['aid'] 1071 | cids = [] 1072 | part = [] 1073 | for p in req['data']['pages']: 1074 | cids.append(p['cid']) 1075 | vp = VideoPart() 1076 | vp.cid = p['cid'] 1077 | vp.page = p['page'] 1078 | vp.vfrom = p['from'] 1079 | vp.part = p['part'] 1080 | vp.duration = p['duration'] 1081 | vp.vid = p['vid'] 1082 | vp.weblink = p['weblink'] 1083 | vp.width = p['dimension']['width'] 1084 | vp.height = p['dimension']['height'] 1085 | vp.rotate = p['dimension']['rotate'] 1086 | part.append(vp) 1087 | v.cids = str(cids)[1:-1].replace(' ', '') 1088 | return v, part,req['code'] 1089 | else: 1090 | return None,None,req['code'] 1091 | 1092 | def get_user_card(self, mid,): 1093 | """ 1094 | 获得用户详细的资料卡 1095 | :param mid: 用户 1096 | :return: 1097 | """ 1098 | req = self.get( 1099 | url='https://api.bilibili.com/x/web-interface/card', 1100 | params={ 1101 | 'jsonp': 'jsonp', 1102 | 'mid': mid, 1103 | # 'loginid': 'loginid' 非必要参数 1104 | } 1105 | ) 1106 | print(req) 1107 | 1108 | def get_video_tags(self, aid): 1109 | """ 1110 | 获得视频的tag 1111 | :param aid: 视频aid 1112 | :return: 1113 | """ 1114 | req = self.get( 1115 | url='https://api.bilibili.com/x/tag/archive/tags', 1116 | params={ 1117 | 'aid': aid, 1118 | 'jsonp': 'jsonp' 1119 | } 1120 | ) 1121 | print(req) 1122 | 1123 | def get_my_attentions(self): 1124 | """ 1125 | 获得当前用户的关注列表 1126 | :return: 关注用户mid列表 1127 | """ 1128 | req = self.get( 1129 | url='https://api.bilibili.com/x/web-interface/attentions', 1130 | params={'jsonp': 'jsonp'} 1131 | ) 1132 | if req['code'] == 0: 1133 | return req['data'] 1134 | 1135 | def get_attention_list(self): 1136 | """ 1137 | 获得当前用户关注的mid列表,带不带params不影响结果 1138 | :return: 1139 | """ 1140 | req = self.get( 1141 | url='https://api.vc.bilibili.com/feed/v1/feed/get_attention_list' 1142 | # params={'uid': '3296491'} 1143 | ) 1144 | if req['code'] == 0 and req['message'] == 'success': 1145 | return req['data']['list'] 1146 | 1147 | def is_favoured(self, aid): 1148 | """ 1149 | 判断当前登录的用户是否收藏指定视频 1150 | 返回示例:{'code': 0, 'message': '0', 'ttl': 1, 'data': {'count': 1, 'favoured': False}} 1151 | count作用不详 1152 | :param aid: 视频aid 1153 | :return: 已收藏返回True 未收藏返回False 1154 | """ 1155 | req = self.get( 1156 | url='https://api.bilibili.com/x/v2/fav/video/favoured', 1157 | params={ 1158 | 'aid': aid, 1159 | 'jsonp': 'jsonp' 1160 | } 1161 | ) 1162 | print(req) 1163 | if req['code'] == 0: 1164 | return req['data']['favoured'] 1165 | 1166 | def archive_coins(self, aid): 1167 | """ 1168 | (谜)关于硬币的api 1169 | :param aid:视频aid 1170 | :return: 1171 | """ 1172 | req = self.get( 1173 | url='https://api.bilibili.com/x/web-interface/archive/coins', 1174 | params={ 1175 | 'jsonp': 'jsonp', 1176 | 'aid': aid 1177 | } 1178 | ) 1179 | print(req) 1180 | 1181 | def elec_show(self, aid, mid): 1182 | """ 1183 | 获得指定稿件的充电信息 1184 | :param aid: 稿件aid 1185 | :param mid: 作者mid 1186 | :return: 1187 | """ 1188 | req = self.get( 1189 | url='https://api.bilibili.com/x/web-interface/elec/show', 1190 | params={ 1191 | 'jsonp': 'jsonp', 1192 | 'aid': aid, 1193 | 'mid': mid 1194 | } 1195 | ) 1196 | if req['code'] == 0: 1197 | av_count = req['data']['av_count'] # 本视频充电人数 1198 | count = req['data']['count'] # 本月充电人数 1199 | total_count = req['data']['total_count'] # 历史充电总人数 1200 | av_list = req['data']['av_list'] # 本视频充电排行榜 1201 | list = req['data']['list'] # 本月充电排行榜 1202 | return av_count, count, total_count, av_list, list 1203 | 1204 | def video_related(self, aid): 1205 | """ 1206 | 获得指定视频的相关视频(看过该视频的还喜欢) 1207 | :param aid:视频aid 1208 | :return: 1209 | """ 1210 | req = self.get( 1211 | url='https://api.bilibili.com/x/web-interface/archive/related', 1212 | params={ 1213 | 'aid': aid, 1214 | 'jsonp': 'jsonp' 1215 | } 1216 | ) 1217 | print(req) 1218 | 1219 | def video_reply(self, aid, page=1, type=1, sort=0): 1220 | """ 1221 | 获得视频的评论 1222 | code=12002 禁止评论(type>1) 1223 | code=12009 评论主体的type不合法(type=0) 1224 | 一些特殊的视频也会返回code12002 1225 | :param aid:视频aid 1226 | :param page:页数 1227 | :param type: 1228 | :param sort: 1229 | :return: 1230 | """ 1231 | req = self.get( 1232 | url='https://api.bilibili.com/x/v2/reply', 1233 | params={ 1234 | 'jsonp': 'jsonp', 1235 | 'pn': page, 1236 | 'type': type, 1237 | 'oid': aid, 1238 | 'sort': sort # 0.普通排序 2.按热度排序 1239 | } 1240 | ) 1241 | print(req) 1242 | 1243 | def video_tag_log(self, aid, page=1, pagesplit=20): 1244 | """ 1245 | 获得视频标签修改记录 1246 | :param aid: 1247 | :param page: 1248 | :param pagesplit: 1249 | :return: 1250 | """ 1251 | req = self.get( 1252 | url='https://api.bilibili.com/x/tag/archive/log', 1253 | params={ 1254 | 'aid': aid, 1255 | 'pn': page, 1256 | 'ps': pagesplit, 1257 | 'jsonp': 'jsonp' 1258 | } 1259 | ) 1260 | print(req) 1261 | 1262 | def video_tag_add(self, aid, tag_name): 1263 | """ 1264 | 为视频添加tag 1265 | code=16009 这个频道已经添加过啦~ 1266 | code=-101 账号未登录 1267 | :param aid: 视频aid 1268 | :param tag_name: 要添加的tag名称 1269 | :return: 1270 | """ 1271 | req = self.post( 1272 | url='https://api.bilibili.com/x/tag/archive/add', 1273 | data={ 1274 | 'aid': aid, 1275 | 'tag_name': tag_name, 1276 | 'jsonp': 'jsonp', 1277 | 'csrf': self.csrf 1278 | } 1279 | ) 1280 | if req['code'] == 0: 1281 | print("[提示]TAG:<{}>添加成功!".format(tag_name)) 1282 | elif req['code'] == 16009: 1283 | print("[提示]TAG:<{}>已经添加过了!".format(tag_name)) 1284 | else: 1285 | print(req) 1286 | 1287 | def video_tag_like(self, aid, tag_id): 1288 | """ 1289 | 视频tag点赞,再点一次取消赞 1290 | :param aid: 1291 | :param tag_id: 1292 | :return: 1293 | """ 1294 | req = self.post( 1295 | url='https://api.bilibili.com/x/tag/archive/like2', 1296 | data={ 1297 | 'tag_id': tag_id, 1298 | 'aid': aid, 1299 | 'jsonp': 'jsonp', 1300 | 'csrf': self.csrf 1301 | } 1302 | ) 1303 | if req['code'] == 0: 1304 | print("[提示]视频aid:<{}>的TAG:<{}>点赞成功!".format(aid, tag_id)) 1305 | else: 1306 | print(req) 1307 | 1308 | def video_tag_hate(self, aid, tag_id): 1309 | """ 1310 | 视频tag踩,再点一次取消踩 1311 | :param aid: 1312 | :param tag_id: 1313 | :return: 1314 | """ 1315 | req = self.post( 1316 | url='https://api.bilibili.com/x/tag/archive/hate2', 1317 | data={ 1318 | 'tag_id': tag_id, 1319 | 'aid': aid, 1320 | 'jsonp': 'jsonp', 1321 | 'csrf': self.csrf 1322 | } 1323 | ) 1324 | if req['code'] == 0: 1325 | print("[提示]视频aid:<{}>的TAG:<{}>踩成功!".format(aid, tag_id)) 1326 | else: 1327 | print(req) 1328 | 1329 | def video_tag_del(self, aid, tag_id): 1330 | """ 1331 | 删除视频的tag 1332 | code=16011 删除太多频道啦,休息休息~ 1333 | code=16049 资源绑定tag关系不存在~ 1334 | code=16071 只有UP主可以删除哦 1335 | :param aid: 1336 | :param tag_id: 1337 | :return: 1338 | """ 1339 | req = self.post( 1340 | url='https://api.bilibili.com/x/tag/archive/del', 1341 | data={ 1342 | 'aid': aid, 1343 | 'tag_id': tag_id, 1344 | 'jsonp': 'jsonp', 1345 | 'csrf': self.csrf 1346 | } 1347 | ) 1348 | print(req) 1349 | 1350 | def video_tag_report(self, aid, tag_id, reason): 1351 | """ 1352 | 举报视频tag 1353 | :param aid: 1354 | :param tag_id: 1355 | :param reason:必须为四个值之一:内容不相关|敏感信息|恶意攻击|剧透内容 1356 | :return: 1357 | """ 1358 | req = self.post( 1359 | url='https://api.bilibili.com/x/tag/archive/report', 1360 | data={ 1361 | 'aid': aid, 1362 | 'tag_id': tag_id, 1363 | 'reason': reason, 1364 | 'jsonp': 'jsonp', 1365 | 'csrf': self.csrf 1366 | } 1367 | ) 1368 | if req['code'] == 0: 1369 | print("[提示]举报视频aid:<{}>中的TAG:<{}>成功,举报理由为:<{}>".format(aid, tag_id, reason)) 1370 | else: 1371 | print(req) 1372 | 1373 | def tag_subscribe_add(self, tag_id): 1374 | """ 1375 | 订阅TAG 1376 | code=16030 已经订阅过这个频道啦~ 1377 | :param tag_id: 1378 | :return: 1379 | """ 1380 | req = self.post( 1381 | url='https://api.bilibili.com/x/tag/subscribe/add', 1382 | data={ 1383 | 'tag_id': tag_id, 1384 | 'jsonp': 'jsonp', 1385 | 'csrf': self.csrf 1386 | } 1387 | ) 1388 | if req['code'] == 0: 1389 | print("[提示]订阅TAG:<{}>成功!".format(tag_id)) 1390 | else: 1391 | print(req) 1392 | 1393 | def tag_subscribe_cancel(self, tag_id): 1394 | """ 1395 | 取消订阅TAG 1396 | code=16035 未订阅过此频道~ 1397 | :param tag_id: 1398 | :return: 1399 | """ 1400 | req = self.post( 1401 | url='https://api.bilibili.com/x/tag/subscribe/cancel', 1402 | data={ 1403 | 'tag_id': tag_id, 1404 | 'jsonp': 'jsonp', 1405 | 'csrf': self.csrf, 1406 | } 1407 | 1408 | ) 1409 | if req['code'] == 0: 1410 | print("[提示]取消订阅TAG:<{}>成功".format(tag_id)) 1411 | elif req['code'] == 16035: 1412 | print("[提示]未订阅过TAG:<{}>".format(tag_id)) 1413 | else: 1414 | print(req) 1415 | 1416 | def tag_cancelSub(self, tag_id): 1417 | """ 1418 | 取消订阅TAG(通过个人主页-订阅-标签) 1419 | :param tag_id: 1420 | :return: 1421 | """ 1422 | req = self.post( 1423 | url='https://space.bilibili.com/ajax/tags/cancelSub', 1424 | data={ 1425 | 'tag_id': tag_id, 1426 | 'csrf': self.csrf 1427 | }, 1428 | headers={'Referer': 'https://space.bilibili.com/'} 1429 | ) 1430 | print(req) 1431 | if req['status']: 1432 | print("[提示]取消订阅TAG:<{}>成功".format(tag_id)) 1433 | elif not req['status']: 1434 | print("[提示]取消订阅TAG:<{}>失败".format(tag_id)) 1435 | 1436 | def space_pravacy(self, option, value): 1437 | """ 1438 | 个人主页-设置-隐私设置,设置指定项对其他用户是否可见 1439 | 1为可见,0为隐藏,可选项: 1440 | 我的收藏夹 fav_video 1441 | 订阅番剧 bangumi 1442 | 订阅标签 tags 1443 | 最近投币的视频 coins_video 1444 | 个人资料 user_info 1445 | 最近玩过的游戏 played_game 1446 | :param value: 隐藏or显示 1447 | :param option: 需要更改的项目 1448 | :return: 1449 | """ 1450 | req = self.post( 1451 | url='https://space.bilibili.com/ajax/settings/setPrivacy', 1452 | data={ 1453 | option: value, 1454 | 'csrf': self.csrf 1455 | }, 1456 | headers={'Referer': 'https://space.bilibili.com/'} 1457 | ) 1458 | print(req) 1459 | if req['status']: 1460 | print("[提示]操作成功!") 1461 | elif not req['status']: 1462 | print("[提示]操作失败!") 1463 | 1464 | def space_user_tags(self, mids): 1465 | """ 1466 | 获取一个或多个用户的个人标签 1467 | :param mids:用户mid的list 1468 | :return: 1469 | """ 1470 | req = self.get( 1471 | url='https://space.bilibili.com/ajax/member/getTags', 1472 | params={'mids': str(mids)[1:-1].replace(" ", '')} 1473 | ) 1474 | print(req) 1475 | 1476 | def space_user_tags_set(self, tags): 1477 | """ 1478 | 编辑个人标签 1479 | 需要使用space_user_tags获取自己的个人标签,然后加上新增的标签,用逗号隔开,一次性全部提交 1480 | :param tags: 例:标签1,标签2,标签3 1481 | :return: 1482 | """ 1483 | req = self.post( 1484 | url='https://space.bilibili.com/ajax/member/setTags', 1485 | data={ 1486 | 'tags': tags, 1487 | 'csrf': self.csrf 1488 | }, 1489 | headers={'Referer': 'https://space.bilibili.com/'} 1490 | ) 1491 | print(req) 1492 | if req['status']: 1493 | print("[提示]个人标签设置成功!") 1494 | elif not req['status']: 1495 | print("[提示]个人标签设置失败!") 1496 | 1497 | def space_index_order(self, index_order): 1498 | """ 1499 | 设置个人主页布局 1500 | 1.我的稿件 1501 | 2.我的收藏夹 1502 | 3.订阅番剧 1503 | 4.订阅标签 1504 | 5.最近投币的视频 1505 | 6.不详 1506 | 7.我的频道 1507 | 8.我的专栏 1508 | 9.我的相簿 1509 | 21.公告 1510 | 22.直播间 1511 | 23.个人资料 1512 | 24.官方活动 1513 | 25.最近玩过的游戏 1514 | 6总是在最后 1515 | :param index_order: 1516 | :return: 1517 | """ 1518 | req = self.post( 1519 | url='https://space.bilibili.com/ajax/settings/setIndexOrder', 1520 | data={ 1521 | 'index_order': str(index_order)[1:-1].replace(" ", ''), 1522 | 'csrf': self.csrf 1523 | }, 1524 | headers={'Referer': 'https://space.bilibili.com/'} 1525 | ) 1526 | if req['status']: 1527 | print("[提示]个人空间布局设置成功!") 1528 | elif not req['status']: 1529 | print("[提示]个人空间布局设置失败!") 1530 | 1531 | def update_my_sign(self, newsign): 1532 | """ 1533 | 修改我的签名(有时不太好用) 1534 | :param newsign: 1535 | :return: 1536 | """ 1537 | req = self.post( 1538 | url='https://api.bilibili.com/x/member/web/sign/update', 1539 | data={ 1540 | 'user_sign': newsign, 1541 | 'jsonp': 'jsonp', 1542 | 'csrf': self.csrf 1543 | } 1544 | ) 1545 | if req['code'] == 0: 1546 | print("[提示]当前签名已修改为:<{}>".format(newsign)) 1547 | else: 1548 | print(req) 1549 | print(self.csrf) 1550 | print("[提示]修改签名失败!") 1551 | 1552 | def site_user_info(self): 1553 | """ 1554 | 获得本账号的绑定情况信息 1555 | :return: 1556 | """ 1557 | req = self.get( 1558 | url='https://passport.bilibili.com/web/site/user/info' 1559 | ) 1560 | print(req) 1561 | 1562 | def realname_status(self): 1563 | """ 1564 | 查询本账号是否通过了实名认证 1565 | :return: 1566 | """ 1567 | req = self.get( 1568 | url='https://api.bilibili.com/x/member/realname/status', 1569 | 1570 | ) 1571 | if req['code'] == 0: 1572 | if req['data']['status'] == 1: 1573 | return True 1574 | else: 1575 | return False 1576 | 1577 | def watchlater_video(self): 1578 | """ 1579 | 获得"稍后观看"中的视频 1580 | :return: 视频aid列表 1581 | """ 1582 | req = self.get( 1583 | url='https://api.bilibili.com/x/v2/history/toview/web' 1584 | ) 1585 | vlist = [] 1586 | if req['code'] == 0: 1587 | for v in req['data']['list']: 1588 | vlist.append(v['aid']) 1589 | return vlist 1590 | 1591 | def get_my_blacklist(self, page=1, pagesplit=20): 1592 | """ 1593 | 获得我的黑名单列表 1594 | :param page: 1595 | :param pagesplit: 1596 | :return: 1597 | """ 1598 | req = self.get( 1599 | url='https://api.bilibili.com/x/relation/blacks', 1600 | params={ 1601 | 're_version': 0, 1602 | 'pn': page, 1603 | 'ps': pagesplit, 1604 | 'jsonp': 'jsonp' 1605 | } 1606 | ) 1607 | return req['data']['list'] 1608 | 1609 | def get_my_coin_log(self): 1610 | """ 1611 | 获得此账号硬币最近一周的变化情况 1612 | :return: 1613 | """ 1614 | req = self.get( 1615 | url='https://api.bilibili.com/x/member/web/coin/log', 1616 | params={'jsonp': 'jsonp'} 1617 | ) 1618 | if req['code'] == 0: 1619 | return req['data']['list'] 1620 | 1621 | def get_my_login_log(self): 1622 | """ 1623 | 获得此账号最近一周的登录情况 1624 | :return: 1625 | """ 1626 | req = self.get( 1627 | url='https://api.bilibili.com/x/member/web/login/log', 1628 | params={'jsonp': 'jsonp'} 1629 | ) 1630 | if req['code'] == 0: 1631 | return req['data']['list'] 1632 | 1633 | def get_my_moral_log(self): 1634 | """ 1635 | 获得此账号最近一周的节操值记录 1636 | :return: 1637 | """ 1638 | req = self.get( 1639 | url='https://api.bilibili.com/x/member/web/moral/log', 1640 | params={'jsonp': 'jsonp'} 1641 | ) 1642 | print(req) 1643 | 1644 | def get_my_exp_log(self): 1645 | """ 1646 | 获得此账号最近一周的经验变化 1647 | :return: 1648 | """ 1649 | req = self.get( 1650 | url='https://api.bilibili.com/x/member/web/exp/log', 1651 | params={'jsonp': 'jsonp'} 1652 | ) 1653 | if req['code'] == 0: 1654 | return req['data']['list'] 1655 | 1656 | def get_my_reply_list(self, stime, etime, order, sort, page=1, pagesplit=10): 1657 | """ 1658 | 查询此账号的历史发言 1659 | :param stime: 查询起始时间戳(秒级) 1660 | :param etime: 查询终止时间戳(秒级) 1661 | :param order: 发布时间(ctime)获得的赞(like) 1662 | :param sort: 倒序(desc) 正序(asc),以赞数查询时,只允许使用倒序查询 1663 | :param page: 页数 1664 | :param pagesplit:默认值10,根据查询范围最大值不定(例如查询最近三年的记录,最大值为715,更大的的查询范围,最大值更低,否则返回-500服务器错误) 1665 | :return: 1666 | """ 1667 | req = self.get( 1668 | url='https://api.bilibili.com/x/member/web/reply/list', 1669 | params={ 1670 | # 'mid': 2062761, 1671 | 'stime': stime, 1672 | 'etime': etime, 1673 | 'order': order, 1674 | 'sort': sort, 1675 | 'pn': page, 1676 | 'ps': pagesplit, 1677 | 'jsonp': 'jsonp' 1678 | } 1679 | ) 1680 | if req['code'] == 0: 1681 | return req['data']['records'] 1682 | else: 1683 | print(req) 1684 | 1685 | def get_my_basic_info(self): 1686 | """ 1687 | 获得此账号的基本信息(个人中心-我的信息) 1688 | :return: 1689 | """ 1690 | req = self.get( 1691 | url='https://api.bilibili.com/x/member/web/account', 1692 | 1693 | ) 1694 | if req['code'] == 0: 1695 | return req['data'] 1696 | 1697 | def update_my_basic_info(self, uname, usersign, sex, birthday): 1698 | """ 1699 | 更新此账号的基本资料 1700 | code=40004 昵称不可包含除-和_以外的特殊字符 1701 | code=40005 昵称太长或包含特殊字符 1702 | code=40014 该昵称已存在 1703 | code=40021 签名不能包含表情图片 1704 | code=40022 签名最多支持70个字 1705 | :param uname: 用户名 1706 | :param usersign: 签名 1707 | :param sex: 性别,男,女,保密 1708 | :param birthday:生日,例:2014-12-01 1709 | :return: 1710 | """ 1711 | req = self.post( 1712 | url='https://api.bilibili.com/x/member/web/update', 1713 | data={ 1714 | 'uname': uname, 1715 | 'usersign': usersign, 1716 | 'sex': sex, 1717 | 'birthday': birthday, 1718 | 'csrf': self.csrf 1719 | } 1720 | ) 1721 | print(req) 1722 | 1723 | def report_add(self, mid, reason): 1724 | """ 1725 | 个人信息举报 1726 | :param mid: 1727 | :param reason: 1.头像违规 2.昵称违规 3.签名违规 选择多项,用逗号隔开1,2,3 1728 | :return: 1729 | """ 1730 | req = self.post( 1731 | url='https://space.bilibili.com/ajax/report/add', 1732 | data={ 1733 | 'mid': mid, 1734 | 'reason': reason, 1735 | 'csrf': self.csrf 1736 | }, 1737 | headers={ 1738 | 'Referer': 'https://space.bilibili.com/%s/' % mid 1739 | } 1740 | 1741 | ) 1742 | print(req) 1743 | 1744 | def watchlater_video_add(self, aid): 1745 | req = self.post( 1746 | url='https://api.bilibili.com/x/v2/history/toview/add', 1747 | data={ 1748 | 'aid': aid, 1749 | 'jsonp': 'jsonp', 1750 | 'csrf': self.csrf 1751 | } 1752 | ) 1753 | print(req) 1754 | 1755 | def old_view(self, avnum): 1756 | """ 1757 | 旧接口,获得稿件信息 1758 | :param avnum: 1759 | :return: 1760 | """ 1761 | req = self.get( 1762 | url='https://api.bilibili.com/view', 1763 | params={ 1764 | 'type': 'jsonp', 1765 | 'appkey': '8e9fc618fbd41e28', 1766 | 'id': avnum 1767 | } 1768 | ) 1769 | print(req) 1770 | 1771 | def old_pagelist(self, aid): 1772 | """ 1773 | 旧接口,获得稿件的分p信息,cid信息 1774 | :param aid: 稿件aid 1775 | :return: 1776 | """ 1777 | req = self.get( 1778 | url='https://www.bilibili.com/widget/getPageList', 1779 | params={'aid': aid} 1780 | ) 1781 | print(req) 1782 | 1783 | def submitArticle(self, infodict): 1784 | """ 1785 | 提交稿件 1786 | code=10009 同一个视频,不能短时间同时提交到不同稿件,请先查看稿件列表是否第一次提交的稿件已经存在。如需在另一个稿件包含该视频,请分开上传提交。 1787 | :param infodict:稿件信息的dict 1788 | :return: 1789 | """ 1790 | req = self.post( 1791 | url='https://member.bilibili.com/x/vu/web/add', 1792 | params={ 1793 | 'csrf': self.csrf 1794 | }, 1795 | data=infodict, 1796 | headers={ 1797 | 'Content-Type': 'application/json;charset=UTF-8' 1798 | } 1799 | ) 1800 | if req['code'] == 0: 1801 | print("[提示]稿件提交成功,稿件ID为<{}>".format(req['data']['aid'])) 1802 | return req['data']['aid'] 1803 | else: 1804 | print("[提示]提交稿件发生错误!返回数据为:"+req) 1805 | 1806 | def get_bangumi_info(self, md): 1807 | """ 1808 | 获得番剧信息 1809 | :param md: 番剧编号 1810 | :return: 1811 | """ 1812 | req = self.get( 1813 | url='https://www.bilibili.com/bangumi/media/md{}/'.format(md), 1814 | ) 1815 | jsdata = re.findall('window.__INITIAL_STATE__=(.*?);\(function\(\)', req) 1816 | return jsdata[0] 1817 | 1818 | def s_get_info(self, aid): 1819 | """ 1820 | 只获得稿件的播放,回复,弹幕数等统计信息 1821 | :param aid: 1822 | :return: 1823 | """ 1824 | req = self.get( 1825 | url='https://api.bilibili.com/x/web-interface/view', 1826 | params={'aid': aid} 1827 | ) 1828 | return req['data']['stat'] 1829 | 1830 | def get_my_archives(self, page=1, pagesplit=10, type=0): 1831 | """ 1832 | 获得我的投稿列表 1833 | :param page: 1834 | :param pagesplit: 分页大小,默认10,最大20 1835 | :param type: 查询类型0.所有 1.审核中 2.已通过 3.未通过 1836 | :return: 1837 | """ 1838 | if type == 1: 1839 | status = 'is_pubing' 1840 | elif type == 2: 1841 | status = 'pubed' 1842 | elif type == 3: 1843 | status = 'not_pubed' 1844 | else: 1845 | status = 'is_pubing,pubed,not_pubed' 1846 | req = self.get( 1847 | url='https://member.bilibili.com/x/web/archives', 1848 | params={ 1849 | 'status': status, 1850 | 'pn': page, 1851 | 'ps': pagesplit 1852 | } 1853 | ) 1854 | return req['data']['arc_audits'] 1855 | 1856 | def getartical(self,aid): 1857 | """ 1858 | 获得稿件数据(编辑稿件) 1859 | :param aid: av号 1860 | :param session: session 1861 | :return: 1862 | """ 1863 | req = self.get( 1864 | url='https://member.bilibili.com/x/web/archive/view', 1865 | params={'aid': aid} 1866 | ) 1867 | return req 1868 | 1869 | def updateArticle(self, datadict): 1870 | """ 1871 | 提交对稿件的修改 1872 | :param datadict: 1873 | :return: 1874 | """ 1875 | data = str(datadict).replace("'", '"').replace('&', '&').replace("'", "'").encode('utf-8') 1876 | req = self.post( 1877 | url='https://member.bilibili.com/x/vu/web/edit', 1878 | data=data, 1879 | headers={'Content-Type': 'application/json;charset=UTF-8'}, 1880 | params={'csrf': self.csrf} 1881 | ) 1882 | print(req) 1883 | 1884 | def getMyChooseArea(self, mid): 1885 | """ 1886 | 查询我的直播间最近使用过的分类 1887 | :param mid:直播间id 1888 | :return: 1889 | """ 1890 | req = self.get( 1891 | url='https://api.live.bilibili.com/room/v1/Area/getMyChooseArea', 1892 | params={'roomid':mid} 1893 | ) 1894 | print(req) 1895 | if req['code'] == 0: 1896 | return req['data'] 1897 | 1898 | def getLiveAreaList(self, show_pinyin=1): 1899 | """ 1900 | 获得直播分类信息 1901 | :param show_pinyin: 1902 | :return: 1903 | """ 1904 | req = self.get( 1905 | url='https://api.live.bilibili.com/room/v1/Area/getList', 1906 | params={'show_pinyin': show_pinyin} 1907 | ) 1908 | print(req) 1909 | 1910 | def startLive(self, room_id, area_id): 1911 | """ 1912 | 开始直播,获取推流码 1913 | :param room_id: 自己直播间id 1914 | :param area_id: 直播间分区id 1915 | :return: 1916 | """ 1917 | req = self.post( 1918 | url='https://api.live.bilibili.com/room/v1/Room/startLive', 1919 | data={ 1920 | 'room_id': room_id, 1921 | 'platform': 'pc', 1922 | 'area_v2': area_id, 1923 | 'csrf_token': self.csrf 1924 | } 1925 | ) 1926 | if req['code'] == 0: 1927 | rtmp_code = req['data']['rtmp']['addr']+req['data']['rtmp']['code'] 1928 | new_link = req['data']['rtmp']['new_link'] 1929 | print("[提示]开播成功,获得推流地址:{}".format(rtmp_code)) 1930 | print("[提示]开播成功,获得new_link:{}".format(new_link)) 1931 | return rtmp_code 1932 | else: 1933 | print("[提示]开播出现问题!code={},message={}".format(req['code'],req['message'])) 1934 | 1935 | def stopLive(self, room_id): 1936 | """ 1937 | 关闭我的直播 1938 | :param room_id: 直播间id 1939 | :return: 1940 | """ 1941 | req = self.post( 1942 | url='https://api.live.bilibili.com/room/v1/Room/stopLive', 1943 | data={ 1944 | 'room_id': room_id, 1945 | 'platform': 'pc', 1946 | 'csrf_token': self.csrf 1947 | } 1948 | ) 1949 | if req['code'] == 0 and req['message'] == '' and req['data']['change'] == 1: 1950 | print("[提示]关播成功!") 1951 | elif req['code'] == 0 and req['message'] == '重复关播' and req['data']['change'] == 0: 1952 | print("[提示]重复关播!请勿重复提交关播请求!") 1953 | else: 1954 | print(req) 1955 | 1956 | def getRoomInfoOld(self, mid): 1957 | """ 1958 | 获得指定用户的直播间信息 1959 | :param mid: 1960 | :return: 1961 | """ 1962 | req = self.get( 1963 | url='https://api.live.bilibili.com/room/v1/Room/getRoomInfoOld', 1964 | params={ 1965 | 'mid': mid 1966 | } 1967 | ) 1968 | if req['code'] == 0 and req['msg'] == 'ok' and req['message'] == 'ok': 1969 | data = req['data'] 1970 | print("[提示]直播间状态:{}".format(data['roomStatus'])) 1971 | print("[提示]轮播状态:{}".format(data['roundStatus'])) 1972 | print("[提示]直播状态:{}".format(data['liveStatus'])) 1973 | print("[提示]直播间地址:{}".format(data['url'])) 1974 | print("[提示]直播间标题:{}".format(data['title'])) 1975 | print("[提示]直播间封面:{}".format(data['cover'])) 1976 | print("[提示]在线人数:{}".format(data['online'])) 1977 | print("[提示]房间ID:{}".format(data['roomid'])) 1978 | print("[提示]直播方式:{}".format(data['broadcast_type'])) 1979 | return True 1980 | else: 1981 | print("[提示]发生错误!返回信息为"+req) 1982 | return False -------------------------------------------------------------------------------- /file/tid.txt: -------------------------------------------------------------------------------- 1 | 1.动画 2 | 24.MAD·AMV 3 | 25.MMD·3D 4 | 27.综合 5 | 47.短片·手书·配音 6 | 3.音乐 7 | 28.原创音乐 8 | 29.三次元音乐 9 | 30.VOCALOID·UTAU 10 | 31.翻唱 11 | 54.OP/ED/OST 12 | 59.演奏 13 | 130.音乐选集 14 | 4.游戏 15 | 17.单机游戏 16 | 19.Mugen 17 | 65.网络游戏 18 | 121.GMV 19 | 136.音游 20 | 171.电子竞技 21 | 172.手机游戏 22 | 173.桌游棋牌 23 | 5.娱乐 24 | 71.综艺 25 | 131.Korea相关 26 | 137.明星 27 | 11.电视剧 28 | 185.国产剧 29 | 187.海外剧 30 | 13.番剧 31 | 32.完结动画 32 | 33.连载动画 33 | 51.资讯 34 | 152.官方延伸 35 | 23.电影 36 | 83.其他国家 37 | 145.日本电影 38 | 147.国产电影 39 | 36.科技 40 | 39.演讲• 公开课 41 | 95.数码 42 | 96.星海 43 | 98.机械 44 | 122.野生技术协会 45 | 124.趣味科普人文 46 | 176.汽车 47 | 119.鬼畜 48 | 22.鬼畜调教 49 | 26.音MAD 50 | 126.人力VOCALOID 51 | 127.教程演示 52 | 129.舞蹈 53 | 20.宅舞 54 | 154.三次元舞蹈 55 | 156.舞蹈教程 56 | 155.时尚 57 | 157.美妆 58 | 158.服饰 59 | 159.资讯 60 | 164.健身 61 | 160.生活 62 | 21.日常 63 | 75.动物圈 64 | 76.美食圈 65 | 138.搞笑 66 | 161.手工 67 | 162.绘画 68 | 163.运动 69 | 174.其他 70 | 165.广告 71 | 166.广告 72 | 167.国创 73 | 153.国产动画 74 | 168.国产原创相关 75 | 169.布袋戏 76 | 167.资讯 77 | 177.纪录片 78 | 37.人文·历史 79 | 178.科学·探索·自然 80 | 179.军事 81 | 180.社会·美食·旅行 82 | 181.影视 83 | 85.短片 84 | 86.特摄 85 | 182.影视杂谈 86 | 183.影视剪辑 87 | 184.预告·资讯 --------------------------------------------------------------------------------