Airtest+python+selenium 一套轻量级web自动化测试框架

在这里插入图片描述

Aritest 简介

Airtest是一套跨平台的测试框架,它提供了跨平台的API,包括安装应用、模拟输入、断言等。 基于图像识别技术定位UI元素,你无需嵌入任何代码即可进行自动化测试。测试脚本运行后可以自动生成详细的HTML测试报告,让你迅速定位失败的测试点,适用于游戏、App和web,支持平台有Windows、Android、iOS和浏览器。

Airtest 集成的多个测试框架,基于web自动化测试的selenuim框架,基于Chrome Devtools Protocol协议,自动录制生成selenium脚本,精确定位与操作界面元素,支持多浏览器(Chrome、Safari、Firfox等主流浏览器);Poco基于UI控件识别的自动化框架,目前支持Unity3D/cocos2dx-/Android原生app/iOS原生app/微信小程序,也可以在其他引擎中自行接入poco-sdk来使用。

AirtestIDE 是一个强大的GUI工具,是网易配套推出的跨平台UI自动化测试编辑器,它内置了Airtest和Poco的相关插件功能,可以帮助你快速简单地完成录制、编写脚本。

在这里插入图片描述

​ 【Airtest-selenium测试框架原理图】

语言基础(python)

使用Airtest这一套框架,对开发编程语言的能力要求不不高,只要了解python的基本语法,具备基础的python编写脚本的能力即可。

python 特点/特性:

【1】 - 易于学习,入门所需时间极短

【2】- 少量代码即可实现功能,python代码非常精简,只需要少量代码即可构造更多功能

【3】 - 可扩展性非常好,python上有各种各样的模块、工具库,导入即可使用

【4】 - 支持多平台Windows/Linux/macOS,python作为目前美国高校最受欢迎的编程语言之一,可在多个领域平台中广泛使用

【5】- 可与多种编程语言集成(C/Java/C#/ObjectC/Ruby等),且实现稳定性一流。

web测试基础知识

要实现web的自动化测试,需要对web的基础知识和基础概念有基本的了解。

【1】HTML文档的基本构成,HEAD头部包含网页标题,BODY展示网站主体内容,各种类型标签/属性

【2】CSS基本的规则结构,选择器(selector)和声明块(declaration blocks),每个声明则是一个属性-值(property-value)

【3】CSS通配选择器(*universal selector)类选择器(.class selector)ID选择器(#ID selector)类选择器结合元素选择器(element.class selector)多类选择器(.class.class selector)属性选择器(attribute selector)

【4】理解DOM和element之间的关联,DOM并不是JavaScript语言的一部分,它是浏览器的一部分,可以通过JavaScript语言的document对象全局访问,也就是说, html 文件通过浏览器解析,解析之后就形成了一颗 DOM 树,可以通过JavaScript 来动态修改 html 的内容,也就是修改网页的内容和排版。

【5】Selenium提供的常用定位方式,ID,Name,Class,CSS selector和xpath。

完整的测试流程

一个完整的测试流程应该包含哪些?

【1】首先,要有清晰的测试需求,明确要进行测试的对象、范围以及测试目的;测试是一个持续性可重复操作的一个验证过程,在不同的阶段,对于不同的项目系统/产品,存在不同的测试目的及测试手段,测试对象及范围都不一样的。清楚当前将要进行的测试是为了达到什么目的,收到什么样的成果以及需要达到一个什么程度,定下项目的测试范围。

【2】明确了测试对象,测试需求也理清楚了,就可以开始制定测试方案。 选用什么框架、需要什么辅助的技术工具、支持什么平台、需要什么样的测试环境,当这一切方案都定下来,就可以开始着手编写测试用例。

【3】规范的测试用例,包含步骤(STEPS)的详细描述,对应测试的预期结果(EXPECT RESULT),运行该测试的预设条件(PRECONDTION),该测试用例的要用到测试数据(TEST-DATA),很多公司特别是大公司对用例的模板规范都有着严格的要求。 对于自动化测试来说,同样重要。

【4】编写脚本,在代码脚本中适当地注释对于以后维护起着相当重要的作用,特别是如果代码行比较多的情况下。通常会优先选择基础功能验证的自动化,可替代手工式黑盒的日常回归测试。因为并非所有的测试用例都适合做自动化测试,因而一般会选择比较核心的单一功能来实现;而测试脚本的每个用例也是尽量精简,多个精简的用例串起来执行就可以是一个完整的测试流程,尽量避免一个脚本跑太复杂的用例测试,当一个测试脚本包含太多步骤的时候,不仅仅会耗费的时间同样会增加调式的难度,以及日后脚本维护的复杂度。

【5】测试脚本完成,通过调试,测试环境也搭建好了,就可以执行测试脚本,查看测试报告,记录反馈BUG,定时执行测试。

安装与环境搭建

Airtest是基于python语言开发的测试框架,需要先把python环境搭建好,再安装Airtest/AirtestIDE。安装时需要注意的是版本的依赖关系,最新版python没有airtest依赖的库,而且最新版本python没有二进制的只有源码,所以搭建时建议使用的是旧一点2.7版本的python :

• Latest Python 2 Release - Python 2.7.15

搭建python环境

到python官网下载对应系统的压缩包:

https://www.python.org/

在这里插入图片描述

1)Window 平台安装Python

下载对应的压缩包版本 :https://www.python.org/downloads/release/python-2715/

在这里插入图片描述

64位系统的下载Windows x86-64 MSI installer,32位系统的下载Windows x86 MSIinstaller

python的安装非常简单,下载后打开安装包,按照python的安装向导一直next即可完成,安装时记得要把Add to

path 打勾就不需要自己修改环境变量了 。

2)MAC 平台安装Python

系统是OS X 10.8或者最新的10.9 Mavericks的MAC是自带python2.7的,如果OS版本没有包含,自行去下载即可.

在这里插入图片描述

用 dmg / pkg 安装包进行安装,如果有安装 brew 的话就可以通过命令行进行安装。

3)Unix & Linux 平台安装Python

下载适用于Unix/Linux 的源码压缩包(source tarball)

解压压缩包

执行 ./configure 脚本

make

make install

安装完成后,Python 会在 /usr/local/bin 目录下,Python 的库一般安装在/usr/local/lib/pythonXX

设置环境变量,export

PATH="$PATH:/usr/local/bin/python"

下载并安装Airtest/AirtestIDE

执行以下命令进行安装:

pip install airtest

需要注意,当时安装Airtest的时候遭遇失败,原因是最新版本的python没有airtest依赖的库,在最新版本python没有二进制的只有源码,所以干脆就重新安装一个旧的2.7版本的python了。

在这里插入图片描述

安装成功!

官网上下载对应系统的最新版IDE:http://airtest.netease.com/changelog.html

在这里插入图片描述

下载后解压即可用

IDE使用指南

1 - 启动IDE

2 - 录制脚本

3 - 编写脚本

4 - 运行脚本

5 - 查看测试报告

启动

进入已解压的AirtestIDE目录,打开AirtestIDE的应用程序,IDE会运行一个后台服务以及一个IDE应用界面窗口

在这里插入图片描述

IDE启动后默认的界面布局如下图:

在这里插入图片描述

录制web测试脚本

AirtestIDE 默认没有不会打开web录制的窗口,需要手动去打开:

在这里插入图片描述

打开web录制窗口后,第一次运行需要修改一下IDE对浏览器的设置,打开选项 - 设置(setting),配置selenium打开浏览器应用程序的路径

在这里插入图片描述

快速操作按键打开一个新脚本文件,通过selenium window打开一个新的录制窗口:

在这里插入图片描述

Do you want to insert poco init code at the current curosr position [Yes] [No] 是否导入初始化代码到光标所在位置,选择【Yes】之后会导入selenium相关的依赖库,只在第一次需要导入。

通过selenium window - start_web 打开一个新页面,输入需要进行测试的URL地址:

在这里插入图片描述

在刚打开录制的浏览器窗口,输入测试URL地址,点击selenium window - 录制按钮,即可开始录制测试脚本:

在这里插入图片描述

selenium 窗口还提供了一些常用的录制操作,如下图所示:
在这里插入图片描述

编写脚本

脚本编辑窗口右上角有一个小菜单,可以快速打开该脚本的报告目录、报告、打开最后运行的日志报告和清理运行截图

在这里插入图片描述

Web 录制无法模拟的按键操作,可以手动通过代码来完成,比如send keys, keys.ENTER 等等。

常见的操作元素方法如下:

  • clear 清除元素的内容

  • send_keys 模拟按键输入

  • click 点击元素

  • submit 提交表单send_keys(Keys.RETURN)相当于回车登录, 如果需要输入中文,防止编码错误使用send_keys(u"中文用户名")

通过WebElement接口可以获取常用的值:

  • size 获取元素的尺寸

  • text 获取元素的文本

  • get_attribute(name) 获取属性值

  • location 获取元素坐标,先找到要获取的元素,再调用该方法

  • page_source 返回页面源码

  • driver.title 返回页面标题

  • current_url 获取当前页面的URL

  • is_displayed() 设置该元素是否可见

  • is_enabled() 判断元素是否被使用

  • is_selected() 判断元素是否被选中

  • tag_name 返回元素的tagName

常见键盘操作

  • send_keys(Keys.ENTER) 按下回车键

  • send_keys(Keys.TAB) 按下Tab制表键

  • send_keys(Keys.SPACE) 按下空格键space

  • send_keys(Kyes.ESCAPE) 按下回退键Esc

  • send_keys(Keys.BACK_SPACE) 按下删除键BackSpace

  • send_keys(Keys.SHIFT) 按下shift键

  • send_keys(Keys.CONTROL) 按下Ctrl键

  • send_keys(Keys.ARROW_DOWN) 按下鼠标光标向下按键

  • send_keys(Keys.CONTROL,‘a’) 组合键全选Ctrl+A

  • send_keys(Keys.CONTROL,‘c’) 组合键复制Ctrl+C

  • send_keys(Keys.CONTROL,‘x’) 组合键剪切Ctrl+X

  • send_keys(Keys.CONTROL,‘v’) 组合键粘贴Ctrl+V

运行脚本

执行菜单栏下的快捷操作按钮运行脚本:

在这里插入图片描述

脚本运行时,log查看窗口会实时打印代码运行日志:

在这里插入图片描述

包含脚本启动信息,语句执行情况,截图位置,运行结果及耗费时间。

查看测试报告

执行菜单栏下的快捷操作按钮查看测试报告:

在这里插入图片描述

测试报告包含测试用例目录名称,作者,运行时间,测试点汇总,每个步骤的执行时间、测试内容、截图及运行结果

在这里插入图片描述

AirtestIDE官方说明文档

https://airtest.netease.com/docs/docs_AirtestIDE-zh_CN/index.html

查找定位元素

AirtestIDE 对web录制支持已经挺完善的了,大部分的控件操作都可以通过录制来完成,最简单的使用方法就是录制脚本,但其实不仅仅是录制,有时候通过查找定位元素来编辑脚本会更加加强测试脚本的使用性,毕竟IDE是通过界面录制进行的,有的界面元素通过录制可能会取不到,又或者包含动态的一些无法直接完成操作测试的实际情况,所以更简单有效的办法就是录制+编写。

find element

selenium.webdriver 模块提供了所有WebDriver的实现, 当前支持的WebDriver有: Firefox, Chrome, IE and Remote。 Keys类提供键盘按键的支持,大量的方法让你去查询页面中的元素:

在这里插入图片描述

较常用查找定位元素使用的方法通过id、name、xpath、selector、classname,接下来会逐一介绍这几种find element的使用方法。

find element by id:

确定元素的id名称,直接通过id查找可定位到元素,将返回页面查找到的第一个id元素

find_element_by_id(“loginsubmit”)

find element by name:

与id同样,当确定元素的name名称时,可直接通过name查找定位元素,同样地,selenium将会返回页面查找到的第一个name元素

find_element_by_name(‘username’)

find_element_by_name(“password”)

find element by xpath:

xpath在xml文档中可遍历节点元素和属性,是XML路径语言。xpath同时扩展了通过id/name查找元素的方式,即是说,如果当前元素是id值,xpath会自动识别成("//*[@id=“top-menu”]),同时诸多类型如input、button、锚点a、iamge等都可以进行判断,比如 ("//button[@data-role=‘submit’]") ,xpath的形式复杂多变,对于网站页面千变万化的内容而言,xpath能够很好的自适应。

使用相对路径的写法以双斜线开头,绝对路径以单斜线开头从html最顶层开始遍历,如下图:

find_element_by_xpath("/html/body/form[1]")                                    #绝对路径

find_element_by_xpath("//form[1]")                                                   #页面中的第一个form元素

find_element_by_xpath("//form[@id='loginForm']")                          #包含id属性并且其值为loginForm

一般格式为//tagname[@attribute=‘value’]/路径/路径,如//[@id=“J_PmTaskInput”]/div/label , [*]表示包含所有

但不推荐使用绝对路径,因为页面可能经常元素变化,稍有改动可能就会导致定位失败;相对路径定位相对而言位置关系改动的概率更低,更靠谱,这样脚本健壮性适应性更强。

有一些非常有用的插件,可以协助发现元素的XPath:

  • XPath Checker - suggests XPath and can be used to test XPath results.

  • Firebug - XPath suggestions are just one of the many powerful features of this very useful add-on.

  • XPath Helper - for Google Chrome

通过就近的包含id或者name属性的元素出发定位你的元素,这样相对关系就很靠谱, 因为这种位置关系很少改变,所以可以使你的测试更加强大。

find elment by css selector:

通过css选择器定位元素,将返回页面第一个匹配到的元素。

find_element_by_css_selector("#J_Milestone > div.os-milestone-check > div")

find_element_by_css_selector("button.ui.teal.J_Pay")           #查找tagtype.class.class..

find_element_by_css_selector("div.ui.negative.button")        #查找所有div标签里面class包含ui、negative、button的元素

常用的选择器:

#表示id,查找id名称为J_Milestone的属性,以及该属性的下一级div

.表示class,查找该id下一级的div的class为os-milestone-check

*表示所有元素,>表示下一级

[]表示attribute,属性名称,[attribute=value] 指某属性值的该属性

:nth-child(n) 表示该父元素的第几个子元素

css selector 相较于xpath的优点就是性能比xpath好,另外就是页面排版布局位置有时候会变,但css selector相对更稳定,名称一般不会经常变更。

find element by class name:

确定元素的class name,可通过class name直接查找定位元素,将会返回该页面第一个匹配的class属性的元素。

find_element_by_class_name('content')

当页面存在多个相同class属性值的元素时,通过class name查找也只能返回第一个结果。

find element by link text:

这是一个查找超链接非常方便的一个定位方法,当确切知道页面的某个超链接使用的标签文本名称,那可以直接通过find_element_by_link_text 查找,将会返回页面第一个匹配的锚点标签。

find_element_by_partial_link_text('快速入门')

find element by partial link text:

这也是一个查找超链接的方法,跟find_element_by_link_text的区别在于,前者是精确查找,后者是模糊查找,也是相当好用的定位方法;同样地,也是会返回页面第一个匹配的锚点标签。

find_element_by_partial_link_text('入门')

以上查找元素find elmenet的方法,不管是哪一种,都是只会返回页面第一个匹配的元素的;如果没有查找到任何匹配的元素,将会返回一个异常:

NoSuchElementException

返回多个元素

在实际运用中,还会存在一种情况,就是查找元素的时候,当前页面返回的元素匹配的结果不止一个,find elment只能返回第一个结果,而有些情况下某些被需要的测试元素恰恰并不是第一个返回要的结果。

举一个实际项目中的遇到的例子,某网站的某个页面上一个时间控件,测试需求需要对时间控件进行选择操作,页面内容如图:
在这里插入图片描述

直接使用find element来定位元素,会返回一个错误的结果:

find_element_by_xpath("//button[@class_name='xdsoft_next']").click()

selenium.common.exceptions.ElementNotVisibleException:Message:elementnotvisible

原因是该页面上有2个时间控件,所以返回的操作按键结果也不止一个,而find_element返回的第一个结果恰巧在该页面该操作下是不被需要的,是被隐藏的元素,所以对其进行操作时会报错 element is not visible ,一个解决办法就是通过find elemets来查找多个元素。

find elements 查找元素的方法跟find element 是类似的,不同的是find elements会返回一个list列表。

  • find_elements_by_name

  • find_elements_by_xpath

  • find_elements_by_link_text

  • find_elements_by_partial_link_text

  • find_elements_by_tag_name

  • find_elements_by_class_name

  • find_elements_by_css_selector

上面的示例中,通过下面的代码可以定位到下个月按钮的元素,并对其进行操作:

find_element_by_xpath("//div[@class='xdsoft_mounthpicker']/button[2]")     #通过xpath定位到指定的button

find_elements_by_class_name('xdsoft_next')[2]                                   #通过classname定位到指定的button

在xpath过滤后还可以进入下一级过滤的,可以用 /button[n] 取下一级的某个索引,索引的用法只适用于直接在某种类型的element后面,比如:

find_element_by_xpath("//div[@class='xdsoft_mounthpicker']/button[1]")

初学者容易会写成下面的错误示范:

find_element_by_xpath("//button[@class='xdsoft_next'][1]")            #属性过滤后无法直接调用索引

通过以上方法就可以成功对该元素时间控件下个月按钮进行点击操作了。

断言

一个完整的测试脚本一定会包含对测试结果是否与预测结果一致的对比,从而判断脚本是否执行成功,Airtest提供了以下断言方法:

assert_exists

assert_not_exists

assert_equal

assert_not_equal

assert exists 使用方法:

assert_exist("//*[@id=“main”]/div/div[2]/h3", “xpath”, “请填写测试点.”) #判断该元素在页面是否存在

如果元素不存在,则会抛出一个异常,AssertionError("%s does not exist in screen, message: %s" % (v, msg)), 在log查看窗口可看到实时的调试日志。

assert_not_exists 使用方法:

assert_not_exist("//*[@id=\"main\"]/div/div[2]/h3", "xpath", "请填写测试点.")    #判断该元素在页面是否不存在

如果返回结果不匹配,则会抛出异常,AssertionError("%s exists unexpectedly at pos: %s, message: %s" % (v, pos, msg)) ,在log查看窗口可看到实时的调试日志。

assert_equal 使用方法:

assert_equal(driver.find_element_by_id("top-menu").text, "确认完成", "发布确认完成")#判断id属性为top-menu的元素文本信息是否等于“确认完成”

如果元素结果不匹配,则会抛出异常,AssertionError("%s and %s are not equal, message: %s" % (first, second, msg)),在log查看窗口可看到实时的调试日志。,在log查看窗口可看到实时的调试日志。

assert_not_equal 使用方法:

assert_not_equal(driver.find_element_by_id("J_FinishProject").text, "完成", "流程状态为已完成")#判断id属性为"J_FinishProject的元素文本信息是否等于“完成”

与assert equal类似,如果返回结果不匹配的就会抛出异常。

Airtest 提供的断言种类并不算丰富,只能简单地对某个测试结果或状态进行判断,实际项目种更为常用的应该是assert equal了,而且如果使用自己构建的函数对测试结果进行判断,那么该代码执行的测试结果并不会记录在html的测试报告里面。为了让assert断言可以完成更多的事情,可以使用传入函数的方法来进行判断,比如下面的例子:

def check_finish():    pro_status = driver.find_element_by_css_selector("div.panel.newbie-container.J_ProjectCommit > div.ui.form.fluid > div > div > div:nth-child(1) > div.content > div.extra.text").text

    status = "指派成功"    if status in pro_status:        print("project finishs!")        return True    else :        print("project not finish, please check!")        return Falseassert_equal(check_finish(), True, "Project all finish! AutoTest is done!")​def pro_assign(dev_id):    driver.find_element_by_xpath("//input[@placeholder='用户UID']").send_keys(dev_id)

    driver.find_element_by_id("prostatus_appoint_submit").click()    driver.switch_to.alert.accept()    def check_devstatus():        pro_devstatus = driver.find_element_by_css_selector("div.panel.newbie-container.J_ProjectCommit > div.ui.form.fluid > div > div > div:nth-child(1) > div.content > div.extra.text").text

        pro_devassign = "对接了第1位开发者,等待开发者确认"        if pro_devassign in pro_devstatus:

            return True        else :            return False            print("后台指派第一位开发者异常,请手动查看项目状态")            driver.quit()    assert_equal(check_devstatus(), True, "指派成功!")

这样依然可以在html测试报告显示函数执行后的结果,而且使用更灵活:
在这里插入图片描述

结束语

总体来说,作为一个年龄还算比较新的测试框架,这个测试工具还有许多不足的地方,需要完善的地方,比如启动浏览器时间比较久,需要等待浏览器渲染页面脚本加载完成才有办法执行步骤,不能从脚本中途进行断点调试,有时候打开多个窗口的时候录制窗口会失焦等,但个人认为这仍是一个非常好用的界面自动化测试的入门工具。而且自今为止,AirtestIDE还有在持续地更新版本,在App的自动化测试上使用的更广泛,希望可以越来越完善,应用更广泛。

下面是我在做自动化对于技术一些归纳和总结,希望能帮助到有心在技术这条道路上一路走到黑的朋友!附带教程学习资料~

在这里插入图片描述


这些资料,对于做【软件测试】的朋友来说应该是最全面最完整的备战仓库,这个仓库也陪伴我走过了最艰难的路程,希望也能帮助到你!凡事要趁早,特别是技术行业,一定要提升技术功底。

关注我的微信公众号:【伤心的辣条】免费获取~

我的学习交流群:902061117 群里有技术大牛一起交流分享~

如果我的博客对你有帮助、如果你喜欢我的博客内容,请 “点赞” “评论” “收藏” 一键三连哦!

好文推荐:

阿里小黑叹息:越来越多的年轻人从职场撤退了?

Python简单?先来40道基础面试题测试下

App公共测试用例梳理

从一名开发人员转做测试的一些感悟

  • 2
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
Web自动化测试是指通过编写自动化脚本来模拟用户在Web应用程序上的操作,以验证应用程序的功能和性能。Selenium是一种流行的Web自动化测试工具,而Python是一种常用的编程语言。结合使用SeleniumPython,可以实现高效的Web自动化测试。 要使用Selenium进行PythonWeb自动化测试,首先需要搭建相应的环境。可以按照以下步骤进行搭建: 1. 安装Python:访问Python官方网站,下载并安装Python的最新版本。 2. 安装Selenium:使用Python的包管理工具pip,在命令行中执行以下命令安装Selenium包: ``` pip install selenium ``` 3. 下载浏览器驱动:根据你所使用的浏览器类型,下载相应的浏览器驱动。例如,如果你使用Chrome浏览器,可以下载Chrome浏览器驱动。 4. 配置浏览器驱动:将下载的浏览器驱动添加到系统的环境变量中,这样Selenium才能找到并使用它。 完成环境搭建后,就可以编写自动化测试脚本了。以下是一个简单的示例脚本: ```python from selenium import webdriver # 创建WebDriver对象,启动浏览器 driver = webdriver.Chrome() # 打开网页 driver.get('https://www.baidu.com') # 查找搜索框并输入内容 input_box = driver.find_element_by_css_selector('#kw') input_box.send_keys('selenium') # 查找“百度一下”按钮并点击 submit_button = driver.find_element_by_css_selector('#su') submit_button.click() # 检查搜索结果中是否包含关键字 assert 'selenium' in driver.title # 关闭浏览器 driver.quit() ``` 以上脚本使用Selenium的API来模拟用户在百度搜索引擎上的操作,并检查搜索结果中是否包含关键字"selenium"。可以根据实际需求编写更复杂的自动化测试脚本。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* [Web自动化测试环境搭建之Python+Selenium](https://download.csdn.net/download/weixin_38690402/15443144)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 33.333333333333336%"] - *2* [Web自动化测试 —— 测试环境搭建 (Selenium+Python)及视频操作](https://blog.csdn.net/Faith_Lzt/article/details/119187797)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 33.333333333333336%"] - *3* [如何使用 Python+selenium 进行 web 自动化测试?](https://blog.csdn.net/caixiangting/article/details/130581863)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 33.333333333333336%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值