北京時間晚上十一點,突然電腦右下角的QQ彈出了一條消息,”在?”
都9012年了還會有人單獨發(fā)個”在”然后人就失蹤了?有事情找就直接說事情嘛,你不說事情,我怎么知道我應該”在”還是應該”不在”呢?
?
鼠標移動到右下角準備點擊”取消閃爍”時發(fā)現(xiàn),是小美。
感覺空氣中突然彌漫著一種說不明的東西,還是忍不住回復了一句,”在,什么事情?”
“你明天下午一點方便使用電腦嗎?”
唉,有什么事情為什么不可以一口氣說完呢,為什么總要說半句呢,如果我在這個人面前我肯定一個大嘴巴子上去了。但,這是小美。”方便”。
?
“我明天選修課要搶課,你方便的話幫我一下唄,我和朋友約了出去玩了。”
果不其然,在我學會了如何修電腦、如何恢復數(shù)據(jù)、如何下載視頻等技能后,又有新的技能樹即將需要被點亮。不過區(qū)區(qū)搶選修課能難到我?我不僅要搶到,還要搶得漂亮,搶得安逸,搶得讓自己都佩服!
?
“No problem!搶課地址,賬號,密碼,課程名。”
這干脆利落的語氣,完美。
?
搶課只是一件小事,無非是打開瀏覽器,等時間到了瘋狂點擊。但想必大多數(shù)人都在大學時候有過慘痛的經歷,無外乎學校網(wǎng)絡太差,熱門課程搶的人數(shù)太多自己不一定能搶到。同樣,我也并不能保證自己在第二天下午一點的時候盯著屏幕不停地點,或者舒服一點用鼠標連點器不停地點,就能很大可能地搶到需要的課程。
?
學校的網(wǎng)絡沒法拯救,只能拯救自身的網(wǎng)絡;搶同一門課程的人數(shù)多,我們就需要開更多的窗口去搶!
?
很好,看來我們需要搞定一段自動搶課的代碼,然后在自己機器上部署、在舍友機器上部署、在云環(huán)境部署、在網(wǎng)絡好的其他機器部署,想必這總能最大可能性搶到想要的課程了吧。
?
我仿佛看到了一個幕后黑手看著自己的屏幕嘿嘿嘿地笑著:
?
王小明 世界電子競技 搶課中...
吳小杰 芭蕾舞藝術 搶課成功
陳小龍 基礎烹飪知識 搶課成功
劉小鄉(xiāng) 莎士比亞戲劇選 搶課中...
...
搶課,我從來沒怕過誰。
?
此前在學習python爬蟲的時候接觸過selenium的知識,完全可以適配這樣瀏覽器操作場景。
可以先用selenium寫一個操作瀏覽器搶課的腳本,再用flask來接收外部的請求命令執(zhí)行對應的搶課腳本,用docker打包成鏡像,再到能暫時操作的所有電腦,云服務器部署一套。
等快到搶課時間了,安安心心躺在椅子上,執(zhí)行一下批量發(fā)送請求的腳本,就可以靜待搶課成功的好消息了。
我只想發(fā)出三個字的聲音:還!有!誰!
官網(wǎng)介紹
can be controlled by many programming languages and testing frameworks.
Selenium 官網(wǎng):http://seleniumhq.org/
Selenium Github 主頁:https://github.com/SeleniumHQ/selenium
百度百科
Selenium是一個用于Web應用程序測試的工具。
Selenium測試直接運行在瀏覽器中,就像真正的用戶在操作一樣。
支持的瀏覽器包括IE(7, 8, 9, 10, 11),Mozilla Firefox,Safari,Google Chrome,Opera等。
這個工具的主要功能包括:測試與瀏覽器的兼容性——測試你的應用程序看是否能夠很好得工作在不同瀏覽器和操作系統(tǒng)之上。
測試系統(tǒng)功能——創(chuàng)建回歸測試檢驗軟件功能和用戶需求。
支持自動錄制動作和自動生成 .Net、Java、Perl等不同語言的測試腳本。
功能
框架底層使用JavaScript模擬真實用戶對瀏覽器進行操作。
測試腳本執(zhí)行時,瀏覽器自動按照腳本代碼做出點擊,輸入,打開,驗證等操作,就像真實用戶所做的一樣,從終端用戶的角度測試應用程序。
使瀏覽器兼容性測試自動化成為可能,盡管在不同的瀏覽器上依然有細微的差別。
使用簡單,可使用Java,Python等多種語言編寫用例腳本。
簡單來說,起初selenium是一套用于web自動化測試的工具,其本身具備了對多種瀏覽器/操作系統(tǒng)的兼容支持,且能通過多種語言進行操作控制。但其強大的功能不僅僅適用于web自動化測試領域,同樣也被廣泛地使用在爬蟲以及rpa(Robotic Process Automation)相關的業(yè)務場景上。 而我們現(xiàn)在需要實現(xiàn)的可以說就是一個簡單的rpa功能。
筆者開發(fā)環(huán)境:Mac OS、PyCharm、python3.6、chrome
筆者提供的測試網(wǎng)址:www.uncleyiba.com
該網(wǎng)址可自行注冊,或者使用測試賬號nvshen/nvshen
因為是沿用的很久之前剛接觸tornado時候的代碼,所以對tornado的使用有一些誤解。[1]
因此可能導致如果多人使用線上測試環(huán)境,會有一些問題出現(xiàn)。
所以建議可以本地啟一套測試環(huán)境。
測試網(wǎng)站及selenium腳本源碼:selenium_example(https://github.com/uncleYiba/selenium_example)
使用方式見readme.md
對于selenium而言,需要實現(xiàn)我們的需求,著重要關注兩點:
1.頁面元素定位
是否能準確獲取到我們需要進行操作的元素
2.頁面元素操作
點擊、填入、清楚內容、獲取數(shù)據(jù)、雙擊、按住、松開、拖動等
既然是操作瀏覽器進行需求實現(xiàn),那我們必然要對前端有一些了解。也就是說html和js相關知識需要有一些涉獵,另外需要會操作chrome的開發(fā)者工具,即Mac的option+command+i,或者是windows的F12。
首先點擊紅色按鈕,再選取需要定位的具體元素信息,即可獲取到該元素在html頁面中的所有信息。
以登陸按鈕為例,我們發(fā)現(xiàn)其并沒有設置id屬性,但是其onclick觸發(fā)的方法直接表現(xiàn)了出來,我們便可以通過兩種方式觸發(fā)對應的登陸事件。可以根據(jù)class_name,tag_name等來獲取元素并執(zhí)行點擊事件,或者可以直接執(zhí)行l(wèi)ogin()的js從而觸發(fā)登陸事件。
?
selenium提供了一系列的方法通過元素的屬性定位頁面中的具體元素,其屬性包括并不僅限于id、name、class_name、tag_name、xpath、css_elector等,通過WebDriver對象我們可以調用對應的find_element_by方法。例如以下html代碼:
<input type="button">登陸</input>
我們獲取其元素的方法就是find_element_by_id,其他具體的可用方法列表如下:
如果方法名中只是”element”則獲取到的是單個元素對象,而如果是”elements”的話則獲取到的是該種類對象的一個list集合。
對于單個元素對象而言,其所有可執(zhí)行方法或屬性如下:
從列表中我們可以清晰地看見單個元素對象也具有find_element_by的一系列方法,意味著我們可以定位一個父元素,再通過父元素定位其子元素,一層一層定位準確。
常見的html元素包括:輸入框input,按鈕button,復選框checkbox,單選框radio,下拉選擇框select,時間選擇框date,富文本框textarea,文件選擇file以及一些用于顯示文本的標簽包括不僅限于div、span、p等。
輸入框input:
<input type="text" name="last_name">
需要實現(xiàn)對其輸入的功能,可使用如下代碼:
browser.find_element_by_name("last_name").send_keys("測試文本")
按鈕button:
<button onclick="alertDiv('提交成功!')">提交</button>
需要實現(xiàn)對其進行點擊的功能,可使用如下代碼:
browser.find_element_by_id("submit")[1].click()
復選框checkbox:
<input type="checkbox" name="q1" value="0">一
<input type="checkbox" name="q2" value="1">二
<input type="checkbox" name="q3" value="2">三
<input type="checkbox" name="q4" value="3">四
需要實現(xiàn)對其value=0和value=1復選框的選中功能,可使用如下代碼:
browser.find_element_by_name("q1").click()
browser.find_element_by_name("q2").click()
單選框radio:
<input type="radio" name="team" value="0">是 <input type="radio" name="team" value="1">否
需要實現(xiàn)對其value=0,顯示為”是”的單選框的選擇功能,可使用如下代碼:
browser.find_elements_by_name("team")[0].click()
下拉選擇框select:
<select name="gender">
<option value="0">男</option>
<option value="1">女</option>
<option value="2">其他</option>
</select>
需要實現(xiàn)對其下拉選項”男”的選擇功能,可使用如下代碼:
時間選擇框date:
<input type="date" name="birthday">
需要實現(xiàn)對其時間的輸入,可使用如下代碼:
PS:鑒于各種日期控件比較多,個人使用看來直接使用js對其賦值是一種比較方便的方式
富文本框textarea:
<textarea name="textarea"></textarea>
需要實現(xiàn)對其輸入的功能,可使用如下代碼:
browser.find_element_by_name("textarea").send_keys("測試文本")
文件選擇file:
<input type="file" name="file">
需要實現(xiàn)文件的選擇功能,可使用如下代碼:
browser.find_element_by_name("file").send_keys(file_path)
至于其他一些用于顯示文本的標簽,例如:
<span >嬴政</span>
需要實現(xiàn)對其文本內容的獲取,可使用如下代碼:
text = browser.find_element_by_id("name").text
至于元素的點住,松開,拖動等操作將結合在實際案例的代碼中。
?
測試網(wǎng)站可見上面開發(fā)及測試環(huán)境介紹章節(jié)介紹
1.打開對應的測試網(wǎng)站www.uncleyiba.com
option = webdriver.ChromeOptions()
option.add_argument('disable-infobars')
browser = webdriver.Chrome(chrome_options=option)
browser.set_window_size(1500, 1000)
browser.get("http://www.uncleyiba.com")
其中第二行代碼加或者不加的區(qū)別僅僅是打開的瀏覽器會不會顯示如圖所示的信息:
通過這段代碼我們操作成功打開一個1500*1000大小的chrome瀏覽器并打開了http://www.uncleyiba.com這個網(wǎng)站
2.輸入用戶名和密碼,并點擊登陸按鈕
# 填入用戶名和密碼
utils.write_into_input_by_id(browser, "username", "nvshen")
utils.write_into_input_by_id(browser, "password", "nvshen")
# 執(zhí)行登陸js
js_login = "login()"
browser.execute_script(js_login)
這里我們輸入了對應的用戶名和密碼,并且通過執(zhí)行登陸按鈕的js代碼實現(xiàn)登錄,而并不是通過點擊登陸按鈕的方式
其中write_into_input_by_id方法具體代碼如下:
def write_into_input_by_id(browser, ele_id, content):
ele = browser.find_element_by_id(ele_id)
ele.send_keys(content)
找到對應的id的input元素并向其中輸入指定的文字
3.等待三秒鐘網(wǎng)頁跳轉,并確保成功跳轉
if not utils.while_else_sleep(page_check.login_message_show, {“browser”: browser},
login_message_show_return_param):
raise Exception(login_message_show_return_param[“message”])
time.sleep(3)
# 三秒之后會刷新頁面,要確保頁面是否已經刷新成功,否則報錯
login_success_return_param = dict()
if not utils.while_else_sleep(page_check.login_success, {“browser”: browser}, login_success_return_param):
raise Exception(login_message_show_return_param[“message”])
在執(zhí)行頁面跳轉的時候總會因為網(wǎng)絡或其他原因,導致其中的延時時間具有不確定性, 可能你一個請求發(fā)過去是毫秒級響應,也有可能過十幾二十秒都沒有反應, 這時候我們需要一個延時等待的機制來盡可能規(guī)避這種情況, 這里是通過寫了一個簡單的函數(shù)while_else_sleep來監(jiān)控頁面的狀態(tài), 從而實現(xiàn)對頁面的加載等待。
def while_else_sleep(func, param, return_param, false_func=nothing_happened_func, times_begin=0, times_max=20, sleep_time=1): ''' :param func:重復執(zhí)行的方法 :param param:func方法攜帶的參數(shù) :param return_param:func方法返回的參數(shù) :param false_func:如果func返回結果為false,需要執(zhí)行的函數(shù) :param times_begin:開始的次數(shù) :param times_max:最大重復執(zhí)行次數(shù) :param sleep_time:每次等待時間 :return:boolean ''' times = times_begin while True: #print("{0}:{1}[max:{2}]".format(func, times, times_max)) times += 1 if func(param, return_param): break else: time.sleep(sleep_time) false_func(param, return_param) if times >= times_max: return False if return_param.get("status", "") == "over": return False return True
我們通過判定函數(shù)func來判定頁面是否已經到達了我們預料的狀態(tài)。如果沒有,則進行對應的延時等待,并進行重試補救操作false_func。當重試超過一定的次數(shù)times_max,則判定此次操作是超時的,沒有繼續(xù)重試的必要了。當然在確定頁面狀態(tài)的過程中可能會出現(xiàn)一些不再需要重試的情況,比如”密碼輸入錯誤”, 這種情況你再怎么重試密碼也依舊是錯誤的,所以我們會在return_param中加入status判定, 如果碰到類似于這種情況則直接執(zhí)行跳出操作,并判定執(zhí)行失敗。
理解了while_else_sleep函數(shù)再來看這個部分的整體函數(shù),就很容易理解其含義:
確保彈窗是登陸成功狀態(tài),如果是則等待三秒,確認已經登陸成功并跳轉到了預期的頁面。
4.點擊”定時搶課頁面”
# 找到對應的 定時搶課頁面 的a標簽
select_class_a = browser.find_elements_by_tag_name("li")[0].find_element_by_tag_name("a")
select_class_a.click()
# 判定子頁面是否刷新成功
select_class_page_show_return_param = dict()
if not utils.while_else_sleep(page_check.select_class_page_show, {"browser": browser},
select_class_page_show_return_param):
raise Exception(select_class_page_show_return_param["message"])
這里觸發(fā)了一個點擊a標簽的事件,實現(xiàn)iframe的跳轉,并且通過一個while_else_sleep函數(shù)對iframe的頁面跳轉狀態(tài)進行了判定
5.切換到對應的iframe進行搶課
# 切換iframe
browser.switch_to.frame(browser.find_element_by_id("child_frame"))
這里僅僅是一個切換frame的操作,除了同標簽頁面內的frame切換,selenium還可以在同一個瀏覽器窗口的不同標簽之間進行切換
6.根據(jù)當前時間設定課程開搶時間,并將這個時間傳給對應的時間控件
# 設置好開搶時間 如果秒數(shù)小于40 那就當前時間,如果秒數(shù)大于40,則推遲一分鐘
second = int(time.strftime('%S', time.localtime(time.time())))
time_str = time.strftime('%Y-%m-%dT%H:%M', time.localtime(time.time() + 60))
if second >= 40:
time_str = time.strftime('%Y-%m-%dT%H:%M', time.localtime(time.time() + 120))
# 填入日期
utils.write_into_date_by_id(browser, "date", time_str)
這里我們首先獲取了當前時間,并且在當前時間的基礎上對課程開搶時間進行了相應的延長, 這里有一個注意點是我們設定的時間傳參格式是%Y-%m-%dT%H:%M
,原因如圖:
我們在獲取date控件的樣例時間格式的時候獲取到的就是這樣的格式, 因此我們再反過來進行賦值的時候要以同樣的格式構造對應的時間值。不以特定的格式進行賦值則會引發(fā)js的錯誤。
7.點擊”生成搶課列表”
# 點擊 生成搶課列表
js_create_class_list = "create_class_list()"
browser.execute_script(js_create_class_list)
# 判定一下是否出現(xiàn)彈窗表示時間選擇有誤
time_error_div_show_return_param = dict()
if utils.while_else_sleep(page_check.time_error_div_show, {"browser": browser},
time_error_div_show_return_param, times_max=4):
raise Exception(time_error_div_show_return_param["message"])
# 判定table是否已經展示出來
class_table_show_return_param = dict()
if not utils.while_else_sleep(page_check.class_table_show, {"browser": browser}, class_table_show_return_param):
raise Exception(class_table_show_return_param["message"])
這里的點擊操作我依舊是采用的執(zhí)行js的方式,我們可以查看對應的button的代碼:
當然可以通過xpath或tag_name的方式獲取元素再進行點擊,這個因個人的習慣不同選擇的方式也不一樣。
在進行js執(zhí)行/按鈕點擊之后,我增加了一步判定,以免上一步時間設置出錯導致?lián)屨n列表不能成功生成。
而在確定時間沒有出錯之后生成搶課列表也是需要一定時間的(當然我這里是js直接生成的寫死的列表, 實際必然是實時向服務器發(fā)送請求獲取到對應的列表,所以會有一定的請求時間),所以我們進行了延時等待的判定。
8.不停地點擊某個課程的”搶課”按鈕,直到搶課成功
# 選擇我們需要的課程 例如 計算機課
trs = browser.find_element_by_id("class_list").find_element_by_tag_name("tbody").find_elements_by_tag_name("tr")
find_flag = False
for each_tr in trs:
tds = each_tr.find_elements_by_tag_name("td")
if tds[1].text == "計算機課":
# time.sleep(1)
left_time_str = tds[3].text
pat_num = "d+"
result_pat = re.findall(pat_num, left_time_str)
if len(result_pat) > 0:
left_time = int(result_pat[0])
click_button_param = {"browser": browser, "button": tds[2].find_element_by_tag_name("button")}
click_button_return_param = dict()
if not utils.while_else_sleep(page_check.click_button, click_button_param,
click_button_return_param, times_max=(left_time+3)*10,
sleep_time=0.1):
raise Exception(click_button_return_param["message"])
# 判定搶課是否成功(有無彈窗,彈窗內容)
select_fail_message_show_return_param = dict()
if not utils.while_else_sleep(page_check.select_fail_div_show, {"browser": browser},
select_fail_message_show_return_param, times_max=4):
raise Exception(browser.find_element_by_id("class_list").find_element_by_tag_name("tbody").
find_elements_by_tag_name("tr")[0].find_elements_by_tag_name("td")[3].text)
else:
raise Exception(tds[3].text)
find_flag = True
break
這里我們獲取了所有課程的信息,并通過對td內容的判定找到了我們需要的計算機課,進一步找到其搶課按鈕。
通過獲取了剩余時間,計算出假設我們每秒點擊十次的話需要點擊多少次 (超時過多之后的點擊可以有但是沒必要,反正也搶不到了)
全部次數(shù)試完之后再判定一下是否搶課成功,即識別是否有彈窗以及彈窗的內容是什么
除了搶課案例外筆者還提供了另一個可供測試的表單提交樣例, 其中包括了更多的元素操作:input填寫,select選擇,date填寫,radio選擇,checkout選擇,file選取, textarea填寫,元素拖拽,按鈕點擊這些事件。
表單提交頁面的進入和選課類似,這里不做重復介紹。大多數(shù)元素的操作在之前的章節(jié)中也有介紹,方法大同小異參考一下源碼即可理解。
這里重點提出來的則是元素拖拽的演示。
在表單提交這個案例中筆者增加了一個類似于驗證的機制,需要將黑色小方塊移動至幾乎與紅色小方塊重合的地步,才可以進行最終的提交。
其中小方塊這一段的html代碼是這樣的:
<td colspan="2" >
<div style="left: 44.6836px; top: 24.9741px;"></div>
<div style="left: 342px; top: 593px;"></div>
</td>
css:
#div1{
width: 30px;
height: 30px;
background-color: black;
position: absolute;
}
#div2{
width: 30px;
height: 30px;
background-color: red;
position: relative;
}
兩個小方塊都是30*30大小,其中紅色方塊是可不操作的,其位置在這個td內部隨機。黑色方塊有初始位置,可以進行拖拽移動。
其實現(xiàn)代碼如下:
# 拖動驗證
# 1.分別得到兩個div的left和top
div1 = browser.find_element_by_id("div1")
div2 = browser.find_element_by_id("div2")
left_div1 = div1.location.get("x")
top_div1 = div1.location.get("y")
left_div2 = div2.location.get("x")
top_div2 = div2.location.get("y")
# 2.設置好ActionChains對象用于進行鍵鼠操作
actions = ActionChains(browser)
actions.click_and_hold(div1) # a.按住div1
actions.move_by_offset(left_div2 - left_div1, top_div2 - top_div1) # b.橫縱坐標移動(相對坐標)
actions.release() # c.釋放鼠標
actions.perform() # d.執(zhí)行動作流
ActionChains類可以實現(xiàn)對一組”動作”的執(zhí)行,它有如下的”動作”可以被執(zhí)行:
包括不僅限于單機,雙擊,按下,松開,移動等。
這里我們通過計算了兩個方塊的相對位置,點擊并按住小黑方塊(div1), 并將其移動相應的相對距離,再釋放鼠標這樣的操作,來實現(xiàn)”讓小黑方塊覆蓋小紅方塊”的驗證操作。
其中browser為瀏覽器對象
在服務器執(zhí)行selenium腳本的時候我們無法直觀地看到當時瀏覽器執(zhí)行的情況, 因此需要對代碼執(zhí)行異常的地方進行捕獲,通過截圖的方式來人為分析可能出現(xiàn)的錯誤。
?
browser.get_screenshot_as_file(screenshot_path)
screenshot_path:截圖圖片存儲路勁
?
這一步實際上是基于上一個”頁面截圖”進一步對圖片進行處理,這主要用于驗證碼的獲取, 大多數(shù)網(wǎng)站的驗證碼并不是一個真實存在的圖片文件,而是一個實時生成的臨時圖片文件。因此我們需要通過截圖的方式來獲取這樣的驗證碼并且利用OCR進行進一步的識別。
#得到驗證碼在屏幕中的坐標位置
left, top, right, bottom = get_elementid_location(browser, "checkCodeImage")
# 瀏覽器頁面截圖并存儲
screenshot_path = os.path.join(conf.data_path, picuniqid + "_screenshot" + ".png")
browser.get_screenshot_as_file(screenshot_path)
# 存儲驗證碼圖
captcha_path = os.path.join(conf.data_path, picuniqid + "_captcha" + ".png")
im = Image.open(screenshot_path)
im = im.crop((left, top, right, bottom))
im.save(captcha_path)
其中get_elementid_location方法是根據(jù)元素的location和size方法獲取其在屏幕中的坐標
這其中有一個值得關注的問題是retina屏幕的問題
所謂“Retina”是一種顯示標準,是把更多的像素點壓縮至一塊屏幕里,從而達到更高的分辨率并提高屏幕顯示的細膩程度。
由摩托羅拉公司研發(fā)。最初該技術是用于Moto Aura上。這種分辨率在正常觀看距離下足以使人肉眼無法分辨其中的單獨像素。也被稱為視網(wǎng)膜顯示屏。
以MacBook Pro with Retina Display為例,工作時顯卡渲染出2880x1800個像素,其中每四個像素一組,輸出原來屏幕的一個像素顯示的大小區(qū)域內的圖像。
這樣一來,用戶所看到的圖標與文字的大小與原來的1440x900分辨率顯示屏相同,但精細度是原來的4倍,但對于特殊元素,如視頻與圖像,則以一個圖片像素對應一個屏幕像素的方式顯示。
故不會產生Windows中分辨率提升使屏幕文字與圖像變小,造成閱讀困難的問題。這樣在設計軟件時只需將所有的UI元素的精細度都提高到原來的4倍就可以既保持了觀看舒適度,又提高了顯示效果。關于iOS設備,也由四個像素代替原來一個像素,通過下圖對比就可以較明顯地觀察到這種關系。
劃重點每四個像素一組
所以如果selenium是在mac的主屏或者說是其他retina屏幕上工作的時候我們需要將其獲得的元素坐標乘上2才是其真實的坐標:
if is_retina_display(browser):
left = int(captcha_location['x'] )*2
top = int(captcha_location['y'] )*2
right = int(captcha_location['x'] +captcha_size['width'] )*2
bottom = int(captcha_location['y'] + captcha_size['height'] )*2
else:
left = int(captcha_location['x'])
top = int(captcha_location['y'])
right = int(captcha_location['x'] + captcha_size['width'])
bottom = int(captcha_location['y'] + captcha_size['height'])
得到了屏幕截圖和元素位置,通過Image類的操作即可以準確獲得想要截圖的元素的位置
這個也是配合截圖使用的,因為截圖僅僅是截取當前的屏幕,如果頁面可以向下滾動或者向上滾動,則被隱藏的部分無法被截圖獲得
js_scroll='''$(document).scrollTop({0})'''.format(scroll_num)
browser.execute_script(js_scroll)
其中scroll_num
即滾動條的位置,0則代表是在最上方
1.獲取元素是否顯示、是否可被操作、是否可進行選擇
2.獲取元素的標簽屬性,例如獲取其name屬性
name = ele.get_attribute("name")
ele為元素對象
3.獲取元素的css屬性,例如獲取其color屬性
color = ele.value_of_css_property("color") ele為元素對象
4.清除元素的值
ele.clear()
ele為元素對象
北京時間凌晨五點,我完成了對docker鏡像的最終測試,并臨時借用了朋友的高寬帶服務器部署了自己的服務。
北京時間下午一點零一分,成功搶到了課程。
就像花瓶碎了一樣,感覺一切頓時有點索然無味。
當然,以上都是假的。
但那些真的,也不知不覺就這樣過去了很多年,卻又像就發(fā)生在昨天。
而今天,我在達觀數(shù)據(jù),它就像初生的太陽,你又在哪里?
?
BOUT
關于作者
景?。?/span>達觀數(shù)據(jù)后端開發(fā)工程師,負責達觀數(shù)據(jù)產品后端開發(fā)、產品落地、客戶定制化產品需求等設計。愛好數(shù)學,喜歡用代碼解決生活中的實際問題。