Python 与游戏测试 (小工具篇)

自动化工具 mitmproxy + python 实现游戏协议测试 Mitmproxy是一款开源的代理服务器,可以在 Wireshark 等嗅探工具中使用。它可以拦截网络请求,并对请求进行修改、重定向等操作。通过使用Mitmproxy和Python语言,可以实现游戏协议测试的自动化。​ 对于想实现开头文中所提到的功能还需要实现客户端,以及对于 protobuf 协议的编解码,这里限于篇幅不再讨论,后续有机会再更新。 阅读详情

最近在TesterHome游戏测试群里,有时候会看到有童鞋问,游戏测试人员学了Python,可以干点什么。

(转自testerhome社区  煎饼同学的  社区游戏测试qq群 581529846 )


很多童鞋初学Python,学习了语法和基础类库后,开始迷茫如何实际使用到工作中去,其实Python可以做的事情是很多的,将日常工作的一些事情自动化,对我们的工作效率有很大的提升。

本文面向Py新手,分享一些辅助工作的小工具思路。以下例子都是在Win10 + Py3.5下完成。

调用CMD

subprocess是Python自带的子进程管理模块,定义有数个创建子进程的函数,也提供了一些管理标准流(standard stream)和管道(pipe)的工具,从而在进程间使用文本通信。


简单理解就是,你通过CMD敲的命令,都基本可以用subprocess来实现批量处理。


例子1:批量SVN操作
以更新SVN为例,这是一个频繁的操作,尤其是多个SVN目录需要一一更新的时候,手动起来是挺麻烦的。

import subprocess
subprocess.Popen(r'TortoiseProc.exe /command:update /path:"C:\project\策划文档" /closeonend:0')
subprocess.Popen(r'TortoiseProc.exe /command:update /path:"C:\project\配置文档" /closeonend:0')

例子2:adb命令的封装
做安卓手游测试的时候,adb是常用工具,我们可以通过它,进行apk的安装,卸载,截图,获取APK信息,性能数据,获取手机信息等等操作。

比如获取当前运行在前台的apk的package和activity名称

def run_cmd(cmd):
    """执行CMD命令"""
    p = subprocess.Popen(cmd, stdout=subprocess.PIPE)
    return [i.decode() for i in p.communicate()[0].splitlines()]

def get_apk_info():
    """获取apk的package,activity名称
 :return: list  eg ['com.android.calendar', 'com.meizu.flyme.calendar.AllInOneActivity']
    """
    result = run_cmd("adb shell dumpsys activity top")
    for line in result:
        if line.strip().startswith('ACTIVITY'):
            return line.split()[1].split('/')
print(get_apk_info())


output: ['com.android.calendar', 'com.meizu.flyme.calendar.AllInOneActivity']
比如查看当前apk的内存占用


def get_mem_using(package_name=None):
    """查看apk的内存占用


    :param package_name:
    :return: 单位KB
    """
    if not package_name:
        package_name = get_apk_info()[0]
    result = run_cmd("adb shell dumpsys meminfo {}".format(package_name))
    info = re.search('TOTAL\W+\d+', str(result)).group()
    mem = ''
    try:
        mem = info.split()
    except Exception as e:
        print(info)
        print(e)
    return mem[-1]


output: 37769
比如备份当前apk到桌面


def backup_current_apk(path=r"C:\Users\jianbing\Desktop\apks"):
    package = get_apk_info()[0]
    result = run_cmd("adb shell pm path {}".format(package))
    cmd = "adb pull {} {}".format(result[0].split(":")[-1], os.path.join(path, "{}.apk".format(package)))
    print(cmd)
    run_cmd(cmd)
再进一步,将常用的adb操作封装为一个ADB工具类。社区里也有童鞋之前分享过,传送门。


处理文本


例子:在整个文件夹中搜索关键字


某天策划说,这个版本他删掉了某个道具,让我检查下有没有删漏的地方,这个道具产出的地方不少,最佳的检查方式是各个相关配置表看下还有没有配置这个道具。


那就写个脚本遍历整个文件夹来搜索指定关键字吧。


import os

def get_files_by_suffix(path, suffixes=("txt", "xml"), traverse=True):
    """从path路径下,找出全部指定后缀名的文件


    :param path: 根目录
    :param suffixes: 指定查找的文件后缀名
    :param traverse: 如果为False,只遍历一层目录
    :return:
    """
    file_list = []
    for root, dirs, files in os.walk(path):
        for file in files:
            file_suffix = os.path.splitext(file)[1][1:].lower()   # 后缀名
            if file_suffix in suffixes:
                file_list.append(os.path.join(root, file))
        if not traverse:
            return file_list


    return file_list




if __name__ == '__main__':


    keyword = "XXX宝箱"


    files = get_files_by_suffix(r"C:\project\config")


    for file in files:


        with open(file, 'r', encoding='utf-8', errors='ignore') as f:
            content = f.read().lower()
            position = content.find(keyword.lower())


            if position != -1:
                print("Find in {0}".format(file))
                start = position - 100 if position - 100 > 0 else 0
                end = position + 100 if position + 100 < len(content) else len(content)
                print(content[start:end])
                print("_" * 100)
操作远程服务器


例子1:查看内网发版时间


有时候问开发,最近一次内网服务端发版是什么时候?开发回答:有点忘记了。。那就得自力更生了~


手动方式:使用FTP软件连入内网服务器,查看文件的更新日期,从而知道发版时间。


懒人方式:Py大法好~


paramiko是Python很有名的第三方库,遵循SSH2协议,支持以加密和认证的方式,进行远程服务器的连接。


import paramiko
import time


_transport = paramiko.Transport("192.168.1.10:22")
_transport.connect(username="root", password="XXXXXX")
sftp = paramiko.SFTPClient.from_transport(_transport)


result = sftp.listdir_attr("/data/www/sg/sg_dev/socket/conf/config/treasure")
print("发版时间是:{}".format(time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(result[0].st_mtime))))


sftp.close()
例子2:查看内网报错信息


在进行测试的时候,需要多留意服务端是否有新的报错信息,有些报错在客户端并没有什么表现,比如数据进库失败,手动方式:通过SecureCRT连入内网服务器,CD到Log目录下,然后tail -n 200 sg_error.log 查看最新的报错信息。


于是萌生了写一个小工具来定时检测,发现报错信息就保存起来的想法。


import datetime
import paramiko
import time
import os




class ScanError(object):


    def __init__(self):


        self._ssh = paramiko.SSHClient()
        self.last_error_log = None
        self._init()


    def _init(self):
        os.chdir("data")   # 打算将报错信息保存到data目录下
        self._ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
        self._ssh.connect("192.168.1.10", username="root", password="XXXXXX")


        error_log = self.get_error_log(500)
        self.last_error_log = error_log


        # 检测最近三天有没有报错信息
        today = datetime.date.today()
        yesterday = today - datetime.timedelta(days=1)
        the_day_before_yesterday = today - datetime.timedelta(days=2)


        error_log_str = "\n".join(error_log)
        if error_log_str.find(str(today)) > -1 or error_log_str.find(str(yesterday)) > -1 or error_log_str.find(str(the_day_before_yesterday)) > -1:
            self.save_error_log("error.txt", error_log)
            print('内网最近三天有错误信息,请查看')
            os.popen('error.txt')


    def get_error_log(self, num=200):
        cmd = 'cd /data/www/sg/sg_dev/socket/log&&tail -n {} sg_error.log'.format(num)
        stdin, stdout, stderr = self._ssh.exec_command(cmd)
        error_log = [i.decode("utf-8") for i in stdout.read().splitlines() if i]
        return error_log

  @staticmethod
    def save_error_log(file_name, log: list):
        with open(file_name, 'w', encoding='utf-8') as f:
            f.write("\n".join(log))

   def run_forever(self, interval=30, show_error=True):
        """运行检测工具


        :param interval: 检测间隔
        :param show_error: 是否检测到报错就自动弹出显示
        :return:
        """
        while 1:
            time.sleep(interval)
            error_log = self.get_error_log()


            if error_log != self.last_error_log and "\n".join(set(error_log) - set(self.last_error_log)).find("ERROR") > -1:


                self.last_error_log = error_log
                file_name = time.strftime("%Y-%m-%d-%H-%M-%S.txt", time.localtime(time.time()))
                print('{} 检测到内网有新的错误信息'.format(time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(time.time()))))
                self.save_error_log(file_name, error_log)


                if show_error:
                    os.popen(file_name)
if __name__ == '__main__':
    ScanError().run_forever()
数据库操作


例子:找号功能


内网的服务器建了N多的号,有时候看着排行榜某个帐号,想登录看下数据,可以使用Python写一个连接数据库的找号脚本。


import cymysql


player_name = "XXXXXX"
conn = cymysql.connect(host='XXXXXX', user='sg', passwd='XXXXXX', db="dev", charset='utf8')
cur = conn.cursor()


sql = "select * from Player where name like '%{0}%'".format(player_name)   # 模糊搜索,从玩家名称搜索玩家ID
cur.execute(sql)
for r in cur.fetchall():
    sql = "select * from Account where uid = '{0}'".format(r[0])   # 从玩家ID搜索玩家帐号
    cur.execute(sql)
    for row in cur.fetchall():
        print('{0}, {1}, {2}'.format(r[0], r[1], row[2]))  # 打印相关信息


conn.close()
扩展开发提供的工具


在之前某个项目,开发做了一个给游戏帐号发道具的网页,提供测试使用,操作流程是这样的,在网页上的表单里边,填写玩家的ID,在下拉列表选中要发送的道具(支持模糊搜索),填写数量。


这个网页使用起来,工作效率不高的地方就是,每次添加道具,都需要重新选择道具和填写数量,且添加过程没有记录下来,无法复用。


优化方案,在网页上点击添加道具,其实就是网页给游戏服务器发送了一个HTTP请求,那就直接让Python来代劳吧~


import requests


player_id = 1100000103
server_ip = "192.168.1.21:5000"


data = {"stuffList": []}
url = "http://{}/api/{}/stuff".format(server_ip, player_id)


data["stuffList"].append({"itemID": 1104000007, "number": 1000})  # itemID为1104000007的物品,数量1000
data["stuffList"].append({"itemID": 1104000008, "number": 1000})
data["stuffList"].append({"itemID": 1104000009, "number": 1000})
data["stuffList"].append({"itemID": 1104000010, "number": 1000})
data["stuffList"].append({"itemID": 1104000011, "number": 1000})
data["stuffList"].append({"itemID": 1104000012, "number": 1000})


requests.post(url, json=data, timeout=5)    # 添加道具
# requests.delete(url, json=data, timeout=5)   # 删除道具 

【Python-游戏测试工程师 】8个高实用性的 Python 游戏测试框架 Python游戏测试框架精选:8款工具覆盖自动化、性能、兼容性测试需求。PyAutoGUI适合键鼠模拟操作,Pywinauto提供精准Windows窗口控制;OpenCV和SikuliX处理图像识别测试;Psutil监控游戏资源占用,Py-Spy分析性能瓶颈;Requests用于服务端接口测试。每款框架均提供核心功能说明、适用场景和代码示例,帮助快速搭建专业游戏测试体系,满足不同维度的测试需求。 阅读详情

相关推荐

软件测试与游戏测试文章合集录

一、阅读须知   创作目的: 这是一篇集合笔者个人所创作的文章,涵盖软件测试与游戏测试的领域方面,目的是收集所有个人的文章,让读者们后续只需要记住一篇文章即可从该文章中跳转至对应的文章进行查看,提升便捷性,如果读者是学习软件或游戏测试的小伙伴,笔者强烈的建议收藏,笔者也真诚的希望在各位行业从业中碰到问题时能够从本文章中找到答案,也期望读者在想进行新知识领域探索时,能够优先看到笔者的文章...

萌笑天的博客 4155

【极客日常】游戏测试开发干货——Python进阶与游戏自动化测试攻略

在互联网上,关于游戏测试(开发)领域的技术分享,实际是非常稀少。为此,针对游戏测试(开发)的工作特性,笔者根据自己以前的博客整合了两个文集:《HiKari为了拿捏Python整理的技术笔记》与《HiKari的游戏自动化测试笔记》

HiKariのTechLab 2660

游戏测试专属:Python 循环语句在游戏测试中的8个高频场景

本文解析了Python循环语句在游戏测试中的8个高频应用场景,分为三大类: 1.基础批量处理类(for循环) ;2.动态验证/监控类(while循环);3.数据校验统计类

u013625540的博客 1236

Python语言的游戏测试

Python作为一门功能强大且易于上手的编程语言,在游戏测试中发挥着越来越重要的作用。无论是进行单元测试、功能测试还是自动化测试,Python都能提供丰富的工具和框架来帮助测试人员提高效率和准确性。在未来,随着游戏行业的不断发展,对质量的要求也会越来越高。利用Python进行游戏测试,能够确保游戏在发布前达到预期的质量标准,从而提升玩家的体验。在不断的实践中,游戏测试人员能够更加深入地理解测试的重要性,以及如何利用Python构建高效的测试流程。

2501_91024643的博客 2236

【8周通关Python-游戏测试工程师 】801游戏测试自动化框架——设计与目录搭建

本文介绍了游戏测试自动化框架的设计与目录搭建方案,重点包括框架设计原则(高内聚、低耦合等)和标准目录结构(common、case、data等)。通过实战指导读者创建完整的本地框架目录,并说明各文件夹功能(如common存放工具类、case存放测试用例)。要求完成目录搭建、运行主脚本,并理解框架设计理念,为后续开发奠定基础。本周将逐步完善配置文件、报告生成等功能,最终实现完整的游戏测试自动化流程。验收标准包括目录创建、脚本执行及设计原则掌握程度。

u013625540的博客 944

游戏测试工程师必读好书,你读过几本?

在这里给大家分享一个书单,我们来一起看一看作为一个游戏测试工程师,需要读的经典好书都有哪些。 下面这个书单,有些书是我已经读过的,也有些是其他人推荐的,列在我个人书单里,暂时还没有看过。不过总体上来说,这些书籍都是值得大家去仔细阅读一下的。 测试基础 1、《软件测试》 [美]Ron Patton著,机械工业出版社出版 软件测试行业的经典入门教材。 2、《鸟哥的Linux私房菜-基础篇》 鸟哥著,人民邮电出版社出版 这个应该很出名了吧,相信大家应该都听说过,这本书的基础篇不仅仅讲解了Linux,也涉及很多.

伤心的辣条 1141

【Python自动化】PyAutoGUI在游戏测试中的应用

在日常游戏的稳定性测试挂机中,发现了一些机器在长时间挂机后的崩溃现象,导致游戏进程退回桌面,或在匹配界面挂机。此时可以借助pyautoui库实现自动点击开始游戏并重新匹配。

weixin_44456338的博客 2440

【8周通关Python-游戏测试工程师 】802游戏测试自动化框架——配置文件管理

本文介绍了游戏测试自动化框架中配置文件管理的方法,重点讲解了使用configparser模块管理ini格式的配置文件。文章首先解释了配置文件的作用在于解耦代码与参数,实现灵活调整;然后详细说明了configparser的核心知识点,包括配置文件的格式、结构及基本操作;最后通过实战演示了如何创建config.ini文件、编写配置读取工具类,并在主脚本中复用配置。文中还提供了游戏测试框架常用配置项的参考表格,涵盖服务器、日志、接口和报告等关键配置参数。

u013625540的博客 1044

python做游戏用什么软件_Python 与游戏测试 (小工具篇)

最近在TesterHome游戏测试群里,有时候会看到有童鞋问,游戏测试人员学了Python,可以干点什么。很多童鞋初学Python,学习了语法和基础类库后,开始迷茫如何实际使用到工作中去,其实Python可以做的事情是很多的,将日常工作的一些事情自动化,对我们的工作效率有很大的提升。本文面向Py新手,分享一些辅助工作的小工具思路。以下例子都是在Win10 + Py3.5下完成。调用CMDsubpr...

weixin_39874379的博客 276

【Python-游戏测试工程师 】游戏测试自动化读 Excel + 批量找数据 + 彩色标注列

本文介绍了一个基于Python的Excel道具批量检索工具,无需复杂代码即可快速查找道具信息。 工具特点包括: 1)输入道具名自动检索并高亮显示结果; 2)每列用不同颜色标注,便于识别; 3)支持精准/模糊匹配。 实现步骤: 1)安装Python环境; 2)安装pandas和openpyxl库; 3)复制提供的代码并修改Excel路径即可使用。 该工具能显著提升查找效率,特别适合处理多列大表格的场景。

u013625540的博客 1379

python游戏压力测试机器人客户端(一)

游戏测试机器人搭建 - Player Actor 前言: 第一次写博客,文笔有限,加上半路出身的游测,大佬们别往死里喷,错的地方请指正,在正式介绍之前先简单说下用的框架:Python的 pykka(Actor模型),测试框架 pytest和测试报告 allure: Actors做什么: 当一个actor接收到消息后,它能做如下三件事中的一件: Create more actors; 创建其他actors Send messages to other actors; 向其他actors发送消息 Design

游戏测试-AJiian的博客 4169

python编写测试小工具-Python与游戏测试(小工具篇)

import datetimeimport paramikoimport timeimport osclass ScanError(object):def __init__(self):self._ssh = paramiko.SSHClient()self.last_error_log = Noneself._init()def _init(self):os.chdir("data&q...

weixin_39741101的博客 1056

Ubuntu 22.04蓝牙开关秒关?别慌,可能是这个Intel固件文件在搞鬼

本文深入解析Ubuntu 22.04蓝牙开关秒关问题,指出Intel固件文件缺失是常见原因,并提供详细修复方案。通过确认硬件型号、检查固件文件及智能替代方案,帮助用户快速解决蓝牙故障,提升系统稳定性。

weixin_30247307的博客 752

python软件测试工具_Python与游戏测试(小工具篇)

import datetimeimport paramikoimport timeimport osclass ScanError(object):def __init__(self):self._ssh = paramiko.SSHClient()self.last_error_log = Noneself._init()def _init(self):os.chdir("data") # ...

weixin_39828956的博客 138

从硬件异常到代码救赎:RH850内存访问错误(MAE)的深层诊断与艺术

本文深入探讨瑞萨RH850微控制器的内存访问错误(MAE)诊断与解决方法。针对程序跑飞和Flash Driver交互中的潜在陷阱,提供系统性硬件异常分析框架和防御性编程实践,帮助嵌入式开发者从底层机制到代码层面有效预防和修复MAE问题,提升系统稳定性。

pytorch8learner的博客 189

从零开始:手把手教你规划与部署华为FusionCompute虚拟化平台(含网络规划避坑指南)

本文详细介绍了华为FusionCompute虚拟化平台的规划与部署流程,特别针对网络规划中的常见问题提供了避坑指南。从硬件软件清单检查、网络平面配置到VRM部署方案选择,帮助用户高效完成部署并优化性能,适用于云计算环境中的虚拟化平台搭建。

weixin_28693447的博客 235

总结一下今年米哈游游戏测试开发的面经

游戏测试岗位面经

weixin_44617849的博客 3564

Unity地形数据高效转换:从Terrain到3DMAX的OBJ导出实战

本文详细解析了Unity地形数据无法直接导入3DMAX的原因,并提供了高效转换的实战方案。通过编写自定义编辑器脚本,将Unity Terrain的高度图数据“烘焙”为静态网格模型,并以OBJ格式导出。文章重点讲解了核心代码逻辑、分辨率选择对模型精度的影响,以及在3DMAX中导入和优化模型的实用技巧,旨在打通Unity与3DMAX之间的数据协作壁垒。

sky77的博客 446

【8周通关Python-游戏测试工程师 】105Python 函数

本文摘要:Python函数封装在游戏测试日志分析中的应用。通过将日志分析逻辑拆分为三个可复用函数:parse_log()拆分日志内容、get_log_level()判断日志等级、batch_analyze_logs()批量生成分析报告,实现了脚本的可复用性。学习重点包括函数定义与调用、必选与默认参数的使用,最终通过封装前4天的日志分析脚本,只需调用函数即可分析不同日志,无需修改核心逻辑,提升测试效率。

u013625540的博客 765

什么是 SAPGUI 里的 Logon Group/Server

这意味着,不同的用户连接可以被分配到不同的应用服务器,以实现均衡的资源利用和降低某一服务器的负载压力。在这种配置下,欧洲的用户登录时选择“EUROPE_GROUP”,系统将自动选择一个位于欧洲的数据中心的服务器进行连接,这样不仅减少了网络延迟,还实现了服务器间的负载均衡。用户在 SAPGUI 中登录时,只需选择相应的 Logon Group(例如“FIN_GROUP”),系统就会自动将他们的连接请求分配到当前负载最小的应用服务器上,这种动态分配大大提升了系统的响应速度和稳定性。

2007 年 ~ 2025 年,深耕 SAP 技术 18 年 1059

手把手教你学simulink(41.4)--逆变器电场景示例:基于Simulink的主从控制的多逆变器协同控制(Multi-Inverter Coordinated Control)

需求分析在现代电力系统中,分布式发电和储能系统的广泛应用使得多个逆变器并联运行成为常见的应用场景。为了确保多个逆变器之间的协同工作,实现系统的稳定性和高效性,通常采用主从控制(Master-Slave Control)策略。主从控制通过一个主控制器(Master)来协调多个从控制器(Slave),确保所有逆变器的输出电压、频率和功率分配符合预期目标。本项目将基于Simulink平台,开发一个多逆变器协同控制系统,采用主从控制策略,实现对多个逆变器的精确控制和优化。

MHD0815的博客 299

【8周通关Python-游戏测试工程师 】周计划

本文提供了一个为期8周的Python游戏测试自动化学习计划,计划采用“理论+实践”的每日学习模式(60分钟/天),通过真实游戏测试场景驱动技能提升,最终实现编写实用测试脚本、优化测试流程的目标。

u013625540的博客 1036

Microsemi Libero使用技巧11——CoreUARTAPB RX管脚分配时不显示

调用串口IP核CoreUARTAPB,并例化到顶层设计,发现UART_RX管脚在进行管脚分配时没有显示出来,最后发现是CoreAPB3总线IP核配置不对导致,改为如下配置后正常。

whik1194的博客 748

【8周通关Python-游戏测试工程师】 Python 学习提升计划

本文为游戏测试工程师设计的8周Python学习计划,聚焦自动化测试、日志分析等四大核心应用场景。计划分为基础、进阶、实战和综合四个阶段,包含每日60分钟学习任务和实战脚本编写要求。每周设置具体学习目标和游戏测试实战任务,如日志处理、异常捕获等,并提供复盘模板跟踪进度。学习建议强调使用真实工作素材,推荐VS Code等工具,并鼓励参考开源项目。通过模块化、场景化的学习路径,帮助测试工程师系统掌握Python在游戏测试中的实际应用。

u013625540的博客 865

零基础学习simulink-- 基于自适应模糊PID控制的直流电机速度控制系统

通过上述代码实现,您可以逐步创建和搭建一个基于自适应模糊PID控制的直流电机速度控制系统。该系统能够根据电机的状态和误差实时调整PID参数,确保电机速度稳定在设定范围内。自适应模糊PID控制具有较强的鲁棒性和适应性,能够在存在不确定性和扰动的情况下提供快速且精确的控制性能。Simulink提供了强大的建模和仿真工具,使得控制系统工程师能够快速构建复杂的控制算法,并将其应用于实际工程中。直流电机建模:建立直流电机的动态模型,包括电枢电压、电流、转速和负载扭矩。自适应模糊PID控制器设计。

amy_mhd的博客 408

VB摄像头监控

该VB模块可对摄像头捕获的画面进行录像等,可在创建的窗口进行控制

游戏测试专属:Python 循环语句实战

本文介绍了Python循环语句在游戏测试中的实战应用。通过循环与字符串操作、条件判断的组合应用,游戏测试人员可以高效处理大量测试数据,显著提升工作效率。

u013625540的博客 796

霍尼韦尔SoftMaster使用说明

霍尼韦尔SoftMaster使用说明

上一篇: 测试圈生态文-无锡
下一篇: node.js 压力测试框架.01
jiazurongyu
博客等级 码龄16年 118粉丝 138原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值