def set_order_delivered(): session = HTMLSession() login_url = 'https://knight-stag.castlery.sg/spree/admin/login' login_page = session.get(url=login_url) authenticity_token = login_page.html.xpath( "//input[@name='authenticity_token']/@value")[0] form_data = { "utf8": "✓", "authenticity_token": authenticity_token, "spree_user[email]": "*****@*****.**", "spree_user[password]": "7787782", "spree_user[remember_me]": 0, "commit": "Login" } login_res = session.post(url=login_url, data=form_data) first_order_href = login_res.html.xpath("//tbody/tr[1]/td[10]/a/@href")[0] base_url = 'https://knight-stag.castlery.sg' first_order_url = base_url + first_order_href first_order_edit_page = session.get(url=first_order_url) shipment_id = first_order_edit_page.html.xpath( "//span[@class='shipment-number']/text()")[0] shipped_url = "https://knight-stag.castlery.sg/spree/api/shipments/" + shipment_id + "/ship" shipped_data = {"send_mailer": "true"} admin_token = "c8e776623190ed753b12d457cf81728940a9ff67db4f2992" admin_headers = { "x-spree-token": admin_token, "x-requested-with": "XMLHttpRequest" } make_shipped = session.put(url=shipped_url, headers=admin_headers, data=shipped_data) delivery_url = "https://knight-stag.castlery.sg/spree/api/shipments/" + shipment_id + "/deliver" make_delivery = session.put(url=delivery_url, headers=admin_headers)
def try_http_put(ip, port): info('http') session = HTMLSession() url = 'http://{}:{}/'.format(ip, port) print(url) para = {} res = session.put(url + '/mnt/sdcard/hackit.txt', data='1' * 2048, **para) print(res) print(res.status_code) print(res.text) print(dir(res))
class BiliAPI(object): """ 只有发布视频的功能,但也足够 :) """ ua = { 'User-Agent': 'Mozilla/5.0 (X11; Linux x86_64; rv:71.0) Gecko/20100101 Firefox/71.0', } def __init__(self, sessdata, bili_jct): """ 登录cookies必要的两个参数,都可以从浏览器cookies中获取 一定不要泄漏下面两个参数给别人,否则会有被盗号风险!!! sessdata: 登录凭证 bili_jct: CSRF令牌 """ self.logger = logging.getLogger('Bilibili') self.SESSDATA = sessdata self.bili_jct = bili_jct self.auth_cookies = {'SESSDATA': sessdata, 'bili_jct': bili_jct} self.session = HTMLSession() self.session.cookies = cookiejar_from_dict(self.auth_cookies) self.session.headers = self.ua @classmethod def typelist(cls): """ 查看分区ID表格 """ try: webbrowser.open_new_tab( 'https://gitee.com/nbodyfun/bilibili-API-collect/blob/master/video/video_zone.md' ) except: pass finally: print( '前往网页查看对应分区tID:\nhttps://gitee.com/nbodyfun/bilibili-API-collect/blob/master/video/video_zone.md' ) def publish_video(self, file, *, atitle=None, adesc='', acopyright=2, asource='来源于网络', specified_type=None, specified_tags=None): """ 发布视频总入口 file: 视频文件地址 atitle: 指定视频标题 adesc: 指定视频描述 acopyright: 指定版权 asource: 声明转载来源 specified_type: 指定分区(int), 分区id详见`-l`参数 specified_tags: 指定标签, 字符串逗号分隔 """ file = Path(file) assert file.exists(), f'不存在文件{file}' filename = file.name # 文件名,带后缀 filestem = atitle or file.stem # 文件名,不包含后缀 filesize = file.stat().st_size # 文件大小 self.logger.info(f'视频:{filestem}') # step 1 self.logger.debug('开始预上传视频') res1 = self.preupload(filename=filename, filesize=filesize) upos_uri = res1['upos_uri'].split('//')[-1] auth = res1['auth'] biz_id = res1['biz_id'] chunk_size = res1['chunk_size'] chunks = ceil(filesize / chunk_size) # 批次 # step 2 self.logger.debug(f'准备上传视频') res2 = self.upload_post(upos_uri=upos_uri, auth=auth) upload_id = res2['upload_id'] key = res2['key'] # 存于bilibili的视频文件名(无后缀) bfilestem = re.search(r'/(.*)\.', key).group(1) # step 3 self.logger.debug(f'分{chunks}个批次上传视频') fileio = file.open(mode='rb') self.upload_put(upos_uri=upos_uri, auth=auth, upload_id=upload_id, fileio=fileio, filesize=filesize, chunk_size=chunk_size, chunks=chunks) fileio.close() # step 4 self.upload_finish(upos_uri=upos_uri, auth=auth, filename=filename, upload_id=upload_id, biz_id=biz_id, chunks=chunks) # 选择分区 typeid = specified_type or self.choose_type( title=filestem, bfilestem=bfilestem, desc=adesc)[0] # 选择标签 if not specified_tags: tags = self.choose_tags(title=filestem, bfilestem=bfilestem, typeid=typeid, desc=adesc) tags_text = ','.join(tags) # 以逗号分隔 else: tags_text = specified_tags # 获取视频封面 cover_url = self.choose_cover(bfilestem=bfilestem)[0] # 发布视频 self.pre_add() res = self.add(bfilestem=bfilestem, filestem=filestem, typeid=typeid, tags=tags_text, copyright=acopyright, desc=adesc, cover_url=cover_url, source=asource) aid = res['data']['aid'] bvid = res['data']['bvid'] self.logger.info( f'[{filestem}]发布成功\naid:{aid}\tbvid:{bvid}\n分区ID:{typeid}\t标签:{tags_text}' ) def pre_add(self): url = 'https://member.bilibili.com/x/geetest/pre/add' self.session.get(url, headers={'TE': 'Trailers'}) def add(self, bfilestem, filestem, typeid, tags, source='来源于网络', copyright=2, desc='', cover_url=''): """ 发布视频 不能发布太频繁, B站官方限制**30秒一稿** bfilestem: 存于bilibili的视频文件名(无后缀) filestem: 视频标题 typeid: 分区id tags: 标签,逗号分隔 source: 来源(转载必要) copyright: 1自制 2转载 desc: 视频简介 cover_url: 封面链接 """ url = f'https://member.bilibili.com/x/vu/web/add?csrf={self.bili_jct}' data = { 'copyright': copyright, # 转载 'videos': [{ 'filename': bfilestem, 'title': filestem, 'desc': desc }], 'source': source, # 来源 'tid': typeid, # 分区id # //i0.hdslb.com/bfs/archive/5eb44a83a7b6466a10eef02a044024784462e3fc.jpg 'cover': cover_url, # 封面url 可以不加,b站后台会自动添加 'title': filestem, # 标题 'tag': tags, # 标签 'desc_format_id': 0, # ? 'desc': desc, # 视频简介 'dynamic': filestem + '\n' + desc, # 动态? 'subtitle': { 'open': 0, 'lan': '' } } # 分P相关 # 自制包含:interactive:0; no_reprint:1; copyright:1; if copyright != 2: del data['source'] data['copyright'] = 1 data['interactive'] = 0 data['no_reprint'] = 1 res_json = self.session.post(url, json=data, headers={ 'TE': 'Trailers' }).json() return res_json def choose_cover(self, *, bfilestem, wait_sec=2): """ 轮询等待封面获取 bfilestem: 存于bilibili的视频文件名(无后缀) wait_sec: 等待秒数 """ url = f'https://member.bilibili.com/x/web/archive/recovers?fns={bfilestem}' while True: res_json = self.session.get(url, headers={'TE': 'Trailers'}).json() allow_covers = res_json['data'] if allow_covers: return allow_covers sleep(wait_sec) self.logger.debug('等待封面获取中...') def choose_type(self, *, title, bfilestem=None, desc=''): """ 选择分区 title: 视频标题 bfilestem: 存于bilibili的视频文件名(无后缀) desc: 视频简介 """ url = 'https://member.bilibili.com/x/web/archive/typeid' params = { 'title': title, 'filename': bfilestem, 'desc': desc, # 视频简介 'cover': '', 'groupid': 1, # 暂不清楚用处 'vfea': '' } res_json = self.session.get(url, params=params, headers={ 'TE': 'Trailers' }).json() # print(dumps(res_json, ensure_ascii=False), end='\n'+'-'*50+'\n') best_type = [(i['id'], i['name']) for i in res_json['data']][0] return best_type def choose_tags(self, *, title, bfilestem=None, typeid='', desc='', limit=10): """ 选择标签 title: 视频标题 bfilestem: 存于bilibili的视频文件名(无后缀) typeid: 分区id limit: 10个标签,B站允许最多10个标签 """ url = 'https://member.bilibili.com/x/web/archive/tags' params = { 'typeid': '', # TODO:添加分区貌似有问题,先为空 'title': title, 'filename': bfilestem, 'desc': desc, 'cover': '', 'groupid': 1, 'vfea': '' } res_json = self.session.get(url, params=params, headers={ 'TE': 'Trailers' }).json() # print(dumps(res_json, ensure_ascii=False), end='\n'+'-'*50+'\n') tags = [i['tag'] for i in res_json['data']] if limit: tags = tags[:limit] return tags def preupload(self, *, filename, filesize): """ 预上传视频 filename: 视频文件名,带后缀 filesize: 视频大小 """ url = 'https://member.bilibili.com/preupload' params = { 'name': filename, # 视频名 'size': filesize, # 视频尺寸 'r': 'upos', 'profile': 'ugcupos/bup', 'ssl': 0, 'version': '2.8.9', 'build': '2080900', 'upcdn': 'bda2', 'probe_version': '20200810' # TODO:跟日期相关,可能会改动 } res_json = self.session.get(url, params=params, headers={ 'TE': 'Trailers' }).json() # print(dumps(res_json, ensure_ascii=False, indent=2), end='\n'+'-'*50+'\n') assert res_json['OK'] == 1 self.logger.debug('预上传成功') return res_json def upload_post(self, *, upos_uri, auth): """ 上传视频前的准备工作 upos_uri: preupload返回值 auth: preupload返回值 """ url = f'https://upos-sz-upcdnbda2.bilivideo.com/{upos_uri}?uploads&output=json' res_json = self.session.post(url, headers={'X-Upos-Auth': auth}).json() # print(dumps(res_json, ensure_ascii=False, indent=2), end='\n'+'-'*50+'\n') assert res_json['OK'] == 1 self.logger.debug('上传准备阶段成功') return res_json def upload_put(self, *, upos_uri, auth, upload_id, fileio, filesize, chunk_size, chunks): """ 分批上传视频 upos_uri: preupload返回值 auth: preupload返回值 upload_id: upload_post返回值 fileio: 视频文件的io流 filesize: 视频文件大小 chunk_size: 一个批次上传多大字节的视频,preupload返回值 chunks: 计算得出的该分多少批次上传 """ url = f'https://upos-sz-upcdnbda2.bilivideo.com/{upos_uri}' params = { 'partNumber': None, # 1开始 'uploadId': upload_id, 'chunk': None, # 0开始 'chunks': chunks, 'size': None, # 当前批次size 'start': None, 'end': None, 'total': filesize, } for batchno in range(chunks): start = fileio.tell() batchbytes = fileio.read(chunk_size) params['partNumber'] = batchno + 1 params['chunk'] = batchno params['size'] = len(batchbytes) params['start'] = start params['end'] = fileio.tell() res = self.session.put(url, params=params, data=batchbytes, headers={'X-Upos-Auth': auth}) assert res.status_code == 200 self.logger.debug(f'批次{batchno+1}上传成功') def upload_finish(self, *, upos_uri, auth, filename, upload_id, biz_id, chunks): """ 通知视频已上传完毕 upos_uri: preupload返回值 auth: preupload返回值 filename: 视频文件名,带后缀 upload_id: upload_post返回值 biz_id: preupload返回值 chunks:批次 """ url = f'https://upos-sz-upcdnbda2.bilivideo.com/{upos_uri}' params = { 'output': 'json', 'name': filename, 'profile': 'ugcupos/bup', 'uploadId': upload_id, 'biz_id': biz_id } data = { "parts": [{ "partNumber": i, "eTag": "etag" } for i in range(chunks, 1)] } res_json = self.session.post(url, params=params, json=data, headers={ 'X-Upos-Auth': auth }).json() assert res_json['OK'] == 1
class KaniRequests(object): def __init__(self, headers={}, proxy={}, default_timeout=None, max_retries=3): def __init__(self, *args, **kwargs): if kwargs["connect"] is None: kwargs["connect"] = default_timeout if kwargs["read"] is None: kwargs["read"] = default_timeout return TimeoutSauce.__init__(self, *args, **kwargs) DefaultTimeout = type("DefaultTimeout", (TimeoutSauce, ), {"__init__": __init__}) self.headers = headers self.proxy = proxy self.session = HTMLSession() self.session.headers.update(headers) if proxy != {}: self.session.proxies = proxy # self.session.verify = os.path.join(os.path.dirname(__file__), "FiddlerRoot.pem") self.session.verify = None self.adapters = requests.adapters.HTTPAdapter(max_retries=max_retries) self.adapters.TimeoutSauce = DefaultTimeout requests.adapters.TimeoutSauce = DefaultTimeout self.session.mount("http://", self.adapters) self.session.mount("https://", self.adapters) self.yag = None self.mail_to = None self.subject = None self.log = logging.getLogger(self.__class__.__name__) def set_error_mailer(self, yag, mail_to, subject): self.yag = yag self.mail_to = mail_to self.subject = subject def mount(self, prefix, adapters): self.session.mount(prefix, adapters) self.session.mount(prefix, adapters) def get(self, url, *args, **kwargs): try: kwargs["cookies"] = self.session.cookies result = self.session.get(url, *args, **kwargs) if self.yag is not None: if result.status_code != 200: status_code = result.status_code body = f"status_code is not 200 on Get {url=} {args=} {kwargs=}\n" body += f"{status_code=}" self.yag.send( to=self.mail_to, subject=self.subject, contents=body, ) self.log.error( "Sending error email because of status_code=%s.", status_code) return result except Exception as e: if self.yag is not None: body = f"Error on Get {url=} {args=} {kwargs=}" body += "\n[sys.exe_info]\n" body += str(sys.exc_info()) body = "\n[traceback.format_exc]\n" body += traceback.format_exc() self.yag.send( to=self.mail_to, subject=self.subject, contents=body, ) self.log.error("Sending error email because of Exception=%s.", e) raise def post(self, url, *args, **kwargs): try: kwargs["cookies"] = self.session.cookies result = self.session.post(url, *args, **kwargs) if self.yag is not None: if result.status_code != 200: status_code = result.status_code body = f"status_code is not 200 on Get {url=} {args=} {kwargs=}\n" body += f"{status_code=}" self.yag.send( to=self.mail_to, subject=self.subject, contents=body, ) self.log.error( "Sending error email because of status_code=%s.", status_code) return result except Exception as e: if self.yag is not None: body = f"Error on Get {url=} {args=} {kwargs=}\n" body += "\n[sys.exe_info]\n" body += sys.exc_info() body = "\n[traceback.format_exc]\n" body += traceback.format_exc() self.yag.send( to=self.mail_to, subject=self.subject, contents=body, ) self.log.error("Sending error email because of Exception=%s.", e) raise def put(self, url, *args, **kwargs): kwargs["cookies"] = self.session.cookies return self.session.put(url, *args, **kwargs) def delete(self, url, *args, **kwargs): kwargs["cookies"] = self.session.cookies return self.session.delete(url, *args, **kwargs) def close(self): self.session.close() def cookies_to_dict(self): return dict_from_cookiejar(self.session.cookies) def add_cookies(self, cookies): add_dict_to_cookiejar(self.session.cookies, cookies)