def login_by_access_token(access_token): """ bilibili access token login. Args: access_token: Bilibili access token got by previous username/password login. Returns: sid: session id. mid: member id. expires_in: access token expire time """ headers = { 'Connection': 'keep-alive', 'Accept-Encoding': 'gzip,deflate', 'Host': 'passport.bilibili.com', 'User-Agent': '', } login_params = { 'appkey': APPKEY, 'access_token': access_token, 'platform': "pc", 'ts': str(int(datetime.now().timestamp())), } login_params['sign'] = cipher.sign_dict(login_params, APPSECRET) r = requests.get(url="https://passport.bilibili.com/api/oauth2/info", headers=headers, params=login_params) login_data = r.json()['data'] return r.cookies['sid'], login_data['mid'], login_data["expires_in"]
def get_key(sid=None, jsessionid=None): """ get public key, hash and session id for login. Args: sid: session id. only for captcha login. jsessionid: j-session id. only for captcha login. Returns: hash: salt for password encryption. pubkey: rsa public key for password encryption. sid: session id. """ headers = { 'Content-Type': 'application/x-www-form-urlencoded', 'Accept': "application/json, text/javascript, */*; q=0.01" } post_data = { 'appkey': APPKEY, 'platform': "pc", 'ts': str(int(datetime.now().timestamp())) } post_data['sign'] = cipher.sign_dict(post_data, APPSECRET) cookie = {} if sid: cookie['sid'] = sid if jsessionid: cookie['JSESSIONID'] = jsessionid r = requests.post("https://passport.bilibili.com/api/oauth2/getKey", headers=headers, data=post_data, cookies=cookie) r_data = r.json()['data'] if sid: return r_data['hash'], r_data['key'], sid return r_data['hash'], r_data['key'], r.cookies['sid']
def upload_cover(access_token, sid, cover_file_path): with open(cover_file_path, "rb") as f: cover_pic = f.read() headers = { 'Connection': 'keep-alive', 'Host': 'member.bilibili.com', 'Accept-Encoding': 'gzip,deflate', 'User-Agent': '', } params = { "access_key": access_token, } params["sign"] = cipher.sign_dict(params, APPSECRET) files = { 'file': ("cover.png", cover_pic, "Content-Type: image/png"), } r = requests.post( "http://member.bilibili.com/x/vu/client/cover/up", headers=headers, params=params, files=files, cookies={'sid': sid}, verify=False, ) return r.json()["data"]["url"]
def get_capcha(sid, file_name=None): headers = { 'User-Agent': '', 'Accept-Encoding': 'gzip,deflate', } params = { 'appkey': APPKEY, 'platform': 'pc', 'ts': str(int(datetime.now().timestamp())) } params['sign'] = cipher.sign_dict(params, APPSECRET) r = requests.get("https://passport.bilibili.com/captcha", headers=headers, params=params, cookies={'sid': sid}) print(r.status_code) capcha_data = r.content if file_name is not None: with open(file_name, 'wb+') as f: f.write(capcha_data) return r.cookies['JSESSIONID'], capcha_data
def get_type_info(access_key): tag_get_data = {"access_key": access_key, "build": "1054"} tag_get_data["sign"] = cipher.sign_dict(tag_get_data, APPSECRET) r = requests.get(url=TYPE_INFO_ADDR, params=tag_get_data) data = r.json()["data"] typelist = data["typelist"] print(typelist) result = [] for video_type_1 in typelist: vt1_str = "## {}: {}\n\n".format(video_type_1["id"], video_type_1["name"]) if "children" in video_type_1: children = video_type_1["children"] children_list = [] for video_type_2 in children: vt2_str = "{}: {}\n\n".format(video_type_2["id"], video_type_2["name"]) children_list.append((video_type_2["id"], vt2_str)) children_list.sort(key=lambda x: x[0]) for i, s in children_list: vt1_str += s result.append((video_type_1["id"], vt1_str)) result.sort(key=lambda x: x[0]) for i, s in result: print(s)
def get_post_data(access_token, sid, avid): headers = { 'Connection': 'keep-alive', 'Host': 'member.bilibili.com', 'Accept-Encoding': 'gzip,deflate', 'User-Agent': '', } params = { "access_key": access_token, "aid": avid, "build": "1054" } params["sign"] = cipher.sign_dict(params, APPSECRET) r = requests.get( url="http://member.bilibili.com/x/client/archive/view", headers=headers, params=params, cookies={ 'sid': sid } ) return r.json()["data"]
def login(username, password): """ bilibili login. Args: username: plain text username for bilibili. password: plain text password for bilibili. Returns: access_token: token for further operation. refresh_token: token for refresh access_token. sid: session id. mid: member id. expires_in: access token expire time (30 days) """ hash, pubkey, sid = get_key() encrypted_password = cipher.encrypt_login_password(password, hash, pubkey) url_encoded_username = parse.quote_plus(username) url_encoded_password = parse.quote_plus(encrypted_password) post_data = { 'appkey': APPKEY, 'password': url_encoded_password, 'platform': "pc", 'ts': str(int(datetime.now().timestamp())), 'username': url_encoded_username } post_data['sign'] = cipher.sign_dict(post_data, APPSECRET) # avoid multiple url parse post_data['username'] = username post_data['password'] = encrypted_password headers = { 'Connection': 'keep-alive', 'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8', 'User-Agent': '', 'Accept-Encoding': 'gzip,deflate', } r = requests.post("https://passport.bilibili.com/api/oauth2/login", headers=headers, data=post_data, cookies={'sid': sid}) login_data = r.json()['data'] return login_data['access_token'], login_data[ 'refresh_token'], sid, login_data['mid'], login_data["expires_in"]
def edit_videos(access_token, sid, mid, avid=None, bvid=None, parts=None, insert_index=None, copyright=None, title=None, tid=None, tag=None, desc=None, source=None, cover=None, no_reprint=None, open_elec=None, max_retry: int = 5, thread_pool_workers: int = 1): """ insert videos into existed post. Args: access_token: oauth2 access token. sid: session id. mid: member id. avid: av number, bvid: bv string, parts: VideoPart list. insert_index: new video index. copyright: 原创/转载. title: 投稿标题. tid: 分区id. tag: 标签. desc: 投稿简介. source: 转载地址. cover: cover url. no_reprint: 可否转载. open_elec: 充电. max_retry: max retry time for each chunk. thread_pool_workers: max upload threads. Returns: (aid, bvid) aid: av号 bvid: bv号 """ if not avid and not bvid: print("please provide avid or bvid") return None, None if not avid: avid = cipher.bv2av(bvid) if not isinstance(parts, list): parts = [parts] if type(avid) is str: avid = int(avid) post_video_data = get_post_data(access_token, sid, avid) status = True with ThreadPoolExecutor(max_workers=thread_pool_workers) as tpe: t_list = [] for video_part in parts: print("upload {} added in pool".format(video_part.title)) t_obj = tpe.submit(upload_video_part, access_token, sid, mid, video_part, max_retry) t_obj.video_part = video_part t_list.append(t_obj) for t_obj in as_completed(t_list): status = status and t_obj.result() print("video part {} finished, status: {}".format( t_obj.video_part.title, t_obj.result())) if not status: print("upload failed") return None, None headers = { 'Connection': 'keep-alive', 'Content-Type': 'application/json', 'User-Agent': '', } submit_data = { 'aid': avid, 'build': 1054, 'copyright': post_video_data["archive"]["copyright"], 'cover': post_video_data["archive"]["cover"], 'desc': post_video_data["archive"]["desc"], 'no_reprint': post_video_data["archive"]["no_reprint"], 'open_elec': post_video_data["archive_elec"]["state"], # open_elec not tested 'source': post_video_data["archive"]["source"], 'tag': post_video_data["archive"]["tag"], 'tid': post_video_data["archive"]["tid"], 'title': post_video_data["archive"]["title"], 'videos': post_video_data["videos"] } # edit archive data if copyright: submit_data["copyright"] = copyright if title: submit_data["title"] = title if tid: submit_data["tid"] = tid if tag: submit_data["tag"] = tag if desc: submit_data["desc"] = desc if source: submit_data["source"] = source if cover: submit_data["cover"] = cover if no_reprint: submit_data["no_reprint"] = no_reprint if open_elec: submit_data["open_elec"] = open_elec if type(insert_index) is int: for i, video_part in enumerate(parts): submit_data['videos'].insert( insert_index + i, { "desc": video_part.desc, "filename": video_part.server_file_name, "title": video_part.title }) elif insert_index is None: for video_part in parts: submit_data['videos'].append({ "desc": video_part.desc, "filename": video_part.server_file_name, "title": video_part.title }) else: print("wrong insert index") return None, None params = { 'access_key': access_token, } params['sign'] = cipher.sign_dict(params, APPSECRET) r = requests.post( url="http://member.bilibili.com/x/vu/client/edit", params=params, headers=headers, verify=False, cookies={'sid': sid}, json=submit_data, ) print("edit submit") print(r.status_code) print(r.content.decode()) data = r.json()["data"] return data["aid"], data["bvid"]
def upload(access_token, sid, mid, parts, copyright: int, title: str, tid: int, tag: str, desc: str, source: str = '', cover: str = '', no_reprint: int = 0, open_elec: int = 1, max_retry: int = 5, thread_pool_workers: int = 1): """ upload video. Args: access_token: oauth2 access token. sid: session id. mid: member id. parts: VideoPart list. copyright: 原创/转载. title: 投稿标题. tid: 分区id. tag: 标签. desc: 投稿简介. source: 转载地址. cover: 封面图片文件路径. no_reprint: 可否转载. open_elec: 充电. max_retry: max retry time for each chunk. thread_pool_workers: max upload threads. Returns: (aid, bvid) aid: av号 bvid: bv号 """ if not isinstance(parts, list): parts = [parts] status = True with ThreadPoolExecutor(max_workers=thread_pool_workers) as tpe: t_list = [] for video_part in parts: print("upload {} added in pool".format(video_part.title)) t_obj = tpe.submit(upload_video_part, access_token, sid, mid, video_part, max_retry) t_obj.video_part = video_part t_list.append(t_obj) for t_obj in as_completed(t_list): status = status and t_obj.result() print("video part {} finished, status: {}".format( t_obj.video_part.title, t_obj.result())) if not status: print("upload failed") return None, None # cover if os.path.isfile(cover): try: cover = upload_cover(access_token, sid, cover) except: cover = '' else: cover = '' # submit headers = { 'Connection': 'keep-alive', 'Content-Type': 'application/json', 'User-Agent': '', } post_data = { 'build': 1054, 'copyright': copyright, 'cover': cover, 'desc': desc, 'no_reprint': no_reprint, 'open_elec': open_elec, 'source': source, 'tag': tag, 'tid': tid, 'title': title, 'videos': [] } for video_part in parts: post_data['videos'].append({ "desc": video_part.desc, "filename": video_part.server_file_name, "title": video_part.title }) params = { 'access_key': access_token, } params['sign'] = cipher.sign_dict(params, APPSECRET) r = requests.post( url="http://member.bilibili.com/x/vu/client/add", params=params, headers=headers, verify=False, cookies={'sid': sid}, json=post_data, ) print("submit") print(r.status_code) print(r.content.decode()) data = r.json()["data"] return data["aid"], data["bvid"]
def login_captcha(username, password, sid): """ bilibili login with captcha. depend on captcha recognize service, please do not use this as first choice. Args: username: plain text username for bilibili. password: plain text password for bilibili. sid: session id Returns: code: login response code (0: success, -105: captcha error, ...). access_token: token for further operation. refresh_token: token for refresh access_token. sid: session id. mid: member id. expires_in: access token expire time (30 days) """ jsessionid, captcha_img = get_capcha(sid) captcha_str = recognize_captcha(captcha_img) hash, pubkey, sid = get_key(sid, jsessionid) encrypted_password = cipher.encrypt_login_password(password, hash, pubkey) url_encoded_username = parse.quote_plus(username) url_encoded_password = parse.quote_plus(encrypted_password) post_data = { 'appkey': APPKEY, 'captcha': captcha_str, 'password': url_encoded_password, 'platform': "pc", 'ts': str(int(datetime.now().timestamp())), 'username': url_encoded_username } post_data['sign'] = cipher.sign_dict(post_data, APPSECRET) # avoid multiple url parse post_data['username'] = username post_data['password'] = encrypted_password post_data['captcha'] = captcha_str headers = { 'Connection': 'keep-alive', 'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8', 'User-Agent': '', 'Accept-Encoding': 'gzip,deflate', } r = requests.post("https://passport.bilibili.com/api/oauth2/login", headers=headers, data=post_data, cookies={ 'JSESSIONID': jsessionid, 'sid': sid }) response = r.json() if response['code'] == 0: login_data = response['data'] return response['code'], login_data['access_token'], login_data[ 'refresh_token'], sid, login_data['mid'], login_data["expires_in"] else: return response['code'], None, None, sid, None, None