Selenium Begin:
1.安装Selenium: pip3 install selenium
2.第一个Selenium自动化测试脚本 test_baidu.py (要注意chrome浏览器对自身版本和chromedriver对版本要相匹配)
3.WebDriver的8种定位方法:
a、id定位:通过元素的id来定位
b、name定位:通过元素的name来定位
c、class定位:通过元素的class类名来定位
d、tag定位:通过元素的标签名来定位如:
定位一个输入框,即find_element_by_tag_name("input")
e、link定位:通过元素所包含的link链接的名称来定位,
如hao123,即find_element_by_link_text("hao123")
f、partial link定位:通过元素所包含的link链接的名称来定位,当其名称很长时,对部分文字定位也可行,
如一个很长的文本链接,即find_element_by_partial_link_text("文本链接")
g、XPath定位:
(1)、绝对路径定位:
如定位百度输入框,通过代码层级结构:find_element_by_xpath("/html/body/div/div[2]/div/div/div/form/span/input")
(2)、利用元素属性定位:
如定位百度输入框,通过元素属性值来定位:find_element_by_xpath("//input[@id = "kw"]")
该元素的任意属性值都可以使用,如果不想指定标签名,可以用 * 号代替
(3)、层级与属性结合:
如定位百度输入框,假如输入框没有可利用的属性值,可以查找它上一级的属性:find_element_by_xpath("//span[@class = "bg s_ipt_wr"]/input")
(4)、使用逻辑运算符:
如定位百度输入框,如果一个属性不能唯一区分一个元素,那么我们可以使用逻辑运算符连接多个属性来查找元素:find_element_by_xpath("//input[@id = "kw" and @class = "s_ipt"]")
(5)、使用contains方法:
如定位百度输入框,用于匹配一个属性中包含的字符串:find_element_by_xpath("//span[contains(@class, "s_ipt_wr")]/input")
(6)、使用text()方法:
如定位e中的a标签,find_element_by_xpath("//a[text(), "hao123"]")
h、CSS_selector定位:
(1)、通过class定位:
如定位百度输入框:find_element_by_css_selector(".s_ipt") 定位class = "s_ipt"的所有元素
(2)、通过id定位:
如定位百度输入框:find_element_by_css_selector("#kw") 定位id = "kw"的所有元素
(3)、通过标签名定位:
如定位百度输入框:find_element_by_css_selector("input") 定位所有的input标签元素
(4)、通过标签层级关系定位:
如定位百度输入框:find_element_by_css_selector("span > input") 定位父元素为span的所有input标签元素
(5)、通过属性定位:
如定位百度输入框:find_element_by_css_selector("[autocomplete = off]") 定位autocomplete属性 = off的所有标签元素
(6)、组合定位:
如定位百度输入框:find_element_by_css_selector("form.fm > span > input.s_ipt") 定义class为fm的父标签form的span的class为s_ipt的input标签元素
(7)、更多定位方法可查看 http://www. w3school.com.cn/cssref/ css_selectors.asp ,XPath和CSS都提供来了非常强大且灵活的定位方法,我们只需掌握一种即可解决大部分问题
i、用By定位元素:
通过By也其实所WebDriver的另一套写法,这种更易阅读和理解,强推!!!!!!!
统一调用find_element()方法,通过By来声明定位,并且传入对应定位方法的定位参数,如:
首先需要导入By:
from selenium.webdriver.common.by import By
find_element(By.ID, "kw")
find_element(By.NAME, "wd")
find_element(By.CLASS_NAME, "s_ipt")
find_element(By,TAG_NAME, "input")
find_element(By.LINK_TEXT, "hao123")
find_element(By.PARTIAL_LINK_TEXT, "hao1")
find_element(By.XPATH, "//*[@class = "bg s_btn"]")
find_element(By.CSS_SELECTOR, "span.bg s_btn_wr > input#su")
Warning:当class = “bg asd”这种存在空格情况的时候,取其中一个定位即可,并需要确认其唯一性
4.控制浏览器:
a、控制浏览器窗口大小:driver.set_window_size(1000, 1000)
b、控制浏览器前进、后退:driver.forward()、driver.back()
c、刷新浏览器:driver.refresh()
5.WebDriver中常用方法:
a、清除文本:search_frame.clear()
b、模拟按键输入:search_frame.send_keys("Appium & Selenium")
c、提交表单:search_button.submit()
d、返回元素尺寸:search_frame.size
e、获取元素到文本:search_frame.text
f、获得属性值:search_frame.get_attribute("name")
g、判断该元素是否用户可见:search_frame.is_displayed()
6.鼠标操作:
(需要先导入from selenium.webdriver import ActionChains)
a、执行ActionChains类中存储的所有行为:ac(driver).move_to_element(driver.find_element(By.ID, "s-usersetting-top")).perform()
b、右击:context_click()
c、双击:ac(driver).move_to_element(driver.find_elementac(driver).move_to_element(driver.find_element(By.ID, "s-usersetting-top")).perform()(By.NAME, "tj_briicon")).double_click().perform()
d、拖动:# driver切换到新页面并执行 拖动
windows = driver.window_handles
driver.switch_to.window(windows[-1])
ac(driver).drag_and_drop(driver.find_element(By.XPATH, "//a[@href = '小度商城官网']"),
driver.find_element(By.CLASS_NAME, "s_ipt_wr")).perform()
e、鼠标悬停:ac(driver).move_to_element(driver.find_element(By.ID, "s-usersetting-top")).perform()
以上为显示各方法的独立执行效果,实际项目中,可使用如下写法步骤清晰,完整执行:
ac = ActionChains(driver)
ac.move_to_element(xxxx) # xxxx是定位到的元素
ac.double_click()
ac.perform()
7.键盘操作:
(需要先导入from selenium.webdriver.common.keys import Keys)
a、删除键:send_keys(Keys.BACK_SPACE)
b、空格键:send_keys(Keys.SPACE)
c、制表键:send_keys(Keys.TAB)
d、回退键esc:send_keys(Keys.ESCAPE)
e、回车键:send_keys(Keys.ENTER)
f、全选:send_keys(Keys.CONTROL, 'a')
g、复制:send_keys(Keys.CONTROL, 'c')
h、剪切:send_keys(Keys.CONTROL, 'x')
i、粘贴:send_keys(Keys.CONTROL, 'v')
j、键盘F1:send_keys(Keys.F1')
……
z、键盘F12:send_keys(Keys.F12)
8、获得验证信息:
(最常用的几个验证信息用于web自动化测试中,如后续断言使用)
a、获取当前页面标题:print("当前界面的title是:%s" %(driver.title))
b、获取当前页面URL:print("当前界面的url是:%s" %(driver.current_url))
c、获取当前页面元素的文本信息:print("当前页面的文本信息是:%s" %(driver.find_element(By.CLASS_NAME, "s-top-right-text").text))
9、设置元素等待:
(需要导入:from selenium.webdriver.support.ui import WebDriverWait + from selenium.webdriver.support import expected_conditions)
a、显式等待:显式等待会等到这个元素出现后,才进行下一步
baidu_input = WebDriverWait(driver, 5, 0.5).until(ec.visibility_of_element_located((By.ID, "kw")))
baidu_input.send_keys("我是显式等待,我等到了!")
b、隐式等待:隐式等待会在整个页面中等待所有元素,当代码需要定位当元素定位到之后边会继续进行,超时一直定位不到则报异常
driver.implicitly_wait(10)
baidu_input = driver.find_element(By.ID, "kw")
baidu_input.send_keys("我是隐式等待,我等到了")
如下是expected_contions类提供到预期条件判断的几个方法:(最后只列举几个)
(1)、判断当前页面标题是否等于预期:title_is()
(2)、判断当前页面标题是否包含预期字符串:title_contains()
(3)、判断元素是否在DOM树里,并不代表该元素一定可见:presence_of_element_located()
(4)、判断元素是否可见:visibility_of_element_located()
(5)、与上一个方法作用相同,上一个方法的参数为定位,该方法接收定位后的元素:visibility_of()
(6)、判断是否至少有一个元素在DOM树中:presence_of_all_elements_located()
(7)、判断某个元素中的text是否包含预期字符串:text_to_be_present_in_element()
(8)、判断某个元素的value是否包含预期字符串:text_to_be_present_in_element_value()
(9)、判断该表单是否可以切换进去:frame_to_be_available_and_switch_to_it()
(10)、判断某个元素是否在DOM树中不可见:invisibility_of_element_located()
(11)、判断某个元素是否可见并是可点击的:element_to_be_clickable()
(12)、等到一个元素从DOM树中移除,可判断界面是否刷新:staleness_of()
(13)、判断某个元素是否被选中:element_to_be_selected()
(14)、判断某个元素的选中状态是否符合预期:element_selection_state_to_be()
(15)、与上一个方法作用相同,只是上一个方法参数为定位后的元素,该方法接收的参数为定位:element_located_selection_state_to_be()
(16)、判断页面上是否存在alert:alert_is_present()
例子:
expected_conditions预期条件判断方法
current_title = ec.title_is("百度一下,你就知道")
print(current_title(driver))
current_title_contains = ec.title_contains("百度")
print(current_title_contains(driver))
driver.get("Tencent 腾讯")
alert = ec.alert_is_present()
print(alert(driver))
10、定位一组元素:在定位单个元素的基础上element -> elements
11、多表单切换:因为Webdriver只能在一个页面上对元素进行识别和定位,因此在遇到frame/iframe对情况时,要通过switch_to.frame()方法将主体
切换为frame/iframe的内嵌页面:
# 定位iframe中的元素
driver.get("126网易免费邮--你的专业电子邮")
login_frame = driver.find_element_by_css_selector('iframe[id^="x-URS-iframe"]') # 在CSS定位中,可以用^=匹配以其为开头的元素
driver.switch_to.frame(login_frame)
account_input = driver.find_element(By.XPATH, "//input[@data-type = 'email' and @name = 'email']")
account_input.send_keys("guangtao.chen")
driver.switch_to.default_content # 切回到最外层的页面
12、多窗口切换:在页面操作时,在弹出的新窗口中进行识别和定位,就需要切换到新到窗口才能操作
current_window = driver.current_window_handle
login_btn = driver.find_element(By.CLASS_NAME, "s-top-login-btn")
login_btn.click()
sleep(1)
regist_btn = driver.find_element(By.CLASS_NAME, "pass-reglink")
regist_btn.click()
sleep(1)
windows = driver.window_handles
for handle in windows:
if handle != current_window:
driver.switch_to.window(handle)
account_input = driver.find_element(By.ID, "TANGRAM__PSP_4__userName")
account_input.send_keys("792607724")
13、警告框处理:
首先使用switch_to.alert()方法定位,然后使用如下方法进行操作:
a、text:返回alert、confirm、prompt中的文字信息
b、accept():接受现有警告框
c、dismiss():解散现有警告框
d、send_keys():在警告框中输入文本
14、下拉框处理:
# 非select下拉框定位:直接定位到下拉菜单,再对其中对元素定位
#以百度:设置->高级搜索->全部时间下拉框
settings_btn = driver.find_element(By.ID, "s-usersetting-top")
settings_btn.click()
sleep(1)
search_settings = driver.find_element(By.CLASS_NAME, "setpref")
search_settings.click()
sleep(1)
settings_Tabs = driver.find_element(By.XPATH, "//ul[@class = 'pftab_hd']")
advanced_search = settings_Tabs.find_element(By.XPATH, "//li[@data-tabid = 'advanced']")
advanced_search.click()
sleep(1)
whole_time_span = driver.find_element(By.ID, "adv-setting-gpc")
time_dropdown_list = whole_time_span.find_element(By.CLASS_NAME, "c-select-dropdown-list")
time_drop_list_items = time_dropdown_list.find_elements_by_class_name("c-select-item")
for item in time_drop_list_items:
print(item.get_attribute("textContent")) # 这边使用text打印不出,所以换成获取元素属性的textContent或innerText或innerHTML即可
print(item.get_attribute("innerText"))
print(item.get_attribute("innerHTML"))
# select下拉框定位:先定位到下拉框,再通过不同定位方式去定位元素
# 暂无实例
a、Select类:用于定位
# coding = utf8
import os
os.path.abspath(".")
from selenium import webdriver
from time import sleep
from selenium.webdriver import ActionChains as ac, TouchActions as ta
from selenium.webdriver.common.by import By
from selenium.webdriver.common.keys import Keys
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as ec
from pykeyboard import PyKeyboard
from pymouse import PyMouse
import pyperclip
from selenium.common.exceptions import UnexpectedAlertPresentException
# driver = webdriver.Safari()
# driver = webdriver.Chrome()
# driver.get("https://www.baidu.com")
# 设置浏览器窗口大小
# print("设置窗口大小")
# driver.set_window_size(1500, 800)
# sleep(1)
# 鼠标悬停中设置菜单上
# ac(driver).move_to_element(driver.find_element(By.ID, "s-usersetting-top")).perform()
# sleep(1)
# 鼠标右击
# ac(driver).context_click().perform()
# sleep(1)
# 鼠标双击
# ac(driver).move_to_element(driver.find_element(By.NAME, "tj_briicon")).double_click().perform()
# ac(driver).move_to_element(driver.find_element(By.NAME, "tj_briicon")).click().perform()
# sleep(1)
# driver切换到新页面并执行 拖动
# windows = driver.window_handles
# driver.switch_to.window(windows[-1])
# ac(driver).drag_and_drop(driver.find_element(By.XPATH, "//a[@href = 'https://dumall.baidu.com/?utm_source=baidu&utm_medium=all-products']"),
# driver.find_element(By.CLASS_NAME, "s_ipt_wr")).perform()
# search_frame = driver.find_element_by_id("kw")
# search_frame.send_keys("Selenium")
# sleep(1)
# search_frame.send_keys(Keys.BACK_SPACE)
# print("删除一个m")
# print("当前界面的title是:%s" %(driver.title))
# print("当前界面的url是:%s" %(driver.current_url))
# # print("当前页面的文本信息是:%s" %(driver.find_element(By.XPATH, "//span[contains(@class, 's_ipt')]").text))
# print("当前页面的文本信息是:%s" %(driver.find_element(By.CLASS_NAME, "s-top-right-text").text))
# print("清除输入框内容")
# search_frame.clear()
# sleep(1)
# print("输入Appium & Selenium")
# search_frame.send_keys("Appium & Selenium")
# search_button = driver.find_element_by_id("su")
# # search_button.click()
# print("按下回车键,这里也可以使用click点击!")
# search_button.submit()
# sleep(1)
# print("获取输入框尺寸:")
# print(search_frame.size)
# sleep(1)
# print("输入框文本信息为:")
# print(search_frame.text)
# sleep(1)
# print("输入框name属性是:")
# print(search_frame.get_attribute("name"))
# sleep(1)
# print("输入框是否用户可见:")
# print(search_frame.is_displayed())
# sleep(1)
# print("跳转到腾讯网主页")
# driver.get("https://www.tencent.com")
# sleep(1)
# driver.back()
# print("回到百度搜索selenium界面")
# sleep(1)
# driver.forward()
# print("前进到腾讯网主页界面")
# 显式等待:显式等待会等到这个元素出现后,才进行下一步
# baidu_input = WebDriverWait(driver, 5, 0.5).until(ec.visibility_of_element_located((By.ID, "kw")))
# baidu_input.send_keys("我是显式等待,我等到了!")
# 隐式等待:隐式等待会在整个页面中等待所有元素,当代码需要定位当元素定位到之后边会继续进行,超时一直定位不到则报异常
# driver.implicitly_wait(10)
# baidu_input = driver.find_element(By.ID, "kw")
# baidu_input.send_keys("我是隐式等待,我等到了")
# expected_conditions预期条件判断方法
# current_title = ec.title_is("百度一下,你就知道")
# print(current_title(driver))
# current_title_contains = ec.title_contains("百度")
# print(current_title_contains(driver))
# driver.get("https://www.tencent.com")
# alert = ec.alert_is_present()
# print(alert(driver))
# alert = driver.switch_to_alert()
# print(alert)
# elements = driver.find_elements_by_xpath("//span[@class = 'title-content-title']")
# for i in elements:
# print(i.text)
# print(type(i))
# 定位iframe中的元素
# driver.get("https://www.126.com")
# login_frame = driver.find_element_by_css_selector('iframe[id^="x-URS-iframe"]')
# driver.switch_to.frame(login_frame)
# account_input = driver.find_element(By.XPATH, "//input[@data-type = 'email' and @name = 'email']")
# account_input.send_keys("guangtao.chen")
# driver.switch_to.default_content
# 多窗口切换
# current_window = driver.current_window_handle
# login_btn = driver.find_element(By.CLASS_NAME, "s-top-login-btn")
# login_btn.click()
# sleep(1)
# regist_btn = driver.find_element(By.CLASS_NAME, "pass-reglink")
# regist_btn.click()
# sleep(1)
# windows = driver.window_handles
# for handle in windows:
# if handle != current_window:
# driver.switch_to.window(handle)
# account_input = driver.find_element(By.ID, "TANGRAM__PSP_4__userName")
# account_input.send_keys("792607724")
# 非select下拉框定位:直接定位到下拉菜单,再对其中对元素定位
#以百度:设置->高级搜索->全部时间下拉框
# settings_btn = driver.find_element(By.ID, "s-usersetting-top")
# settings_btn.click()
# sleep(1)
# search_settings = driver.find_element(By.CLASS_NAME, "setpref")
# search_settings.click()
# sleep(1)
# settings_Tabs = driver.find_element(By.XPATH, "//ul[@class = 'pftab_hd']")
# advanced_search = settings_Tabs.find_element(By.XPATH, "//li[@data-tabid = 'advanced']")
# advanced_search.click()
# sleep(1)
# whole_time_span = driver.find_element(By.ID, "adv-setting-gpc")
# time_dropdown_list = whole_time_span.find_element(By.CLASS_NAME, "c-select-dropdown-list")
# time_drop_list_items = time_dropdown_list.find_elements_by_class_name("c-select-item")
# for item in time_drop_list_items:
# print(item.get_attribute("textContent")) # 这边使用text打印不出,所以换成获取元素属性的textContent或innerText或innerHTML即可
# print(item.get_attribute("innerText"))
# print(item.get_attribute("innerHTML"))
# select下拉框定位:先定位到下拉框,再通过不同定位方式去定位元素
# 暂无实例
# Mac中上传文件,Windows下直接把文件地址贴进去就好了,Mac中需要用到模拟键盘使用快捷键进行交互
# soutu_btn = driver.find_element(By.CLASS_NAME, "soutu-btn")
# soutu_btn.click()
# sleep(1)
# choose_file_btn = driver.find_element(By.CLASS_NAME, "upload-pic")
# with open("/Users/cgt/Desktop/picture/537.jpg") as file:
# choose_file_btn.send_keys(file.name) # 这边百度识图是input按钮,我佛了,所以下面的非input的先不用了
# k = PyKeyboard()
# m = PyMouse()
# # 模拟快捷键Command + Shift + G
# k.press_keys(["Command", "Shift", "G"])
# # 输入文件路径
# k.type_string(file.name)
# # 前往文件
# k.press_keys(["Return"])
# # 点击确定进行上传
# k.press_keys(["Return"])
# Firefox 浏览器下载文件
# fp = webdriver.FirefoxProfile()
# fp.set_preference("browser.download.folderList", 2)
# fp.set_preference("browser.download.dir", os.getcwd())
# fp.set_preference("browser.helperApps.neverAsk.saveToDisk", "binary/octet-stream")
# driver = webdriver.Firefox(firefox_profile = fp)
# driver.get("https://pypi.org/project/selenium/#files")
# driver.find_element_by_partial_link_text("selenium-3.141.0.tar.gz").click()
# Chrome 浏览器下载文件
# co = webdriver.ChromeOptions()
# prefs = {"profile.default_content_settings.popups" : 0, "download.default_directory" : os.getcwd()}
# co.add_experimental_option("prefs", prefs)
# driver = webdriver.Chrome(chrome_options = co)
# driver.get("https://pypi.org/project/selenium/#files")
# driver.find_element_by_partial_link_text("selenium-3.141.0.tar.gz").click()
# 操作Cookie
# driver = webdriver.Chrome()
# driver.get("http://www.baidu.com")
# driver.add_cookie({"name" : "Bruce", "value" : "Cat"}) # 添加Cookie需要按照浏览器支持的cookie进行添加
# driver.delete_cookie("Bruce") # 删除特定名的值为为Bruce的cookie
# for cookie in driver.get_cookies():
# print("%s -> %s" %(cookie["name"], cookie["value"]))
# 调用JavaScript
# driver = webdriver.Chrome()
# driver.get("http://www.baidu.com")
# driver.set_window_size(800, 600)
# driver.find_element_by_id("kw").send_keys("Selenium")
# driver.find_element_by_id("su").click()
# js = "window.scrollTo(200, 350)"
# sleep(5)
# driver.execute_script(js)
# 使用JavaScript对页面中的textarea框进行输入
# driver = webdriver.Chrome()
# driver.get("file:///Users/cgt/Selenium_Project/model.html")
# text = "Textarea need use JavaScript to control ~"
# js = "document.getElementById('id').value = '" + text + "';"
# driver.execute_script(js)
# 处理HTML5视频播放
# driver = webdriver.Chrome()
# driver.get("http://videojs.com/")
# sleep(8)
# video = driver.find_element_by_id("preview-player_html5_api")
# url = driver.execute_script("return arguments[0].currentSrc;", video)
# print(url)
# print("播放视频")
# sleep(3)
# driver.find_element_by_class_name("Typography__H1-sc-1hs8ygb-0").click() # Chrome等浏览器对video的autoplay定义了新标准,需要模拟一次click事件,才可继续播放
# driver.execute_script("return arguments[0].play()", video)
# sleep(15)
# print("暂停视频")
# driver.execute_script("arguments[0].pause()", video)
# 滑动解锁
# driver = webdriver.Chrome()
# driver.get("https://www.helloweba.net/demo/2017/unlock/")
# slider = driver.find_elements_by_class_name("slide-to-unlock-handle")[0] # 定位到滑动块,滑动块也是样式变化展现
# action = ac(driver) # 鼠标事件
# action.click_and_hold(slider).perform()
# for index in range(999):
# try:
# action.move_by_offset(index + 50, 0).perform() # 拖动的距离offset
# sleep(0.1)
# except UnexpectedAlertPresentException: # 弹出alert后需要会直接报错,这里我们直接break规避一下
# break
# success_text = driver.switch_to.alert.text
# print(success_text)
# 滑动选则日期 -- 无效目前原因暂不明确
# 这里会报W3C错误,TouchActions,需要先退出W3C模式
# chromeOptions = webdriver.ChromeOptions()
# chromeOptions.add_experimental_option("w3c", False)
# driver = webdriver.Chrome(options = chromeOptions)
# driver.get("http://www.jq22.com/yanshi4976")
# sleep(5)
# driver.switch_to.frame("iframe")
# driver.find_element_by_id("appDate").click()
# dwwos = driver.find_elements_by_class_name("dwwo")
# year = dwwos[0]
# month = dwwos[1]
# day = dwwos[2]
# action = ta(driver) # 触摸事件
# action.scroll_from_element(year, 0, 4).perform()
# action.scroll_from_element(month, 0, 15).perform()
# action.scroll_from_element(day, 0, 17).perform()
# 换一种ActionChains去滑动选择日期,具体情况目前只能根据每一个ul的高度去滑,当前还没有什么好的办法,如果有好的办法请告诉我,谢谢
# driver = webdriver.Chrome()
# driver.get("http://www.jq22.com/yanshi4976")
# sleep(5)
# driver.switch_to.frame("iframe")
# driver.find_element_by_id("appDate").click()
# dwwos = driver.find_elements_by_class_name("dwwo")
# dwuls = driver.find_elements_by_class_name("dw-ul")
# year = dwwos[0]
# month = dwwos[1]
# day = dwwos[2]
# action = ac(driver)
# action.click_and_hold(year).perform()
# action.move_by_offset(0, 10).perform()
# action.release().perform()
# sleep(2)
# action.click_and_hold(month).perform()
# action.move_by_offset(0, 20).perform()
# action.release().perform()
# sleep(2)
# action.click_and_hold(day).perform()
# action.move_by_offset(0, 30).perform()
# action.release().perform()
# 窗口截图及关闭窗口
# driver = webdriver.Chrome()
# driver.get("http://www.baidu.com")
# driver.save_screenshot("temp_screenshot.png")
# sleep(1)
# open_url = "http://www.163.com"
# js = "window.open('" + open_url + "');"
# driver.execute_script(js)
# sleep(2)
# 关闭新打开的窗口,close和quit不同,quit直接退出浏览器了
# driver.switch_to.window(driver.window_handles[-1])
# driver.close()
# driver.refresh()
print("刷新浏览器n! = ! 脚本结束 != !")
# driver.quit()
关注 + 收藏 + 点赞哦,谢谢啦~