appium(2)简单的demo、元素定位
目录
- appium-录制用例
- 获取包名和activity
- 录制步骤
- (1)启动appium客户端,默认启动地址 http://127.0.0.1:4723/wd/hub
- (2)file>New Session Window
- (3)配置设备信息、包名等,点【Start Session】
- (4)录制脚本
- 代码
- 报错
- Capability设置
- 重置策略
- 获取安卓udid
- 手机设置
- 开启开发者模式
- 开启手机指针位置
- 定位工具:uiautomatorviewer.bat
- 元素定位
- 常用定位方式
- 元素常用方法
- 代码
- TouchActions
- 代码
- 特殊控件toast定位
- 定位
- 代码
- uiautomator定位
- 常用表达式
- 组合定位:
- 父子关系定位:
- 滚动页面查找元素
- 代码
- 踩坑
- ui automator识别模拟器为横屏
- Selenium error: Could not parse UiSelector argument: 'com.xueqiu.android:id/tv_search' is not a stringCall to '10' failed
appium-录制用例
获取包名和activity
windows系统
adb shell dumpsys activity |find “mFocusedActivity” 获取当前activity
C:\Users\Administrator>adb shell dumpsys activity |find "mFocusedActivity"mFocusedActivity: ActivityRecord{10828b7 u0 com.xueqiu.android/.common.MainActivity t11}
adb shell dumpsys window | findstr mCurrentFocus 获取当前activity
C:\Users\Administrator>adb shell dumpsys window | findstr mCurrentFocusmCurrentFocus=Window{26c290 u0 com.xueqiu.android/com.xueqiu.android.common.MainActivity}
录制步骤
(1)启动appium客户端,默认启动地址 http://127.0.0.1:4723/wd/hub
(2)file>New Session Window
(3)配置设备信息、包名等,点【Start Session】
{
“platformName”: “android”,
“deviceName”: “Huawei Mate30”,
“appPackage”: “com.xueqiu.android”,
“appActivity”: “.view.WelcomeActivityAlias”,
“noReset”: “True”
}
(4)录制脚本
- 点【录制】
- 点【选择元素】
- 选择元素:点左边的输入框
- 点右边的【Tap】即点击输入框操作
- 选择元素:点坐标的输入框
- 点右边的【Send Keys】,输入文本,即向左边的输入框输入搜索关键词
- Recoder选择【Python】语言
- 结束【录制】
- 复制录制脚本
动图
代码
# pip install appium-python-client
from appium import webdriver
import time
descrip_cap = {"platformName": "android","deviceName": "Huawei Mate30","appPackage": "com.xueqiu.android","appActivity": ".view.WelcomeActivityAlias","noReset": "True"
}driver = webdriver.Remote("http://127.0.0.1:4723/wd/hub",descrip_cap)
driver.implicitly_wait(10)
#####################复制录制的脚本#############################
el1 = driver.find_element_by_id("com.xueqiu.android:id/tv_search")
el1.click()
el2 = driver.find_element_by_id("com.xueqiu.android:id/search_input_text")
el2.send_keys("alibaba")
el3 = driver.find_element_by_xpath("/hierarchy/android.widget.FrameLayout/android.widget.FrameLayout/android.widget.LinearLayout/android.widget.FrameLayout/android.view.ViewGroup/android.widget.FrameLayout/android.widget.LinearLayout/android.widget.RelativeLayout/android.widget.FrameLayout/android.widget.LinearLayout/androidx.recyclerview.widget.RecyclerView/android.widget.RelativeLayout[1]/android.widget.LinearLayout/android.widget.TextView[1]")
el3.click()
el4 = driver.find_element_by_xpath("/hierarchy/android.widget.FrameLayout/android.widget.FrameLayout/android.widget.LinearLayout/android.widget.FrameLayout/android.view.ViewGroup/android.widget.FrameLayout/android.widget.LinearLayout/android.widget.RelativeLayout/android.widget.LinearLayout/androidx.viewpager.widget.ViewPager/android.widget.RelativeLayout/android.view.ViewGroup/androidx.recyclerview.widget.RecyclerView/android.widget.LinearLayout[1]/android.widget.LinearLayout/android.widget.LinearLayout/android.widget.LinearLayout/android.widget.FrameLayout[1]/android.widget.RelativeLayout/android.widget.LinearLayout[1]/android.widget.TextView")
el4.click()
#####################复制录制的脚本#############################
time.sleep(5)
driver.quit()
运行效果:
报错
An unknown server-side error occurred while processing the command. Original error: Error executing adbExec. Original error: 'Command 'D\:\\adt-bundle-windows-x86_64-20140702\\sdk\\platform-tools\\adb.exe -P 5037 -s d270ac3a shell pm clear com.xueqiu.android' exited with code 255'; Stderr: 'Security exception: PID 26038 does not have permission android.permission.CLEAR_APP_USER_DATA to clear data of package com.xueqiu.android java.lang.SecurityException: PID 26038 does not have permission android.permission.CLEAR_APP_USER_DATA to clear data of package com.xueqiu.android at com.android.server.am.ActivityManagerService.clearApplicationUserData(ActivityManagerService.java:7695) at com.android.server.pm.PackageManagerShellCommand.runClear(PackageManagerShellCommand.java:1632) at com.android.server.pm.PackageManagerShellCommand.onCommand(PackageManagerShellCommand.java:204) at android.os.ShellCommand.exec(ShellCommand.java:103) at com.android.server.pm.PackageManagerService.onShellCommand(PackageManagerService.java:24667) at android.os.Binder.shellCommand(Binder.java:634) at android.os.Binder.onTransact(Binder.java:532) at android.content.pm.IPackageManager$Stub.onTransact(IPackageManager.java:3152) at com.android.server.pm.PackageManagerService.onTransact(PackageManagerService.java:4970) at android.os.Binder.execTransact(Binder.java:731)'; Code: '255'
Security exception: PID 26038 does not have permission android.permission.CLEAR_APP_USER_DATA to clear data of package com.xueqiu.android
原因:
安卓手机未开启OEM解锁
解决:
设置>开发者选项>OEM解锁,改为开启
Capability设置
https://github.com/appium/appium/blob/master/docs/en/writing-running-appium/caps.md
Capability | Description | Values |
---|---|---|
automationName | automation引擎 | Appium (default), or UiAutomator2, Espresso, or UiAutomator1 for Android, or XCUITest or Instruments for iOS, or YouiEngine for application built with You.i Engine |
app | app地址 | /abs/path/to/my.apk or http://myapp.com/app.ipa |
platformName | 手机使用的操作系统 | iOS, Android, or FirefoxOS |
platformVersion | 操作系统版本 | e.g., 7.1, 4.4 |
deviceName | 设备名称 | iPhone Simulator, iPad Simulator, iPhone Retina 4-inch, Android Emulator, Galaxy S4 |
udid | 设备唯一标识符 | e.g. 1ae203187fc012g |
noReset | 不重置app状态 | true, false |
fullReset | 重置app | true, false |
dontStopAppOnReset | 在使用adb启动应用程序之前,不会停止测试应用程序的进程。如果被测试的应用程序是由另一个锚应用程序创建的,设置为false,则允许锚应用程序的进程在使用adb启动测试应用程序期间仍然是活动的。换句话说,当dontStopAppOnReset设置为true时,我们将不会在adb shell am start调用中包含-S标志。省略此功能或将其设置为false后,我们将包含-S标志。默认false | true, false |
newCommandTimeout | 在假定客户机退出并结束会话之前,Appium等待来客户机新命令的时间(以秒为单位) | e.g 60单位秒 |
appActivity【安卓】 | 启动的Android活动(页面)的活动(页面)名 | MainActivity, .Settings |
appPackage【安卓】 | apk包名 | com.example.android.myApp, com.android.settings |
dontStopAppOnReset【安卓】 | 在adb启动应用程序之前,不会停止测试应用程序的进程 | true or false |
skipDeviceInitialization【安卓】 | 跳过设备初始化,包括.安装和运行设置应用程序或设置权限。可用于提高启动性能 | true or false |
unicodeKeyboard【安卓】 | 支持Unicode 输入, 默认为false;切换非英文输入 | true or false |
resetKeyboard【安卓】 | 将键盘重置为其原始状态为false | true or false |
autoGrantPermissions【安卓】 | 在安装时自动授权app所需要的权限,默认为fasle。如果noReset为 true,此配置不生效。 | true or false |
skipDeviceInitialization【安卓】 | 跳过设备初始化,包括安装和运行设置应用程序或设置权限。可用于提高启动性能,设备已用于自动化,并为下一次自动化做好准备。默认为false | true or false |
skipUnlock【安卓】 | 在会话创建期间跳过解锁。默认值为false | true or false |
skipLogcatCapture【安卓】 | 跳过捕捉logcat日志。它可能会提高性能,比如网络。日志相关的命令将无法工作。默认值为false。 | true or false |
systemPort【安卓】 | systemPort用于连接到appium-uiautomator2-server或appium-espresso-driver。默认值一般是8200,对于appium-uiautomator2-server,从8200到8299选择一个端口,对于appium- espreso -driver,从8300到8399选择8300。并行运行测试时,必须调整端口以避免冲突。 | e.g., 8201 |
ignoreUnimportantViews【安卓】 | 调用setCompressedLayoutHierarchy()。忽略一些元素提高运行速度。被忽略的元素将无法找到。默认false | true or false |
重置策略
获取安卓udid
C:\Users\Administrator>adb devices
List of devices attached
eaa66aa37d14 unauthorized
127.0.0.1:62001 device
模拟器
"udid":"127.0.0.1:62001"
真机
"udid":"eaa66aa37d14"
手机设置
开启开发者模式
(1)设置>关于手机>连续点击版本号5次以上
(2)设置中,已经出现【开发者选项】
开启手机指针位置
开发者选项—>指针位置,设为开启状态。开启后,顶部会有指针移动坐标,可定位屏幕上的元素的坐标。
定位工具:uiautomatorviewer.bat
元素定位
常用定位方式
driver.find_element_by_id(resource-id)driver.find_element_by_accessibility_id(content-desc)driver.find_element_by_xpath("//*")
- id定位取 resource-id的值
- accessibility_id定位取 content-desc的值
- xpath定位建议组合定位
元素常用方法
方法 | 释义 |
---|---|
element.click() | 点击 |
element.send_keys(text) | 输入文本 |
element.se_value(value) | 设置元素的值 |
element.clear() | 清除操作 |
element.is_displayed() | 判断元素是否可见,返回true或false |
element.is_enabled() | 判断元素是否可用,返回true或false |
element.is_selected() | 判断元素是否被选中,返回true或false |
element.get_attribute(name) | 获取属性值 |
element.text | 获取元素文本 |
element.location | 获取元素坐标.e.g.{“y”:19,“x”:20} |
element.size | 获取元素尺寸(高和宽)e.g.{“width”:50,“height”:42} |
代码
# pip install appium-python-client
from appium import webdriver
import timeclass TestXueQiu:def setup(self):descrip_cap = {"platformName": "android","deviceName": "Huawei Mate30","appPackage": "com.xueqiu.android","appActivity": ".view.WelcomeActivityAlias","noReset": "True","unicodeKeyboard":"True","resetKeyboard":"True",}self.driver = webdriver.Remote("http://127.0.0.1:4723/wd/hub", descrip_cap)self.driver.implicitly_wait(10)def teardown(self):time.sleep(3)self.driver.quit()def test_xueqiu(self):# 定位、点击搜索框el1 = self.driver.find_element_by_id("com.xueqiu.android:id/tv_search")el1.click()# 输入搜索关键词el2 = self.driver.find_element_by_id("com.xueqiu.android:id/search_input_text")el2.send_keys("阿里巴巴")#点击搜索到的词条el3 = self.driver.find_element_by_xpath("//*[@resource-id='com.xueqiu.android:id/name' and @text='阿里巴巴']")el3.click()# 点击阿里巴巴,进入股票页面el4 = self.driver.find_element_by_xpath("//*[@resource-id='com.xueqiu.android:id/stockName' and @text='阿里巴巴']")el4.click()# 获取当前股价el5 = self.driver.find_element_by_id("com.xueqiu.android:id/stock_current_price")print("阿里巴巴当前股价为:%s"% str(el5.text))# 判断阿里巴巴股价是否大于200assert float(el5.text) > 200
TouchActions
文档:
https://github.com/appium/appium/blob/master/docs/en/writing-running-appium/touch-actions.md
常用方法:
方法 | 释义 |
---|---|
press | 按住 |
release | 释放 |
moveTo | 移动至 |
tap | 点击 |
wait | 等待,单位为ms |
longPress | 长按 |
perform | 执行 |
TouchAction
TouchAction().press(el0).moveTo(el1).release()
MultiTouch同时按住多个元素
action0 = TouchAction().tap(el)
action1 = TouchAction().tap(el)
MultiAction().add(action0).add(action1).perform()
滚动
driver.execute_script("mobile: scroll", {"direction": "down"})
代码
# pip install appium-python-client
from appium import webdriver
import timefrom appium.webdriver.common.touch_action import TouchActionclass TestTouchAction:def setup(self):descrip_cap = {"platformName": "android","deviceName": "Huawei Mate30","appPackage": "cn.kmob.screenfingermovelock","appActivity": "com.samsung.ui.FlashActivity","noReset": "True",}self.driver = webdriver.Remote("http://127.0.0.1:4723/wd/hub", descrip_cap)self.driver.implicitly_wait(10)def teardown(self):time.sleep(3)self.driver.quit()def test_xueqiu(self):#点击开启手势密码el1 = self.driver.find_element_by_accessibility_id("手势密码锁")el1.click()# 绘制手势密码# 以下坐标试用 手机分辨率为540*960coordinate1 = (90,128)coordinate2 = (272,128)coordinate3 = (450,128)coordinate4 = (272,350)wait_time = 220 #单位为ms毫秒TouchAction(self.driver).press(x=coordinate1[0],y=coordinate1[1]).wait(wait_time)\.move_to(x=coordinate2[0],y=coordinate2[1]).wait(wait_time)\.move_to(x=coordinate3[0],y=coordinate3[1]).wait(wait_time)\.move_to(x=coordinate4[0],y=coordinate4[1]).wait(wait_time)\.release().perform()# 点击继续el2 = self.driver.find_element_by_id("cn.kmob.screenfingermovelock:id/btnTwo")el2.click()# 再次绘制绘制手势密码TouchAction(self.driver).press(x=coordinate1[0], y=coordinate1[1]).wait(wait_time) \.move_to(x=coordinate2[0], y=coordinate2[1]).wait(wait_time) \.move_to(x=coordinate3[0], y=coordinate3[1]).wait(wait_time) \.move_to(x=coordinate4[0], y=coordinate4[1]).wait(wait_time) \.release().perform()# 点击确认el3 = self.driver.find_element_by_id("cn.kmob.screenfingermovelock:id/btnTwo")el3.click()
特殊控件toast定位
toast
- 简短消息提示框
- 根据设置的显示时间后自动消失
- 系统级别控件。归属于系统settings。不在app内。
例如下图的“验证码已发送”提示语
定位
通过打印页面元素,可以看到toast元素
<android.widget.Toast index="1" package="com.android.settings" class="android.widget.Toast" text="验证码已发送" checkable="false" checked="false" clickable="false" enabled="false" focusable="false" focused="false" long-clickable="false" password="false" scrollable="false" selected="false" bounds="[0,0][0,0]" displayed="true" />
但是通过class="android.widget.Toast"无法定位到,因此使用Xpath通过文本定位
driver.find_element_by_xpath('//*[@text="验证码已发送"]')
注意:Capability设置需加上automationName,才可以定位到
“automationName”:“uiautomator2”
代码
# pip install appium-python-client
from appium import webdriver
import time
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions
from appium.webdriver.common.mobileby import MobileByclass TestXueQiu:def setup(self):des_caps = {"platformName": "android","deviceName": "Huawei Mate30","appPackage": "com.xueqiu.android","appActivity": ".view.WelcomeActivityAlias","noReset": "True","unicodeKeyboard":"True","resetKeyboard":"True","automationName":"uiautomator2"}self.driver = webdriver.Remote("http://127.0.0.1:4723/wd/hub", des_caps)self.driver.implicitly_wait(10)def teardown(self):time.sleep(3)self.driver.quit()def test_toast(self):# 点击【我的】self.driver.find_element_by_xpath("//*[@resource-id='com.xueqiu.android:id/tab_name' and @text='我的']").click()# 点击【手机号】登录self.driver.find_element_by_id('com.xueqiu.android:id/tv_login_phone').click()# 输入手机号码self.driver.find_element_by_id('com.xueqiu.android:id/register_phone_number').send_keys("18000000000")#任意填个手机号码# 点击【发送验证码】self.driver.find_element_by_id('com.xueqiu.android:id/register_code_text').click()# 等待toast元素加载locator = (MobileBy.XPATH,'//*[@text="验证码已发送"]')WebDriverWait(self.driver,30).until(expected_conditions.presence_of_element_located(locator))# # 打印当前页面元素树print(self.driver.page_source)# toast元素# <android.widget.Toast index="1" package="com.android.settings" class="android.widget.Toast" text="验证码已发送" checkable="false" checked="false" clickable="false" enabled="false" focusable="false" focused="false" long-clickable="false" password="false" scrollable="false" selected="false" bounds="[0,0][0,0]" displayed="true" /># 等待toast元素消失WebDriverWait(self.driver, 30).until_not(expected_conditions.presence_of_element_located(locator))# 定位"重新获取"验证码按钮,获取文案text = self.driver.find_element_by_id('com.xueqiu.android:id/register_code_text').textassert "重新获取" in text
uiautomator定位
https://developer.android.com/reference/android/support/test/uiautomator/UiSelector.html
uiautomator是安卓的工作引擎,速度快,但表达式书写复杂。
常用表达式
表达式 | |
---|---|
new UiSelector().reaourceId(“id”) | 通过id定位 |
new UiSelector().className(“className”) | 通过className定位 |
new UiSelector().descriptioon(“content-desc”) | 通过content-desc定位 |
new UiSelector().text(“text”) | 通过文本定位 |
new UiSelector().textContains(“包含文本”) | 通过包含文本定位 |
new UiSelector().textStartsWith(“以text开头”) | 匹配以text开头的元素 |
new UiSelector().textMatches(“正则表达式”) | 通过正则表达式匹配文本 |
childSelector() | 父子关系定位 |
fromParent() | 兄弟关系定位 |
组合定位:
driver.find_element_by_android_uiautomator('new UiSelector().resourceId("com.xueqiu.android:id/name").text("阿里巴巴")')
父子关系定位:
driver.find_element_by_android_uiautomator('new UiSelector().resourceId("com.xueqiu.android:id/ll_stock_result_view").childSelector(text("阿里巴巴"))')
滚动页面查找元素
self.driver.find_element_by_android_uiautomator('new UiScrollable(new UiSelector().scrollable(true).''instance(0)).scrollIntoView(new UiSelector().textContains("财经").''instance(0))').click()
代码
# pip install appium-python-client
from appium import webdriver
import timeclass TestXueQiu:def setup(self):descrip_cap = {"platformName": "android","deviceName": "Huawei Mate30","appPackage": "com.xueqiu.android","appActivity": ".view.WelcomeActivityAlias","noReset": "True","unicodeKeyboard":"True","resetKeyboard":"True"}self.driver = webdriver.Remote("http://127.0.0.1:4723/wd/hub", descrip_cap)self.driver.implicitly_wait(10)def teardown(self):time.sleep(3)self.driver.quit()def test_check_alibaba(self):# 定位、点击搜索框# el1 = self.driver.find_element_by_id("com.xueqiu.android:id/tv_search")# resourceId("com.xueqiu.android:id/tv_search")el1 = self.driver.find_element_by_android_uiautomator('new UiSelector().resourceId("com.xueqiu.android:id/tv_search")')el1.click()# 输入搜索关键词# el2 = self.driver.find_element_by_id("com.xueqiu.android:id/search_input_text")el2 = self.driver.find_element_by_android_uiautomator('new UiSelector().resourceId("com.xueqiu.android:id/search_input_text")')el2.send_keys("阿里巴巴")#点击搜索到的词条# Xpath定位# el3 = self.driver.find_element_by_xpath("//*[@resource-id='com.xueqiu.android:id/name' and @text='阿里巴巴']")el3 = self.driver.find_element_by_android_uiautomator('new UiSelector().resourceId("com.xueqiu.android:id/name").text("阿里巴巴")')el3.click()# 点击阿里巴巴,进入股票页面# Xpath定位# el4 = self.driver.find_element_by_xpath("//*[@resource-id='com.xueqiu.android:id/stockName' and @text='阿里巴巴']")# el4 = self.driver.find_element_by_android_uiautomator('new UiSelector().resourceId("com.xueqiu.android:id/stockName").text("阿里巴巴")')# 通过搜索结果列表框定位其儿子节点中text为“阿里巴巴”的元素el4 = self.driver.find_element_by_android_uiautomator('new UiSelector().resourceId("com.xueqiu.android:id/ll_stock_result_view").childSelector(text("阿里巴巴"))')el4.click()# 获取当前股价# el5 = self.driver.find_element_by_id("com.xueqiu.android:id/stock_current_price")el5 = self.driver.find_element_by_android_uiautomator('new UiSelector().resourceId("com.xueqiu.android:id/stock_current_price")')print("阿里巴巴当前股价为:%s"% str(el5.text))# 判断阿里巴巴股价是否大于200assert float(el5.text) > 200def test_scroll_to_article(self):time.sleep(1)# 滚动匹配包含"财经"的文本,并点击self.driver.find_element_by_android_uiautomator('new UiScrollable(new UiSelector().scrollable(true).''instance(0)).scrollIntoView(new UiSelector().textContains("财经").''instance(0))').click()
踩坑
ui automator识别模拟器为横屏
原因:
ui automator识别通过分辨率识别为横屏
解决:
设置模拟器分辨率
Selenium error: Could not parse UiSelector argument: ‘com.xueqiu.android:id/tv_search’ is not a stringCall to ‘10’ failed
Call to ‘10’ failed
[elements("-android uiautomator",“new UiSelector().resourceId(‘com.xueqiu.android:id/tv_search’)”)] Error response status: 9, , UnknownCommand - The requested resource could not be found, or a request was received using an HTTP method that is not supported by the mapped resource. Selenium error: Could not parse UiSelector argument: ‘com.xueqiu.android:id/tv_search’ is not a string
原因:
定位表达式中使用了单引号
new UiSelector().resourceId(‘com.xueqiu.android:id/tv_search’)
解决:
定位表达式中使用了双引号
new UiSelector().resourceId(“com.xueqiu.android:id/tv_search”)
appium(2)简单的demo、元素定位相关推荐
- python元素定位id和name_python中通过selenium简单操作及元素定位知识点总结
浏览器的简单操作 # 导入webdriver模块 # 创建driver对象,指定Chrome浏览器 driver = webdriver.Chrome() # 窗口最大化 driver.maximiz ...
- Appium移动端自动化测试之元素定位(三)
1.name定位 driver.find_element_by_id('com.shanjian.originaldesign:id/edit_Tel').send_keys('15817252876 ...
- appium微信公众号分类元素定位方法
appium自动化遇到定位分类中的元素,开始以为切换分类是一个新的页面,一直定位元素都提示元素不可交互,原因是实际上三个分类中的元素都是一个前端页面展示,你去切换分类定位第二个分类里元素,实际上定位的 ...
- Appium+PythonUI自动化测试之uiautomatorviewer和Inspector元素定位
一.uiautomatorviewer uiautomatorviewer是android-sdk自带的一个元素定位工具,非常简单好用,使用uiautomatorviewer,你可以检查一个应用的UI ...
- Appium 自动化测试元素定位工具使用
简介 前面环境基本都搭建好了,相关的知识也准备的差不多了,那么我们就开始下一步元素定位,元素定位首先需要知道使用哪些元素定位工具,本文讲解常见的元素定位工具uiautomatorviewer和 ...
- Appium+python自动化(九)- 定位元素工具(义结金兰的两位异性兄弟)(超详解)...
简介 环境搭建好了,其他方面的知识也准备的差不多了,那么我们就开始下一步元素定位,元素定位宏哥主要介绍如何使用uiautomatorviewer,通过定位到页面上的元素,然后进行相应的点击等操作. 此 ...
- [Appium] App自动化-元素定位
[Appium] App自动化-元素定位及工具 一.元素定位工具简介 Web自动化是通过浏览器自带的F12键进行元素定位,但是App自动化支持三大定位工具(UIAutomatorView/Appium ...
- Appium(三)常用的8种元素定位方式之 id、name、class、相对定位
其实APP自动化测试的元素定位方式和Web自动化测试元素定位方式大体相同,无论是APP还是Web自动化测试,最重要的一个环节就是获取元素的定位,只有准确的定位到了元素才能进行相关元素的操作,而Appi ...
- 【资料补充】元素定位和定位辅助工具
Web页面组成-代码 <!DOCTYPE html> <html lang="en"> <head><meta charset=" ...
最新文章
- css:z-index
- 微服务时代组件化和服务化的抉择
- 互联网+大赛作品_“颂中国力量 绘美好梦想”全市中小学生互联网+书画大赛作品展示(二十六)...
- 赶上直播电商、在线教育、小程序直播的风口 腾讯音视频解决方案助力
- 李宏毅线性代数笔记 10: PageRank
- maven工程如何引用css和js文件
- IOT(Index Organized Table)
- pymysql安装_centos7.6 安装openstack stein组件之四
- ubuntu 14.04 配置 java 环境
- Android Studio 插件——《阿里巴巴 Java 开发规约》的扫描插件
- 微软官方出的各种dll丢失的修复工具
- 这些年,我身边的那些人和事
- 笔记本计算机摄像头怎么打开,手把手教你笔记本内置摄像头打不开解决方法
- 笔记工具:幕布 简要使用教程
- 我的世界服务器修改高度放水,我的世界:水不够用?学会这4种方法,教你一桶水造无限水...
- 高可用集群下的负载均衡(6):haproxy实现访问不同资源的负载均衡(日志、监控、acl访问控制的配置)
- Java实现印刷体转手写体—妈妈再也不用担心我被罚抄作业了
- Iso中查看Windows版本
- 蘑菇丁工学云打卡教程
- Stata做空间杜宾模型、莫兰指数等操作