用户端APP自动化测试_L2

目录:

  1. appium server 环境安装
  2. capability 进阶用法
  3. 元素定位工具
  4. 高级定位技巧-xpath 定位
  5. 高级定位技巧-css 定位与原生定位
  6. 特殊控件 toast 识别
  7. 显式等待高级使用
  8. 高级控件交互方法
  9. 设备交互api
  10. 模拟器控制
  11. 雪球财经app股票详情功能点自动化测试实战

1.appium server 环境安装

  • 安装 Node.js
  • 安装 Appium Server
  • 安装 Appium Doctor

安装 Node.js

  • 下载
  • 默认配置环境变量
  • 查看源
  • 更换源
bash 复制代码
// 查看源
npm config get registry

//更换源
npm config set registry https://registry.npm.taobao.org

安装成功后的截图:

安装 Appium Server

  • Appium Server 安装
bash 复制代码
// 安装最新版本的appium server
npm install -g appium


// 注意 -g 参数一定要有,不能省,代表全局
// 安装某个特定的版本
npm install -g appium@1.19.1

安装环境检测工具

  • 运行环境检测工具 appium-doctor
bash 复制代码
# 安装检测工具 appium-doctor
npm install -g appium-doctor
  • 执行检测命令 appium-doctor

运行 Appium 服务

bash 复制代码
// 帮助文档
appium --help

// 运行 appium 服务
appium

2.capability 进阶用法

deviceName

  • 只是设备的名字,别名
  • 随便起
  • 不能锁定唯一一个设备

uid

  • 多设备选择的时候,要指定 uid

  • 默认读取设备列表的第一个设备

  • 设备列表获取

adb devices

newCommandTimeout

  • appium 程序应等待来自客户端的新命令多长时间
  • 超时后会话删除
  • 默认 60
  • 设置为 0 禁用

autoGrantPermissions

  • 授予启动的应用程序某些权限

PRINT_PAGE_SOURCE_ON_FIND_FAILURE

  • 默认为 false
  • 发生任何错误,强制服务器将实际的 XML 页面源转储到日志中.

测试策略

  • noReset
  • fullReset
  • dontStopAppOnReset

noReset

  • 默认为false
  • 安卓true
    • 不停止应用程序
    • 不清除应用程序数据
    • 不卸载 apk

fullReset

  • 默认为 falsetrue:新会话之前完全卸载被测应用程序

  • 安卓

    • 在会话开始之前(appium 启动 app)和测试之后停止应用程序
    • 清除应用程序数据并卸载 apk

dontStopAppOnReset

  • 默认为 false
  • 不希望应用程序在运行时重新启动,设置为 true

#打开的app退出后重新启动

adb shell am start -S 包名/activity名

#打开的app不需要退出,直接使用当前页面

adb shell am start 包名/activity名

性能相关

  1. skipServerInstallation:这个选项可以跳过服务器的安装过程,如果在测试过程中不需要进行服务器安装,就可以使用这个选项来提高测试效率。
  2. skipDeviceInitialization:这个选项可以跳过设备的初始化过程,如果在测试过程中设备已经初始化过,就可以使用这个选项来避免重复初始化,提高测试效率。
  3. skipUnlock:这个选项可以跳过设备的解锁过程,如果在测试过程中设备已经解锁,就可以使用这个选项来避免重复解锁,提高测试效率。
  4. skipLogcatCapture:这个选项可以跳过日志的获取过程,如果在测试过程中不需要日志获取,就可以使用这个选项来提高测试效率。
  5. systemPort:这个选项可以获取系统的端口号,在测试过程中需要访问系统端口时使用。
  6. ignoreUnimportantViews:这个选项可以跳过不重要组件的获取过程,如果在测试过程中不需要获取这些组件的信息,就可以使用这个选项来提高测试效率。
  7. relaxed-security:这个选项可以在启动时设置放松的安全性,以允许某些应用程序在安全性检查中运行,从而提高测试效率。但是,这个选项可能会增加安全风险,应该谨慎使用。

3.元素定位工具

uiautomatorviewer 工具安装(不推荐)

  • 工具的安装:Android SDK 自带的界面分析工具
  • 打开 tools/bin 目录下的 uiautomatorviewer 程序

uiautomatorviewer 工具功能介绍

  • 第一个是通过分析给定的文件定位
  • 第二个是将当前界面截图并分析xml结构
  • 第三个与第二个功能类似,但它会对页面内容进行压缩,导致一些控件定位不准确
  • 第四个是保存当前界面的截图以及xml结构

weditor 安装与运行

  • 要求:python 3.6+ 以上
  • 安装:weditor 是 python 的第三方库
    • pip install weditor 进行安装
    • 运行:安装完成之后,在命令行运行 python -m weditor 即可

weditor 功能介绍

  • 支持 Android 和 iOS 的界面分析
  • 通过设备的 uuid 连接设备
  • 展示页面结构

appium inspector 安装与运行

  • 下载:下载链接
  • 运行 appium inspector
    • 运行 appium server
    • 本地的 adb 已连接设备
    • Desired Capabilities 参数填写
  • 点击 Start Session
  • 注意:在运行appium inspect 的时候需要检查一下weditor在手机上安装的ATX服务是否停止,因为ATX服务会占用uiautomator2的

appium inspector 功能简介

  • 定位的模式相关
    • 原生app模式
    • 混合模式
  • 界面操作相关
    • 选择元素
    • 坐标滑动界面
    • 坐标点击元素
  • 其他功能
    • 返回
    • 刷新页面
    • 录制
    • 搜索元素
    • 复制 xml 结构

对选中元素操作

  • 点击
  • 输入
  • 清空
  • 复制元素的属性
  • 获取元素的响应时间
  • 元素的属性

4.高级定位技巧-xpath 定位

xpath 函数

包含-contains()

  • Xpath 表达式中的一个函数

  • contains()函数匹配==属性值==中包含的==字符串==

    复制代码
    //*[contains(@属性,"属性值")]

xpath 轴

父子-当前节点的父节点

bash 复制代码
//*[@text="HK"]/..

//*[@text="HK"]/parent::*

父子-当前节点的子节点

bash 复制代码
//*[@resource-id="com.xueqiu.android:id/stock_layout"]/child::*

爷孙-当前节点的爷爷

bash 复制代码
//*[@text="HK"]/../..

//*[@text="HK"]/parent::*/parent::*

爷孙-当前节点的孙子

bash 复制代码
//*[@resource-id="com.xueqiu.android:id/stock_layout"]/child::*/child::*

祖先-ancestor

  • 返回当前节点的所有祖先

    复制代码
    //*[@text="HK"]/ancestor::android.widget.RelativeLayout
  • 显式指定要返回的祖先

    复制代码
    //*[@text="HK"]/ancestor::android.widget.RelativeLayout[1]

兄弟姐妹-sibling

  • 节点后的兄弟姐妹节点,following-sibling
  • 节点前的兄弟姐妹节点,preceding-sibling

following-sibling

  • 选择当前节点之后的所有兄弟节点

  • 节点后有一个兄弟节点

    复制代码
    //*[@text="HK"]/following-sibling::*
  • 节点后有多个兄弟节点

    复制代码
    //*[@resource-id="com.xueqiu.android:id/stock_layout"]/following-sibling::*[@resource-id="com.xueqiu.android:id/price_layout

preceding-sibling

  • 选择当前节点之前的所有兄弟节点

  • 节点前有一个兄弟节点

    复制代码
    //*[@text="09988"]/preceding-sibling::*
  • 节点前有多个兄弟节点

    复制代码
    //*[@resource-id="com.xueqiu.android:id/add_attention"]/preceding-sibling::*[@resource-id="com.xueqiu.android:id/price_layou

XPath 运算符

AND

  • 可以在 XPath 表达式中放置 2 个条件

  • AND 两个条件都应该为真的情况下,才能找到元素

    复制代码
    //*[@resource-id="com.xueqiu.android:id/current_price" and @text="107.8"]

OR

  • 可以在 XPath 表达式中放置 2 个条件

  • OR 的情况下,两个条件中的任何一个为真,就可找到元素。

  • OR 定位获取的是并集

    复制代码
    //*[@resource-id="com.xueqiu.android:id/tv_stock_add_follow" or @text="加自选"]

5.高级定位技巧-css 定位与原生定位

原生定位

bash 复制代码
# ID 定位
driver.find_element_by_android_uiautomator('new UiSelector().resourceId("<element-ID>")')

# 组合定位
driver.find_element_by_android_uiautomator('new UiSelector().resourceId("com.xueqiu.android:id/tab_name").text("我的")')

css selector 定位介绍

  • 官网说明
  • Android: Appium Server 版本 >= 1.19.0
  • iOS:Appium Server>= 1.21.0
bash 复制代码
代码:
driver.find_element(AppiumBy.CSS_SELECTOR,"#com\.xueqiu\.android\:id\/tv_search")

解析前:
{"using":"css selector","value":"#com\\.xueqiu\\.android\\:id\\/tv_search"}

解析后:
{"strategy":"-android uiautomator","selector":"new UiSelector().resourceId(\"com.xueqiu.android:id/tv_search\")",...}

css selector 用法

bash 复制代码
# 通过 id
elementById("someResourceID")`
    -> `elementsByCss("#someResourceID")
# 通过 class
elementsByClassName("android.widget.TextView")`
    -> `elementsByCss("android.widget.TextView")
# 通过 accessibility id
elementsByAccessibilityId("Some Content Description")`
    -> `elementsByCss('*[description="Some Content Description"]')
# 通过 xpath
elementsByXpath("//android.widget.TextView[@description='Accessibility']")`
    -> `elementsByCss("android.widget.TextView[description='Accessibility']")

iOS css selector 定位

总结

  • Appium Server 版本>=1.21.0
  • css selector 会转化为 Android/iOS 原生定位的定位策略
  • Android 转为 Android Uiautomator 定位方式
  • iOS 转为 class chain 定位方式

6.特殊控件 toast 识别

Toast 是什么

  • 一种消息框类型

  • 永远不会获得焦点,无法被点击

  • Toast显示的时间有限,Toast会根据用户设置的显示时间后自动消失

  • 是系统级别的控件,属于系统settings

  • Toast类的思想:就是尽可能不引人注意,同时还向用户显示信息,希望他们看到

Toast 定位

  • appium 用的是uiautomator底层来抓取toast,
  • 再把toast放到控件树内,但是它本身不属于空间
  • 使用的是uiautomator2

Toast 定位

  • xpath 可以找到 ``` //*@class="android.widget.Toast"

    //*contains(@text,"xxx") ``` xxx:toast的文本内容

    复制代码
    driver.manage().timeouts().implicitlyWait(Duration.ofSeconds(50));  
    driver.findElement(AppiumBy.xpath("//*[@class=\"android.widget.Toast\"]"));

代码示例:

python 复制代码
from appium import webdriver
from appium.webdriver.common.mobileby import MobileBy


class TestToast():
    def setup(self):
        desire = {
            'platformName': 'android',
            'platformVersion': '6.0',
            'deviceName': 'emulator-5554',
            'appPackage': 'io.appium.android.apis',
            'appActivity': 'io.appium.android.apis.view.PopupMenu1',
            'automationName': 'uiautomator2'
        }
        self.driver = webdriver.Remote("http://127.0.0.1:4723/wd/hub", desire)
        self.driver.implicitly_wait(5)

    def teardown(self):
        self.driver.quit()

    def test_toast(self):
        self.driver.find_element(MobileBy.ACCESSIBILITY_ID, "Make a Popup!").click()
        self.driver.find_element(MobileBy.XPATH, "//*[@text='Search']").click()
        print(self.driver.find_element(MobileBy.XPATH, "//*[@class='android.widget.Toast']").text)
        # print(self.driver.find_element(MobileBy.XPATH, "//*[contains(@text, 'Clicked popup')]").text)

7.显式等待高级使用

Wait 等待

  • 强制等待:sleep 不推荐
  • 全局隐式等待
    • 在服务端等待
    • driver.implicitly_wait(TIMEOUT)
  • 显式等待
    • 在客户端等待
    • WebDriverWait(self.driver,10,0.5).until(expected_conditions.visibility_of_element_located(LOCATOR))

显式等待

  • 显式等待
    • 显示等待与隐式等待相对,显示等待必须在每个需要等待的元素前面进行声明。
    • 是针对于某个特定的元素设置的等待时间,在设置时间内,默认每隔一段时间检测一次当前页面某个元素是否存在,
    • 如果在规定的时间内找到了元素,则直接执行,即找到元素就执行相关操作,
    • 如果超过设置时间检测不到则抛出异常。默认检测频率为 0.5s,默认抛出异常为:NoSuchElementException
  • 显示等待用到的两个类:
    • WebDriverWaitexpected_conditions 两个类

显式等待

  • 显式等待可以等待动态加载的 ajax 元素,显式等待需要使 ExpectedCondtions 来检查条件
  • 一般页面上元素的呈现
    • title 出现 首先出现 title
    • dom 树出现 presence ,还不完整
    • css 出现 (可见 visibility)
    • js 出现,js 特效执行 ( 可点击 clickable)
  • html 文档是自上而下加载的,
  • js 文件加载会阻塞 Html 内容的加载,有些 JS 异步加载的方式来完成 js 的加载
  • 样式表下载完成之后会跟之前的样式表一起进行解析,会对之前的元素重新渲染

WebDriverWait 用法

  • WebDriverWait 用法
    • WebDriverWait(driver,timeout,poll_frequency=0.5,ignored_exceptions=None)
    • driver:浏览器驱动
    • timeout:最长超时时间,默认以秒为单位
    • poll_frequency:检测的间隔步长,默认为 0.5s
    • ignored_exceptions:超时后的抛出的异常信息,默认抛出 NoSuchElementExeception 异常。
  • WebDriverWait 的 until()和 until_not()方法:
    • method: 在等待期间,每隔一段时间(init中的 poll_frequency)调用这个传入的方法,直到返回值不是 False , message: 如果超时,抛出 TimeoutException,将 message 传入异常
    • until_not: 与 until 相反,until 是当某元素出现或什么条件成立则继续执行,until_not 是当某元素消失或什么条件不成立则继续执行,参数也相同。

expected_conditions 类

  • presence_of_element_located 判断元素是否被加到了 DOM 树里,并不代表该元素一定可见
    • 用法:WebDriverWait().until(expected_conditions.presence_of_element_located(元素对象))
  • visibility_of_element_located 判断某个元素是否可见,可见代表元素非隐藏,并且元素的宽和高都不等于 0
    • 用法:
    • WebDriverWait().until(expected_conditions.visibility_of_element_located(元素定位符))

使用 lambda 表达式

  • WebDriverWait(driver,time).until(lambda x:x.find_element_by_id("someId")
  • 返回一个元素

总结三种等待方式

  • 隐式等待,尽量默认都加上,时间限定在 3-6s,不要太长, 为了所有的 find_element 方法都有一个很好的缓冲
  • 显式等待,用来处理隐式等待无法解决的一些问题,比如:文件上传(可以设置长一点),文件上传需要设置 20s 以上, 但是如果设置隐式等待, 它会在每个 find 方法都等这么长时间 , 一旦发现没有找到元素, 就会等 20s 以后才抛出异常, 影响 case 的执行效率,这时候就需要用显式等待,显式等待可以设置的长一点
  • 强制等待:一般不推荐,前两种基本能解决绝大部分问题,如果某个控件没有任何特征,只能强制等待,这种情况比较少

8.高级控件交互方法

Actions

  • Actions
  • 执行一系列或多个键盘和指针(触摸、鼠标、触控笔)操作链
  • w3c

W3C 事件流

用法

  • 定义 ActionChains 实例
  • 定义输入源
  • 定义动作

代码

bash 复制代码
...
# 定义ActionChains 实例
actions = ActionChains(driver)
# 第一步:定义输入源
# ActionChains里有个属性是ActionBuilder类型的, 使用的就是w3c协议
# 可以定义鼠标指针源,键盘源,滚轮源事件
actions.w3c_actions = ActionBuilder(driver, mouse=PointerInput(interaction.POINTER_TOUCH, "touch"))
# 第二步:定义动作
# 移动到起点-> 按下-> 滑动-> 抬起
actions.w3c_actions.pointer_action.move_to_location(115, 183)
actions.w3c_actions.pointer_action.pointer_down()
actions.w3c_actions.pointer_action.move_to_location(362, 179)
actions.w3c_actions.pointer_action.release()
actions.perform()
...

练习

  • 安装手势密码锁 app(TouchAction.apk)
  • 打开应用
  • 点击【设置手势】
  • 完成手势操作(如图)

代码示例:

python 复制代码
import time
from appium import webdriver
from appium.webdriver.common.appiumby import AppiumBy
from selenium.webdriver import ActionChains
from selenium.webdriver.common.actions import interaction
from selenium.webdriver.common.actions.action_builder import ActionBuilder
from selenium.webdriver.common.actions.pointer_input import PointerInput


class TestAction:
    def setup(self):
        caps = {}
        caps["platformName"] = "Android"
        caps["appPackage"] = "cn.kmob.screenfingermovelock"
        caps["appActivity"] = "com.samsung.ui.FlashActivity"
        caps["deviceName"] = "127.0.0.1:7555"
        caps["ensureWebviewsHavePages"] = True
        caps["noReset"] = "true"
        self.driver = webdriver.Remote("http://localhost:4723/wd/hub", caps)
        self.driver.implicitly_wait(15)

    def teardown(self):
        self.driver.quit()

    def test_action(self):
        el1 = self.driver.find_element(AppiumBy.ID,"cn.kmob.screenfingermovelock:id/patternTxt")
        el1.click()
        # 定义ActionChains 实例
        actions = ActionChains(self.driver)
        # 第一步:定义输入源
        # ActionChains里有个属性是ActionBuilder类型的, 使用的就是w3c协议
        # 可以定义鼠标指针源,键盘源,滚轮源事件
        actions.w3c_actions = ActionBuilder(self.driver, mouse=PointerInput(interaction.POINTER_TOUCH, "touch"))
        # 第二步:定义动作
        # 移动到起点-> 按下-> 滑动-> 抬起
        actions.w3c_actions.pointer_action.move_to_location(118, 176)
        actions.w3c_actions.pointer_action.pointer_down()
        actions.w3c_actions.pointer_action.move_to_location(355, 176)
        actions.w3c_actions.pointer_action.pause(0.5)
        actions.w3c_actions.pointer_action.move_to_location(751, 221)
        actions.w3c_actions.pointer_action.pause(0.5)
        actions.w3c_actions.pointer_action.move_to_location(752, 518)
        actions.w3c_actions.pointer_action.pause(0.5)
        actions.w3c_actions.pointer_action.move_to_location(751, 821)
        actions.w3c_actions.pointer_action.release()
        actions.perform()
        time.sleep(2)

9.设备交互api

常用的设备交互命令(建议去appium官网查看文档)

  • 模拟电话、短信
  • 网络模式
  • 横竖屏切换
  • App处理
  • 录屏

模拟电话、短信

  • appium可以模拟来电话,来短信功能,在app运行过程中收到短信/电话,app如何做处理的,专属的一些场景
  • 只支持原生模拟器,不支持mumu,genimotion等
bash 复制代码
driver.makeGsmCall(PHONE_NUMBER, GsmCallActions.CALL);
driver.makeGsmCall(PHONE_NUMBER, GsmCallActions.ACCEPT);
driver.makeGsmCall(PHONE_NUMBER, GsmCallActions.CANCEL);
driver.sendSMS("555-123-4567", "Appium Test");

网络设置

bash 复制代码
 def set_network_connection(self, connection_type: int) -> int:
        """Sets the network connection type. Android only.

        Possible values:

            +--------------------+------+------+---------------+
            | Value (Alias)      | Data | Wifi | Airplane Mode |
            +====================+======+======+===============+
            | 0 (None)           | 0    | 0    | 0             |
            +--------------------+------+------+---------------+
            | 1 (Airplane Mode)  | 0    | 0    | 1             |
            +--------------------+------+------+---------------+
            | 2 (Wifi only)      | 0    | 1    | 0             |
            +--------------------+------+------+---------------+
            | 4 (Data only)      | 1    | 0    | 0             |
            +--------------------+------+------+---------------+
            | 6 (All network on) | 1    | 1    | 0             |
            +--------------------+------+------+---------------+
bash 复制代码
self.driver.set_network_connection(1)
self.driver.set_network_connection(4)

横竖屏切换

  • 横竖屏切换,官方暂不支持python,以下是java代码。
  • 切换成横屏
    • driver.rotate(Screenorientation.LANDSCAPE)
  • 切换成竖屏
    • driver.rotate(Screenorientation.PORTRAIT)

获取日志

bash 复制代码
self.driver.log_types
self.driver.get_log("logcat")

其它常用操作

  • 锁屏
    • driver.lock()
  • 截图
    • driver.get_screenshot_as_file('./photos/img.png')
  • 录屏:模拟器需要 androidAPI>27,华为不支持,只支持 8.0以上的版本
    • 开始录制:self.driver.start_recording_screen()
    • 结束录制:self.driver.stop_recording_screen()

代码示例:

python 复制代码
import time
from appium import webdriver
from appium.webdriver.extensions.android.gsm import GsmCallActions


class TestDevice:
    def setup(self):
        caps = {}
        caps["platformName"] = "Android"
        caps['platformVersion'] = '6.0'
        caps["appPackage"] = "cn.kmob.screenfingermovelock"
        caps["appActivity"] = "com.samsung.ui.FlashActivity"
        caps["deviceName"] = "127.0.0.1:7555"
        caps["ensureWebviewsHavePages"] = True
        caps["noReset"] = "true"
        caps['unicodeKeyBoard'] = 'true'
        caps['resetKeyBoard'] = 'true'
        self.driver = webdriver.Remote("http://localhost:4723/wd/hub", caps)
        self.driver.implicitly_wait(15)

    def teardown(self):
        self.driver.quit()

    def test_mobile(self):
        self.driver.make_gsm_call('15033657989', GsmCallActions.CALL)
        self.driver.send_sms('15033657956', 'hello appium api')
        time.sleep(5)
        self.driver.set_network_connection(1)
        time.sleep(2)
        self.driver.set_network_connection(4)
        time.sleep(2)
        self.driver.get_screenshot_as_file('./datas/screenshot/img.png')

10.模拟器控制

android 模拟器创建

  • Android Studio
  • 在命令行启动模拟器
    • emulator -list-avds 模拟器列表
    • emulator '@foo' or '-avd foo'

配置

  • desirecap里面需要配置
    • avd: '模拟器名'
  • 注意自动启动模拟器,只能是sdk的模拟器,第三方模拟器不支持,7.0不支持

代码示例:

test_simulator_control.py

python 复制代码
import time

from appium import webdriver


class TestControl:
    def setup(self):
        caps = {}
        caps["platformName"] = "Android"
        caps['platformVersion'] = '6.0'
        caps["appPackage"] = "cn.kmob.screenfingermovelock"
        caps["appActivity"] = "com.samsung.ui.FlashActivity"
        caps["deviceName"] = "127.0.0.1:7555"
        caps["ensureWebviewsHavePages"] = True
        caps['unicodeKeyBoard'] = 'true'
        caps['resetKeyBoard'] = 'true'
        caps["noReset"] = "true"
        caps['avd'] = 'Resizable_Experimental_API_34'
        self.driver = webdriver.Remote("http://localhost:4723/wd/hub", caps)
        self.driver.implicitly_wait(15)

    def teardown(self):
        self.driver.quit()

    def test_control(self):
        self.driver.set_network_connection(1)
        time.sleep(2)
        self.driver.set_network_connection(4)
        time.sleep(2)
        self.driver.get_screenshot_as_file('./datas/screenshot/img.png')

11.雪球财经app股票详情功能点自动化测试实战

产品分析

  • 被测应用:雪球 App
  • 雪球 App 介绍
    • 雪球 app 是一款免费版,非常实用的股票平台,提供热点资讯内容和实时行情,提供了证券交流交易,公募、理财服务
    • 雪球 app 功能包括搜索股票,查看行情,交易,浏览热门文章,发帖,登录,注册,等功能

Page Object 模式六大原则

总结

  • 公共方法表示该页提供的服务。
  • 尽量不要暴露页面的内部
  • 一般不要断言
  • 方法返回其他页面对象·不需要表示整个页面
  • 同一行动的不同结果用不同的方法建模

用例设计

  • 搜索场景
    • 打开【雪球】应用首页
    • 点击搜索框,进入搜索页面
    • 向搜索输入框中输入【alibaba】
    • 点击搜索结果中的【阿里巴巴】
    • 切换到 tab 的【股票】
    • 找到 股票【阿里巴巴】的股票价格 price
    • 判断 price 在 110 上下 10%浮动
相关推荐
数据狐(Datafox)18 分钟前
京东商品列表API技术解析与落地应用(含标准 JSON 示例)
java·大数据·前端·人工智能·python·数据分析·json
量化吞吐机23 分钟前
2026年下半年手工交易规则走向量化表达,产品该先接住哪一步
人工智能·python
Metaphor6921 小时前
使用 Python 读取和删除 Excel 文件属性
python·excel
迷迭香yy2 小时前
Python构建转融券多空识别系统从接口到因子的全流程 IG50免费开源股票数据API接口
开发语言·python·开源
月光船幽幽2 小时前
真实即粗糙,光滑是伪造
人工智能·python
一次旅行2 小时前
Attention机制从数学到工程:拆解缩放点积+多头注意力|附可运行PyTorch实现与踩坑指南
人工智能·pytorch·python
泡干脆面就番茄3 小时前
NumPy 科学计算完全指南:从数组创建到广播机制
python·numpy
denggun123453 小时前
信号量(DispatchSemaphore vs AsyncSemaphore)、swift协作式线程池 and python信号量
开发语言·python·swift
起光3 小时前
Python类与对象(一)
python
阿童木写作3 小时前
跨马翻译:AI批量图片翻译工具,视频字幕翻译与智能抠图一站式解决
大数据·人工智能·python·音视频