news 2026/9/1 6:30:03

AppUI自动化实战封装

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
AppUI自动化实战封装

AppUI自动化实战封装

1、新建一个项目

2、在项目中写两条用例:

启动雪球-进入我的页面进入登录-登录成功后获取登录名验证是否成功登录

import time from appium import webdriver from appium.webdriver.common.mobileby import MobileBy as By from appium.webdriver.common.touch_action import TouchAction # 初始化app desired_caps = {} desired_caps['platformName'] = 'Android' # 'Android' or ’Ios' desired_caps['deviceName'] = 'emulator-5554' # 设备名称,可以自定义 # desired_caps['appPackage'] = 'com.iodkols.onekeylockscreen' # desired_caps['appActivity'] = '.OneLock' desired_caps['appPackage'] = 'com.xueqiu.android' desired_caps['appActivity'] = 'view.WelcomeActivityAlias' #desired_caps['noReset'] = 'True' driver = webdriver.Remote('<http://localhost:4723/wd/hub>', desired_caps) # 类似于driver = webdriver.Chrome() driver.implicitly_wait(10) time.sleep(8) #在首页进入【我的】页面 driver.find_element(By.XPATH, "//*[@text='我的']").click() #在【我的】页面点击【账号密码登录】进入登录页面 driver.find_element(By.XPATH, "//*[@text='帐号密码登录']").click() #在登录页面输入账号 driver.find_element(By.XPATH, "//*[@resource-id='com.xueqiu.android:id/login_account']").send_keys('13262506790') #在登录页面输入密码 driver.find_element(By.XPATH, "//*[@resource-id='com.xueqiu.android:id/login_password']").send_keys('1111111a') #在登录页面点击【登录】 driver.find_element(By.XPATH, "//*[@text='登录']").click() # 对一键导入弹框进行判断处理 try: cancel_ele = driver.find_element(By.XPATH, "//*[@text='取消']").click() except: pass #登录后在我的页面获取登录昵称 name_ele = driver.find_element(By.XPATH, "//*[@resource-id='com.xueqiu.android:id/name']") name_text = name_ele.get_attribute("text") print(name_text) assert '思源_smile' == name_text driver.quit()

启动雪球-进行登录-在首页进入讨论帖页面-编辑并发布帖子-进入我的页面校验帖子是否成功生成

import time from appium import webdriver from appium.webdriver.common.mobileby import MobileBy as By from appium.webdriver.common.touch_action import TouchAction # 初始化app desired_caps = {} desired_caps['platformName'] = 'Android' # 'Android' or ’Ios' desired_caps['deviceName'] = 'emulator-5554' desired_caps['appPackage'] = 'com.xueqiu.android' desired_caps['appActivity'] = 'view.WelcomeActivityAlias' #desired_caps['noReset'] = 'True' driver = webdriver.Remote('<http://localhost:4723/wd/hub>', desired_caps) # 类似于driver = webdriver.Chrome() driver.implicitly_wait(10) time.sleep(8) #在首页进入【我的】页面 driver.find_element(By.XPATH, "//*[@text='我的']").click() #在【我的】页面点击【账号密码登录】进入登录页面 driver.find_element(By.XPATH, "//*[@text='帐号密码登录']").click() #在登录页面输入账号 driver.find_element(By.XPATH, "//*[@resource-id='com.xueqiu.android:id/login_account']").send_keys('13262506790') #在登录页面输入密码 driver.find_element(By.XPATH, "//*[@resource-id='com.xueqiu.android:id/login_password']").send_keys('1111111a') #在登录页面点击【登录】 driver.find_element(By.XPATH, "//*[@text='登录']").click() #登录后进入雪球首页 driver.find_element(By.XPATH, "//*[@text='雪球']").click() #在首页点击【编辑】按钮 driver.find_element(By.XPATH, "//*[@resource-id='com.xueqiu.android:id/post_status']").click() #点击【发讨论】按钮进入发布讨论页面 driver.find_element(By.XPATH, "//*[@text='发讨论']").click() #在发布讨论页面输入框中输入讨论内容 title_text = "随着气候变暖,今年会不会有一个寒冷的冬天?" driver.find_element(By.XPATH, "//*[@resource-id='com.xueqiu.android:id/status_edit']").send_keys(title_text) #点击【发布】返回首页 driver.find_element(By.XPATH, "//*[@text='发布']").click() #进入【我的】页面 driver.find_element(By.XPATH, "//*[@text='我的']").click() #在【我的】页面点击【讨论】进入讨论页面 driver.find_element(By.XPATH, "//*[@text='讨论']").click() #在讨论页面获取讨论标题元素 eles = driver.find_elements(By.XPATH, "//*[@resource-id='com.xueqiu.android:id/statusText']") #对标题元素获取text属性存入列表 title_list = [ele.get_attribute("text") for ele in eles] # 写个函数对结果进行断言 def assert_title(): for title in title_list: if title == title_text: return True else: return False assert assert_title() driver.quit()

处理用例中公共的部分app初始化,对公共部分单独封装实现模块化及分层复用

3、对初始化app代码单独封装

新建py_page包-包下新建app模块,定义一个App类,类下定义一个start()实例方法对driver进行初始化并返回创建的driver

import time from appium import webdriver from appium.webdriver.common.mobileby import MobileBy as By from appium.webdriver.common.touch_action import TouchAction class App: def start(self): # 初始化app desired_caps = {} desired_caps['platformName'] = 'Android' desired_caps['deviceName'] = 'emulator-5554' desired_caps['appPackage'] = 'com.xueqiu.android' desired_caps['appActivity'] = 'view.WelcomeActivityAlias' self.driver = webdriver.Remote('<http://localhost:4723/wd/hub>', desired_caps) # 类似于driver = webdriver.Chrome() self.driver.implicitly_wait(10) return self.driver

在测试用例中app初始化通过from py_page.app import App及driver = App().start()来代替,即实现所有用例共用app中的初始化代码;

4、比较多个用例存在公共页面元素交互部分,把这部分元素的定位与交互单独封装,以页面为模块归类,类中方法为在该页面执行的元素交互;

from py_page.app import App from appium.webdriver.common.mobileby import MobileBy as By class LoginPage(App): def __init__(self): self.driver = self.start() def account_login(self): # 在登录页面进行账号密码登录 self.driver.find_element(By.XPATH, "//*[@text='我的']").click() self.driver.find_element(By.XPATH, "//*[@text='帐号密码登录']").click() self.driver.find_element(By.XPATH, "//*[@resource-id='com.xueqiu.android:id/login_account']").send_keys( '13262506790') self.driver.find_element(By.XPATH, "//*[@resource-id='com.xueqiu.android:id/login_password']").send_keys('1111111a') self.driver.find_element(By.XPATH, "//*[@text='登录']").click()
from appium.webdriver.common.mobileby import MobileBy as By class MainPage(App): def __init__(self): self.driver = self.start() def goto_myPage(self): # 在首页进入【我的】页面 self.driver.find_element(By.XPATH, "//*[@text='我的']").click()
from py_page.app import App from appium.webdriver.common.mobileby import MobileBy as By class MyPage(App): def __init__(self): self.driver = self.start() def goto_login(self): # 在我的页面进入【登录】页面 self.driver.find_element(By.XPATH, "//*[@text='我的']").click() def is_cancel(self): # 对一键导入弹框进行判断处理 try: self.driver.find_element(By.XPATH, "//*[@text='取消']").click() except: pass def get_login_name(self): # 登录后在我的页面获取登录昵称 name_ele = self.driver.find_element(By.XPATH, "//*[@resource-id='com.xueqiu.android:id/name']") name_text = name_ele.get_attribute("text") return name_text

5、在修改原来测试用例,采用调用py_page中各方法来实现测试业务的流转执行

from py_page.main_page import MainPage class TestLogin: def test_login_pos(self): name_text = MainPage().goto_myPage().goto_login().account_login().is_cancel().get_login_name() print(name_text) assert name_text == '思源_smile'

似乎存在什么问题?

优化上述py_page保证链式调用

from appium.webdriver.common.mobileby import MobileBy as By class MainPage(App): def __init__(self): self.driver = self.start() def goto_myPage(self): # 在首页进入【我的】页面 self.driver.find_element(By.XPATH, "//*[@text='我的']").click() from py_page.my_page import MyPage return MyPage()
from py_page.app import App from appium.webdriver.common.mobileby import MobileBy as By class MyPage(App): def __init__(self): self.driver = self.start() def goto_login(self): # 在我的页面进入【登录】页面 self.driver.find_element(By.XPATH, "//*[@text='我的']").click() return LoginPage() def is_cancel(self): # 对一键导入弹框进行判断处理 try: self.driver.find_element(By.XPATH, "//*[@text='取消']").click() except: pass return self def get_login_name(self): # 登录后在我的页面获取登录昵称 name_ele = self.driver.find_element(By.XPATH, "//*[@resource-id='com.xueqiu.android:id/name']") name_text = name_ele.get_attribute("text") return name_text
from py_page.app import App from appium.webdriver.common.mobileby import MobileBy as By class LoginPage(App): def __init__(self): self.driver = self.start() def account_login(self): # 在登录页面进行账号密码登录 self.driver.find_element(By.XPATH, "//*[@text='我的']").click() self.driver.find_element(By.XPATH, "//*[@text='帐号密码登录']").click() self.driver.find_element(By.XPATH, "//*[@resource-id='com.xueqiu.android:id/login_account']").send_keys( '13262506790') self.driver.find_element(By.XPATH, "//*[@resource-id='com.xueqiu.android:id/login_password']").send_keys('1111111a') self.driver.find_element(By.XPATH, "//*[@text='登录']").click() from py_page.my_page import MyPage return MyPage()

上述代码似乎还存在问题,在测试用例的链式调用中,涉及页面跳转的每次调用页面类都会调用app初始化一个driver,而不是传递原来的driver;

初步解决方案,每个页面类在构造方法中对driver进行判断,并在涉及页面跳转的方法中return 页面类(self.driver),即把当前页面的driver作为参数传入要跳转的页面,需要引入单例设计

from py_page.app import App from appium.webdriver.common.mobileby import MobileBy as By class MainPage(App): def __init__(self,driver=None): if driver == None: self.driver = self.start() else: self.driver = driver def goto_myPage(self): # 在首页进入【我的】页面 self.driver.find_element(By.XPATH, "//*[@text='我的']").click() from py_page.my_page import MyPage return MyPage(self.driver)
from py_page.app import App from appium.webdriver.common.mobileby import MobileBy as By class MyPage(App): def __init__(self,driver=None): if driver == None: self.driver = self.start() else: self.driver = driver def goto_login(self): # 在我的页面进入【登录】页面 self.driver.find_element(By.XPATH, "//*[@text='我的']").click() from py_page.login_page import LoginPage return LoginPage(self.driver) def is_cancel(self): # 对一键导入弹框进行判断处理 try: self.driver.find_element(By.XPATH, "//*[@text='取消']").click() except: pass return self def get_login_name(self): # 登录后在我的页面获取登录昵称 name_ele = self.driver.find_element(By.XPATH, "//*[@resource-id='com.xueqiu.android:id/name']") name_text = name_ele.get_attribute("text") return name_text
from py_page.app import App from appium.webdriver.common.mobileby import MobileBy as By class LoginPage(App): def __init__(self,driver=None): if driver==None: self.driver = self.start() else: self.driver=driver def account_login(self): # 在登录页面进行账号密码登录 self.driver.find_element(By.XPATH, "//*[@text='我的']").click() self.driver.find_element(By.XPATH, "//*[@text='帐号密码登录']").click() self.driver.find_element(By.XPATH, "//*[@resource-id='com.xueqiu.android:id/login_account']").send_keys( '13262506790') self.driver.find_element(By.XPATH, "//*[@resource-id='com.xueqiu.android:id/login_password']").send_keys('1111111a') self.driver.find_element(By.XPATH, "//*[@text='登录']").click() from py_page.my_page import MyPage return MyPage(self.driver)

再次执行测试用例,即可实现完整的元素定位交互以及页面跳转

6、继续优化py_page中的代码,把页面类中的构造方法封装到app中,减少代码冗余

app模块的初步实现

from appium import webdriver from appium.webdriver.common.mobileby import MobileBy as By from appium.webdriver.common.touch_action import TouchAction class App: def __init__(self,driver=None): self.driver = driver def start(self): # 初始化app if self.driver==None: desired_caps = {} desired_caps['platformName'] = 'Android' desired_caps['deviceName'] = 'emulator-5554' desired_caps['appPackage'] = 'com.xueqiu.android' desired_caps['appActivity'] = 'view.WelcomeActivityAlias' #desired_caps['noReset'] = 'True' self.driver = webdriver.Remote('<http://localhost:4723/wd/hub>', desired_caps) # 类似于driver = webdriver.Chrome() self.driver.implicitly_wait(10) return self.driver
from py_page.app import App from appium.webdriver.common.mobileby import MobileBy as By class MainPage(App): def goto_myPage(self): # 在首页进入【我的】页面 self.driver.find_element(By.XPATH, "//*[@text='我的']").click() from py_page.my_page import MyPage return MyPage(self.driver)
from py_page.app import App from appium.webdriver.common.mobileby import MobileBy as By class MyPage(App): def goto_login(self): # 在我的页面进入【登录】页面 self.driver.find_element(By.XPATH, "//*[@text='账号密码登录']").click() from py_page.login_page import LoginPage return LoginPage(self.driver) def is_cancel(self): # 对一键导入弹框进行判断处理 try: self.driver.find_element(By.XPATH, "//*[@text='取消']").click() except: pass return self def get_login_name(self): # 登录后在我的页面获取登录昵称 name_ele = self.driver.find_element(By.XPATH, "//*[@resource-id='com.xueqiu.android:id/name']") name_text = name_ele.get_attribute("text") return name_text
from py_page.app import App from appium.webdriver.common.mobileby import MobileBy as By class LoginPage(App): def account_login(self): # 在登录页面进行账号密码登录 self.driver.find_element(By.XPATH, "//*[@text='我的']").click() self.driver.find_element(By.XPATH, "//*[@text='帐号密码登录']").click() self.driver.find_element(By.XPATH, "//*[@resource-id='com.xueqiu.android:id/login_account']").send_keys( '13262506790') self.driver.find_element(By.XPATH, "//*[@resource-id='com.xueqiu.android:id/login_password']").send_keys('1111111a') self.driver.find_element(By.XPATH, "//*[@text='登录']").click() from py_page.my_page import MyPage return MyPage(self.driver)
from py_page.main_page import MainPage class TestLogin: def test_login_pos(self): name_text = MainPage().goto_myPage().goto_login().account_login().is_cancel().get_login_name() print(name_text) assert name_text == '思源_smile'

基于上面代码修改app后原测试用例会报错,想一想这是为什么?

因为测试用例中调用MainPage()时由于继承了app,会调用app中的构造方法初始化一个driver=None,但goto_myPage()中有self.driver.find_element(By.XPATH,"//*[@text='我的']").click(),然而这个driver是一个None自然没有find_element这个方法

修改方案如下

from appium import webdriver from appium.webdriver.common.mobileby import MobileBy as By from appium.webdriver.common.touch_action import TouchAction class App: def __init__(self,driver=None): self.driver = driver def start(self): # 初始化app if self.driver==None: desired_caps = {} desired_caps['platformName'] = 'Android' desired_caps['deviceName'] = 'emulator-5554' desired_caps['appPackage'] = 'com.xueqiu.android' desired_caps['appActivity'] = 'view.WelcomeActivityAlias' #desired_caps['noReset'] = 'True' self.driver = webdriver.Remote('<http://localhost:4723/wd/hub>', desired_caps) # 类似于driver = webdriver.Chrome() self.driver.implicitly_wait(10) return self def main(self): from py_page.main_page import MainPage return MainPage(self.driver)

测试用例修改如下:

from py_page.main_page import MainPage from py_page.app import App class TestLogin: def test_login_pos(self): name_text = App().start().main().goto_myPage().goto_login().account_login().is_cancel().get_login_name() print(name_text) assert name_text == '思源_smile'

7、继续优化py_page,使元素定位及交互从页面类中分离,减少页面类中的代码量,方便维护与管理

(1)在py_page中新建base_page.py封装页面基类,实现对页面元素的定位及交互,页面元素的查找常用有两种形式:查找单个元素&&查找多个元素集,即封装find && finds方法,每个查找元素的形式包含id, xpath, class ,ACCESSIBILITY_ID四种方式故作如下封装,由于BasePage中find&&finds方法需要用到driver,故BasePage初始化一个driver来实现调用self.driver

from appium.webdriver.common.mobileby import MobileBy as By class BasePage: def __init__(self, driver: webdriver = None): self.driver = driver def find(self, by, locator): by_locator = None if by == 'id' or by == 'ID': by_locator = (By.ID, locator) elif by == 'xpath' or by == 'XPATH': by_locator = (By.XPATH, locator) elif by == 'class' or by == 'CLASS': by_locator = (By.CLASS_NAME, locator) elif by == 'ACCESSIBILITY_ID' or by == 'accessibility_id': by_locator = (By.ACCESSIBILITY_ID, locator) ele = self.driver.find_element(*(by_locator)) return ele def finds(self, by, locator): by_locator = None if by == 'id' or by == 'ID': by_locator = (By.ID, locator) elif by == 'xpath' or by == 'XPATH': by_locator = (By.XPATH, locator) elif by == 'class' or by == 'CLASS': by_locator = (By.CLASS_NAME, locator) elif by == 'ACCESSIBILITY_ID' or by == 'accessibility_id': by_locator = (By.ACCESSIBILITY_ID, locator) eles = self.driver.find_elements(*(by_locator)) return eles def find_and_click(self, by, locator): ele = self.find(by, locator) ele.click() def finds_and_click(self, by, locator, index): eles = self.finds(by, locator) eles[index].click() def finds_and_send(self, by, locator, index, text): eles = self.finds(by, locator) eles[index].send_keys(text) def find_and_send(self, by, locator, text): self.find(by, locator).send_keys(text) def find_and_clear(self, by, locator): self.find(by, locator).clear() @staticmethod def get_yaml_eles(yaml_path): with open(yaml_path, "r", encoding="UTF-8") as f: datas = yaml.safe_load(f) return datas

修改app.py,使App继承BasePage, 因此调用这个App()时会调用BasePage中的构造方法,初始化一个self.driver==None

from appium import webdriver from appium.webdriver.common.mobileby import MobileBy as By from appium.webdriver.common.touch_action import TouchAction from py_page.base_page import BasePage class App(BasePage): def start(self): # 初始化app if self.driver==None: desired_caps = {} desired_caps['platformName'] = 'Android' # 'Android' or ’Ios' desired_caps['deviceName'] = 'emulator-5554' desired_caps['appPackage'] = 'com.xueqiu.android' desired_caps['appActivity'] = 'view.WelcomeActivityAlias' #desired_caps['noReset'] = 'True' self.driver = webdriver.Remote('<http://localhost:4723/wd/hub>', desired_caps) # 类似于driver = webdriver.Chrome() self.driver.implicitly_wait(10) return self def main(self): from py_page.main_page import MainPage return MainPage(self.driver) def stop(self): self.driver.quit()

py_page中其他页面类继承页面基类BasePage,使得页面类能够调用页面基类中元素定位及交互方法,后续在测试中需要用到页面元素交互的方法都可以封装在BasePage中,供页面类直接调用;

基于BasePage的封装,优化py_page中页面类的代码实现:

from appium.webdriver.common.mobileby import MobileBy as By from py_page.base_page import BasePage class MainPage(BasePage): def goto_myPage(self): # 在首页进入【我的】页面 self.find_and_click(By.XPATH, "//*[@text='我的']") from py_page.my_page import MyPage return MyPage(self.driver)
from appium.webdriver.common.mobileby import MobileBy as By from py_page.base_page import BasePage class MyPage(BasePage): def goto_login(self): # 在我的页面进入【登录】页面 self.find_and_click(By.XPATH, "//*[@text='帐号密码登录']") from py_page.login_page import LoginPage return LoginPage(self.driver) def is_cancel(self): # 对一键导入弹框进行判断处理 try: self.find_and_click(By.XPATH, "//*[@text='取消']") except: pass return self def get_login_name(self): # 登录后在我的页面获取登录昵称 name_ele = self.find(By.XPATH, "//*[@resource-id='com.xueqiu.android:id/name']") name_text = name_ele.get_attribute("text") return name_text
from appium.webdriver.common.mobileby import MobileBy as By from py_page.base_page import BasePage class LoginPage(BasePage): def account_login(self): # 在登录页面进行账号密码登录 self.find_and_send(By.XPATH, "//*[@resource-id='com.xueqiu.android:id/login_account']",'13262506790') self.find_and_send(By.XPATH, "//*[@resource-id='com.xueqiu.android:id/login_password']",'1111111a') self.find_and_click(By.XPATH, "//*[@text='登录']") from py_page.my_page import MyPage return MyPage(self.driver)

(2)把py_page页面类中的页面元素集中管理,从代码中分离,当前端页面元素及交互变更时,我们减少对页面类中代码的修改,从数据载体中集中统一维护;

新建yaml_page,yaml_page文件夹下对应每一个页面类创建对应的yamlPage

login_page.yaml

account_login: login_account: [XPATH, "//*[@resource-id='com.xueqiu.android:id/login_account']"] login_password: [XPATH, "//*[@resource-id='com.xueqiu.android:id/login_password']"] login_button: [XPATH, "//*[@text='登录']"]

main_page.yaml

goto_myPage: my: [XPATH, "//*[@text='我的']"]

my_page.yaml

goto_login: account_login: [XPATH, "//*[@text='帐号密码登录']"] is_cancel: cancel: [XPATH, "//*[@text='取消']"] get_login_name: login_name: [XPATH, "//*[@resource-id='com.xueqiu.android:id/name']"]

修改对应py_page中页面类中的代码

mian_page.py

from py_page.base_page import BasePage class MainPage(BasePage): yaml_path = './yaml_page/main_page.yaml' yaml_datas = BasePage.get_yaml_eles(yaml_path) def goto_myPage(self): # 在首页进入【我的】页面 datas = self.yaml_datas['goto_myPage'] self.find_and_click(*datas['my']) from py_page.my_page import MyPage return MyPage(self.driver)

(3)继续优化py_page中页面类的代码,下面login_page.py中的account_login方法包含多个步骤,可用行为驱动的方式优化

login_page.py

from py_page.base_page import BasePage class LoginPage(BasePage): yaml_path = './yaml_page/login_page.yaml' yaml_datas = BasePage.get_yaml_eles(yaml_path) def account_login(self): # 在登录页面进行账号密码登录 datas = self.yaml_datas['account_login'] self.find_and_send(*datas['login_account'],'13262506790') self.find_and_send(*datas['login_password'],'1111111a') self.find_and_click(*datas['login_button']) from py_page.my_page import MyPage return MyPage(self.driver)
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/1 6:27:48

如何找到合适的GEO代理公司:7项质量特征|参考版

如何找到合适的GEO代理公司&#xff1a;7项质量特征&#xff5c;参考版 对许多决策者来说&#xff0c;并且确定GEO代理公司仍像在信息不足的情况下摸索。几乎所有供应商都会承诺进入“新的AI搜索世界”&#xff0c;但营销话术背后可能只是旧SEO换了名称。真正需要进一步回答的是…

作者头像 李华
网站建设 2026/9/1 6:26:46

本地化桌面标注工具:高效批量处理图片标注,提升自媒体内容生产效率

这次我们来看一个面向自媒体创作者的桌面标注工具。如果你经常需要为视频截图、教程配图或社交媒体内容添加箭头、文字、方框等标注&#xff0c;手动用专业软件处理既耗时又麻烦。这个工具的核心价值就是简化这个流程&#xff0c;让标注变得像“戳戳点点”一样简单直接。它最值…

作者头像 李华
网站建设 2026/9/1 6:26:26

MobileNetV3核心组件逐模块拆解与PyTorch实战

简介&#xff1a;面向深度学习从业者与研究人员&#xff0c;MobileNetV3 完整 PyTorch 实现资源包聚焦轻量级网络在计算机视觉中的应用&#xff0c;涵盖模型搭建、预训练权重、训练日志、推理测试与效率评估等环节&#xff0c;适合用于学习 MobileNetV3 架构细节并快速开展图像…

作者头像 李华
网站建设 2026/9/1 6:26:12

下载即用!DeepSeek Harness 有桌面客户端了!

大家好&#xff0c;我是 Java陈序员。 最近的 DeepSeek Harness 可以说是十分火热&#xff0c;很多人都想安装体验一下。但是 DeepSeek Harness 依赖 Node.js 环境&#xff0c;需要手动安装 Node.js 环境、敲命令行启动。 对于一些不是很懂技术的普通用户来说&#xff0c;安装过…

作者头像 李华
网站建设 2026/9/1 6:24:53

Matlab实现元胞自动机模拟城市增长

简介&#xff1a;基于元胞自动机的Matlab城市增长模拟项目&#xff0c;适合城乡规划、地理信息科学等方向的师生与研究人员。项目以艾哈迈达巴德地区为案例&#xff0c;通过CA模型模拟未开发土地向住宅、商业、工业等用地的演变&#xff0c;并依据人口迁移、交通便利度等规则迭…

作者头像 李华
网站建设 2026/9/1 6:24:16

OpenAI断供Cursor?开发者如何应对AI编程工具链的模型依赖风险

OpenAI 对 Cursor 断供这件事&#xff0c;今天在不少技术群里都刷屏了。先说我的判断&#xff1a;如果消息属实&#xff0c;影响最大的是那些把 Cursor 当主力开发工具、并且所有 Agent 任务都跑在 OpenAI 模型上的人&#xff1b;如果你只是偶尔用 Cursor 补全代码&#xff0c;…

作者头像 李华