今日破解某app加密app当中用到了谷歌序列化传输

1.请求序列化文件

# Generated by the protocol buffer compiler.  DO NOT EDIT!
# source: xbeiapp.proto
# 用于x呗请求参数的序列化 import sys
_b=sys.version_info[0]<3 and (lambda x:x) or (lambda x:x.encode('latin1'))
from google.protobuf import descriptor as _descriptor
from google.protobuf import message as _message
from google.protobuf import reflection as _reflection
from google.protobuf import symbol_database as _symbol_database
from google.protobuf import descriptor_pb2
# @@protoc_insertion_point(imports) _sym_db = _symbol_database.Default() DESCRIPTOR = _descriptor.FileDescriptor(
name='xbeiapp.proto',
package='',
syntax='proto3',
serialized_pb=_b('\n\x0exbei.proto\"\xd0\x01\n\x0cTerminalInfo\x12\x14\n\x0cterminalType\x18\x01 \x01(\t\x12\x12\n\nappVersion\x18\x02 \x01(\t\x12\x15\n\rsystemVersion\x18\x03 \x01(\t\x12\x11\n\tdeviceKey\x18\x04 \x01(\t\x12\x0c\n\x04lang\x18\x05 \x01(\t\x12\x12\n\nappChannel\x18\x07 \x01(\t\x12\x13\n\x0bproductType\x18\x08 \x01(\t\x12\x13\n\x0bproductName\x18\t \x01(\t\x12\x0f\n\x07\x61ppType\x18\n \x01(\t\x12\x0f\n\x07\x61ppName\x18\x0b \x01(\t\"\xe6\x02\n\x0f\x45nvironmentInfo\x12\x16\n\x0e\x64\x65viceUniqueId\x18\x04 \x01(\t\x12\x10\n\x08\x62lackBox\x18\x05 \x01(\t\x12\x12\n\nintranelIP\x18\x07 \x01(\t\x12\x11\n\tlongiTude\x18\t \x01(\t\x12\x10\n\x08latiTude\x18\n \x01(\t\x12\x0b\n\x03mac\x18\x0b \x01(\t\x12\x0c\n\x04imei\x18\x0c \x01(\t\x12\x15\n\rphoneOperator\x18\r \x01(\t\x12\x13\n\x0bphoneMarker\x18\x0e \x01(\t\x12\x12\n\nphoneModel\x18\x0f \x01(\t\x12\x14\n\x0coperationSys\x18\x11 \x01(\t\x12\x1b\n\x13operationSysVersion\x18\x12 \x01(\t\x12\x12\n\nisEmulator\x18\x18 \x01(\t\x12/\n\nresolution\x18\x13 \x03(\x0b\x32\x1b.EnvironmentInfo.Resolution\x1a\x1d\n\nResolution\x12\x0f\n\x07smartid\x18\x06 \x01(\t\"\x81\x01\n\x08xbei\x12\x13\n\x0bphoneNumber\x18\x03 \x01(\t\x12#\n\x0cterminalInfo\x18\x02 \x03(\x0b\x32\r.TerminalInfo\x12\x10\n\x08\x63odeType\x18\x04 \x01(\t\x12)\n\x0f\x65nvironmentInfo\x18\x05 \x03(\x0b\x32\x10.EnvironmentInfob\x06proto3')
) _TERMINALINFO = _descriptor.Descriptor(
name='TerminalInfo',
full_name='TerminalInfo',
filename=None,
file=DESCRIPTOR,
containing_type=None,
fields=[
_descriptor.FieldDescriptor(
name='terminalType', full_name='TerminalInfo.terminalType', index=0,
number=1, type=9, cpp_type=9, label=1,
has_default_value=False, default_value=_b("").decode('utf-8'),
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
options=None, file=DESCRIPTOR),
_descriptor.FieldDescriptor(
name='appVersion', full_name='TerminalInfo.appVersion', index=1,
number=2, type=9, cpp_type=9, label=1,
has_default_value=False, default_value=_b("").decode('utf-8'),
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
options=None, file=DESCRIPTOR),
_descriptor.FieldDescriptor(
name='systemVersion', full_name='TerminalInfo.systemVersion', index=2,
number=3, type=9, cpp_type=9, label=1,
has_default_value=False, default_value=_b("").decode('utf-8'),
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
options=None, file=DESCRIPTOR),
_descriptor.FieldDescriptor(
name='deviceKey', full_name='TerminalInfo.deviceKey', index=3,
number=4, type=9, cpp_type=9, label=1,
has_default_value=False, default_value=_b("").decode('utf-8'),
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
options=None, file=DESCRIPTOR),
_descriptor.FieldDescriptor(
name='lang', full_name='TerminalInfo.lang', index=4,
number=5, type=9, cpp_type=9, label=1,
has_default_value=False, default_value=_b("").decode('utf-8'),
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
options=None, file=DESCRIPTOR),
_descriptor.FieldDescriptor(
name='appChannel', full_name='TerminalInfo.appChannel', index=5,
number=7, type=9, cpp_type=9, label=1,
has_default_value=False, default_value=_b("").decode('utf-8'),
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
options=None, file=DESCRIPTOR),
_descriptor.FieldDescriptor(
name='productType', full_name='TerminalInfo.productType', index=6,
number=8, type=9, cpp_type=9, label=1,
has_default_value=False, default_value=_b("").decode('utf-8'),
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
options=None, file=DESCRIPTOR),
_descriptor.FieldDescriptor(
name='productName', full_name='TerminalInfo.productName', index=7,
number=9, type=9, cpp_type=9, label=1,
has_default_value=False, default_value=_b("").decode('utf-8'),
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
options=None, file=DESCRIPTOR),
_descriptor.FieldDescriptor(
name='appType', full_name='TerminalInfo.appType', index=8,
number=10, type=9, cpp_type=9, label=1,
has_default_value=False, default_value=_b("").decode('utf-8'),
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
options=None, file=DESCRIPTOR),
_descriptor.FieldDescriptor(
name='appName', full_name='TerminalInfo.appName', index=9,
number=11, type=9, cpp_type=9, label=1,
has_default_value=False, default_value=_b("").decode('utf-8'),
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
options=None, file=DESCRIPTOR),
],
extensions=[
],
nested_types=[],
enum_types=[
],
options=None,
is_extendable=False,
syntax='proto3',
extension_ranges=[],
oneofs=[
],
serialized_start=19,
serialized_end=227,
) _ENVIRONMENTINFO_RESOLUTION = _descriptor.Descriptor(
name='Resolution',
full_name='EnvironmentInfo.Resolution',
filename=None,
file=DESCRIPTOR,
containing_type=None,
fields=[
_descriptor.FieldDescriptor(
name='smartid', full_name='EnvironmentInfo.Resolution.smartid', index=0,
number=6, type=9, cpp_type=9, label=1,
has_default_value=False, default_value=_b("").decode('utf-8'),
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
options=None, file=DESCRIPTOR),
],
extensions=[
],
nested_types=[],
enum_types=[
],
options=None,
is_extendable=False,
syntax='proto3',
extension_ranges=[],
oneofs=[
],
serialized_start=559,
serialized_end=588,
) _ENVIRONMENTINFO = _descriptor.Descriptor(
name='EnvironmentInfo',
full_name='EnvironmentInfo',
filename=None,
file=DESCRIPTOR,
containing_type=None,
fields=[
_descriptor.FieldDescriptor(
name='deviceUniqueId', full_name='EnvironmentInfo.deviceUniqueId', index=0,
number=4, type=9, cpp_type=9, label=1,
has_default_value=False, default_value=_b("").decode('utf-8'),
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
options=None, file=DESCRIPTOR),
_descriptor.FieldDescriptor(
name='blackBox', full_name='EnvironmentInfo.blackBox', index=1,
number=5, type=9, cpp_type=9, label=1,
has_default_value=False, default_value=_b("").decode('utf-8'),
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
options=None, file=DESCRIPTOR),
_descriptor.FieldDescriptor(
name='intranelIP', full_name='EnvironmentInfo.intranelIP', index=2,
number=7, type=9, cpp_type=9, label=1,
has_default_value=False, default_value=_b("").decode('utf-8'),
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
options=None, file=DESCRIPTOR),
_descriptor.FieldDescriptor(
name='longiTude', full_name='EnvironmentInfo.longiTude', index=3,
number=9, type=9, cpp_type=9, label=1,
has_default_value=False, default_value=_b("").decode('utf-8'),
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
options=None, file=DESCRIPTOR),
_descriptor.FieldDescriptor(
name='latiTude', full_name='EnvironmentInfo.latiTude', index=4,
number=10, type=9, cpp_type=9, label=1,
has_default_value=False, default_value=_b("").decode('utf-8'),
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
options=None, file=DESCRIPTOR),
_descriptor.FieldDescriptor(
name='mac', full_name='EnvironmentInfo.mac', index=5,
number=11, type=9, cpp_type=9, label=1,
has_default_value=False, default_value=_b("").decode('utf-8'),
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
options=None, file=DESCRIPTOR),
_descriptor.FieldDescriptor(
name='imei', full_name='EnvironmentInfo.imei', index=6,
number=12, type=9, cpp_type=9, label=1,
has_default_value=False, default_value=_b("").decode('utf-8'),
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
options=None, file=DESCRIPTOR),
_descriptor.FieldDescriptor(
name='phoneOperator', full_name='EnvironmentInfo.phoneOperator', index=7,
number=13, type=9, cpp_type=9, label=1,
has_default_value=False, default_value=_b("").decode('utf-8'),
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
options=None, file=DESCRIPTOR),
_descriptor.FieldDescriptor(
name='phoneMarker', full_name='EnvironmentInfo.phoneMarker', index=8,
number=14, type=9, cpp_type=9, label=1,
has_default_value=False, default_value=_b("").decode('utf-8'),
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
options=None, file=DESCRIPTOR),
_descriptor.FieldDescriptor(
name='phoneModel', full_name='EnvironmentInfo.phoneModel', index=9,
number=15, type=9, cpp_type=9, label=1,
has_default_value=False, default_value=_b("").decode('utf-8'),
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
options=None, file=DESCRIPTOR),
_descriptor.FieldDescriptor(
name='operationSys', full_name='EnvironmentInfo.operationSys', index=10,
number=17, type=9, cpp_type=9, label=1,
has_default_value=False, default_value=_b("").decode('utf-8'),
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
options=None, file=DESCRIPTOR),
_descriptor.FieldDescriptor(
name='operationSysVersion', full_name='EnvironmentInfo.operationSysVersion', index=11,
number=18, type=9, cpp_type=9, label=1,
has_default_value=False, default_value=_b("").decode('utf-8'),
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
options=None, file=DESCRIPTOR),
_descriptor.FieldDescriptor(
name='isEmulator', full_name='EnvironmentInfo.isEmulator', index=12,
number=24, type=9, cpp_type=9, label=1,
has_default_value=False, default_value=_b("").decode('utf-8'),
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
options=None, file=DESCRIPTOR),
_descriptor.FieldDescriptor(
name='resolution', full_name='EnvironmentInfo.resolution', index=13,
number=19, type=11, cpp_type=10, label=3,
has_default_value=False, default_value=[],
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
options=None, file=DESCRIPTOR),
],
extensions=[
],
nested_types=[_ENVIRONMENTINFO_RESOLUTION, ],
enum_types=[
],
options=None,
is_extendable=False,
syntax='proto3',
extension_ranges=[],
oneofs=[
],
serialized_start=230,
serialized_end=588,
) _xbei = _descriptor.Descriptor(
name='xbei',
full_name='xbei',
filename=None,
file=DESCRIPTOR,
containing_type=None,
fields=[
_descriptor.FieldDescriptor(
name='phoneNumber', full_name='xbei.phoneNumber', index=0,
number=3, type=9, cpp_type=9, label=1,
has_default_value=False, default_value=_b("").decode('utf-8'),
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
options=None, file=DESCRIPTOR),
_descriptor.FieldDescriptor(
name='terminalInfo', full_name='xbei.terminalInfo', index=1,
number=2, type=11, cpp_type=10, label=3,
has_default_value=False, default_value=[],
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
options=None, file=DESCRIPTOR),
_descriptor.FieldDescriptor(
name='codeType', full_name='xbei.codeType', index=2,
number=4, type=9, cpp_type=9, label=1,
has_default_value=False, default_value=_b("").decode('utf-8'),
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
options=None, file=DESCRIPTOR),
_descriptor.FieldDescriptor(
name='environmentInfo', full_name='xbei.environmentInfo', index=3,
number=5, type=11, cpp_type=10, label=3,
has_default_value=False, default_value=[],
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
options=None, file=DESCRIPTOR),
],
extensions=[
],
nested_types=[],
enum_types=[
],
options=None,
is_extendable=False,
syntax='proto3',
extension_ranges=[],
oneofs=[
],
serialized_start=591,
serialized_end=720,
) _ENVIRONMENTINFO_RESOLUTION.containing_type = _ENVIRONMENTINFO
_ENVIRONMENTINFO.fields_by_name['resolution'].message_type = _ENVIRONMENTINFO_RESOLUTION
_xbei.fields_by_name['terminalInfo'].message_type = _TERMINALINFO
_xbei.fields_by_name['environmentInfo'].message_type = _ENVIRONMENTINFO
DESCRIPTOR.message_types_by_name['TerminalInfo'] = _TERMINALINFO
DESCRIPTOR.message_types_by_name['EnvironmentInfo'] = _ENVIRONMENTINFO
DESCRIPTOR.message_types_by_name['xbei'] = _xbei
_sym_db.RegisterFileDescriptor(DESCRIPTOR) TerminalInfo = _reflection.GeneratedProtocolMessageType('TerminalInfo', (_message.Message,), dict(
DESCRIPTOR = _TERMINALINFO,
__module__ = 'xbei_pb2'
# @@protoc_insertion_point(class_scope:TerminalInfo)
))
_sym_db.RegisterMessage(TerminalInfo) EnvironmentInfo = _reflection.GeneratedProtocolMessageType('EnvironmentInfo', (_message.Message,), dict( Resolution = _reflection.GeneratedProtocolMessageType('Resolution', (_message.Message,), dict(
DESCRIPTOR = _ENVIRONMENTINFO_RESOLUTION,
__module__ = 'xbei_pb2'
# @@protoc_insertion_point(class_scope:EnvironmentInfo.Resolution)
))
,
DESCRIPTOR = _ENVIRONMENTINFO,
__module__ = 'xbei_pb2'
# @@protoc_insertion_point(class_scope:EnvironmentInfo)
))
_sym_db.RegisterMessage(EnvironmentInfo)
_sym_db.RegisterMessage(EnvironmentInfo.Resolution) xbei = _reflection.GeneratedProtocolMessageType('xbei', (_message.Message,), dict(
DESCRIPTOR = _xbei,
__module__ = 'xbei_pb2'
# @@protoc_insertion_point(class_scope:xbei)
))
_sym_db.RegisterMessage(xbei) # @@protoc_insertion_point(module_scope)

2.返回参数反序列化

# Generated by the protocol buffer compiler.  DO NOT EDIT!
# source: xbei.proto import sys
_b=sys.version_info[0]<3 and (lambda x:x) or (lambda x:x.encode('latin1'))
from google.protobuf import descriptor as _descriptor
from google.protobuf import message as _message
from google.protobuf import reflection as _reflection
from google.protobuf import symbol_database as _symbol_database
from google.protobuf import descriptor_pb2
# @@protoc_insertion_point(imports) _sym_db = _symbol_database.Default() DESCRIPTOR = _descriptor.FileDescriptor(
name='xbei.proto',
package='',
syntax='proto3',
serialized_pb=_b('\n\x0cxbei.proto\">\n\nStatusInfo\x12\x0c\n\x04\x63ode\x18\x01 \x01(\t\x12\x0f\n\x07message\x18\x02 \x01(\t\x12\x11\n\ttimestamp\x18\x03 \x01(\x03\")\n\x06xbei\x12\x1f\n\nstatusInfo\x18\x01 \x03(\x0b\x32\x0b.StatusInfob\x06proto3')
) _STATUSINFO = _descriptor.Descriptor(
name='StatusInfo',
full_name='StatusInfo',
filename=None,
file=DESCRIPTOR,
containing_type=None,
fields=[
_descriptor.FieldDescriptor(
name='code', full_name='StatusInfo.code', index=0,
number=1, type=9, cpp_type=9, label=1,
has_default_value=False, default_value=_b("").decode('utf-8'),
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
options=None, file=DESCRIPTOR),
_descriptor.FieldDescriptor(
name='message', full_name='StatusInfo.message', index=1,
number=2, type=9, cpp_type=9, label=1,
has_default_value=False, default_value=_b("").decode('utf-8'),
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
options=None, file=DESCRIPTOR),
_descriptor.FieldDescriptor(
name='timestamp', full_name='StatusInfo.timestamp', index=2,
number=3, type=3, cpp_type=2, label=1,
has_default_value=False, default_value=0,
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
options=None, file=DESCRIPTOR),
],
extensions=[
],
nested_types=[],
enum_types=[
],
options=None,
is_extendable=False,
syntax='proto3',
extension_ranges=[],
oneofs=[
],
serialized_start=16,
serialized_end=78,
) _xbei = _descriptor.Descriptor(
name='xbei',
full_name='xbei',
filename=None,
file=DESCRIPTOR,
containing_type=None,
fields=[
_descriptor.FieldDescriptor(
name='statusInfo', full_name='xbei.statusInfo', index=0,
number=1, type=11, cpp_type=10, label=3,
has_default_value=False, default_value=[],
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
options=None, file=DESCRIPTOR),
],
extensions=[
],
nested_types=[],
enum_types=[
],
options=None,
is_extendable=False,
syntax='proto3',
extension_ranges=[],
oneofs=[
],
serialized_start=80,
serialized_end=121,
) _xbei.fields_by_name['statusInfo'].message_type = _STATUSINFO
DESCRIPTOR.message_types_by_name['StatusInfo'] = _STATUSINFO
DESCRIPTOR.message_types_by_name['xbei'] = _xbei
_sym_db.RegisterFileDescriptor(DESCRIPTOR) StatusInfo = _reflection.GeneratedProtocolMessageType('StatusInfo', (_message.Message,), dict(
DESCRIPTOR = _STATUSINFO,
__module__ = 'xbei_pb2'
# @@protoc_insertion_point(class_scope:StatusInfo)
))
_sym_db.RegisterMessage(StatusInfo) xbei = _reflection.GeneratedProtocolMessageType('xbei', (_message.Message,), dict(
DESCRIPTOR = _xbei,
__module__ = 'xbei_pb2'
# @@protoc_insertion_point(class_scope:xbei)
))
_sym_db.RegisterMessage(xbei) # @@protoc_insertion_point(module_scope)

3.序列化部分py代码

    def util(self, ip):
data_pb = shengbei_pb2.xbei()
terminalInfo = data_pb.terminalInfo.add()
environmentInfo = data_pb.environmentInfo.add() resolution = environmentInfo.resolution.add() terminalInfo.terminalType = "app"
terminalInfo.appVersion = "7.14.0"
terminalInfo.systemVersion = self.device_info['version']
terminalInfo.deviceKey = self.device_info['imei']
terminalInfo.lang = "CN"
terminalInfo.appChannel = "xxxx"
terminalInfo.productType = "loan"
terminalInfo.productName = "bbd_android"
terminalInfo.appType = "android"
terminalInfo.appName = "xxxxx" environmentInfo.deviceUniqueId = self.device_info['uniqueId']
environmentInfo.blackBox = self.device_info['black_box']
environmentInfo.intranelIP = ip
environmentInfo.longiTude = self.log1
environmentInfo.latiTude = self.lat1
environmentInfo.mac = self.device_info['mac']
environmentInfo.imei = self.device_info['imei']
environmentInfo.phoneOperator = "未知"
environmentInfo.phoneMarker = "LGE"
environmentInfo.phoneModel = self.device_info['mobile']
environmentInfo.operationSys = "android"
environmentInfo.operationSysVersion = self.device_info['version']
resolution.smartid = self.device_info['smartid']
environmentInfo.isEmulator = "false"
data_pb.phoneNumber = self.phone
data_pb.codeType = "02"
return data_pb.SerializeToString()

4.反序列化部分py代码

data_pb = shengb_pb2.xbei()
data_pb.ParseFromString(content)

最新文章

  1. 变量声明---let,const,解构
  2. php单点登录之模拟淘宝天猫同步登录
  3. 在SQL Server中将数据导出为XML和Json
  4. label的for属性
  5. webpack 代码拆分,按需加载
  6. 剑指offer(07)-调整数组顺序使奇数位于偶数前面【转】
  7. 页面异步加载javascript文件
  8. 基于HOOK和MMF的Windows密码渗透技术
  9. js中的if判断十分优美的简洁写法
  10. 位图9宫格 BitmapSlice9.jsfl
  11. Python基础:1.数据类型(列表)
  12. Java多线程初学者指南(5):join方法的使用
  13. GFF 和 OGS 这两种触摸屏谁更好?
  14. ./scripts/feeds update -a OpenWrt大招系列
  15. [WebGL入门]二十四,补色着色
  16. ERP中通过EDI导入资料的时候出现【Microsoft Office Excel不能访问文件‘C:\Windows\TEMP\433....’
  17. jvm内存结构(一)
  18. RabbitMQ是如何运转的?
  19. 生成命令行接口--google开源的fire使用体验【python-fire】
  20. [PHP] 数据结构-输出链表倒数第k个结点PHP实现

热门文章

  1. argis android sdk配置备忘一下
  2. 第5章函数进阶 第5.1节 Python函数的位置参数、关键字参数精讲
  3. moviepy音视频剪辑:moviepy中的剪辑相关类及关系
  4. 第15.16节 PyQt(Python+Qt)入门学习:PyQt中的信号(signal)和槽(slot)机制以及Designer中的使用
  5. AWD不死马与克制方法
  6. 对巡风vulscan的理解
  7. 【Azure Developer】VS Code运行Java 版Azure Storage SDK操作Blob (新建Container, 上传Blob文件,下载及清理)
  8. python web的一些常见技术面试笔试题
  9. [从源码学设计]蚂蚁金服SOFARegistry之推拉模型
  10. 2020传智博黑马python课