摘要
很久之前就想著要寫個(gè)腳本,要么去刷12306的票般贼,要么就登QQ空間愧哟。為什么呢奥吩?你想啊,別人剛發(fā)一個(gè)說說蕊梧,然后你就能檢測(cè)到并秒贊回去霞赫,這得多讓人驚訝。(不小心暴露了異想天開的本質(zhì)啦肥矢,⊙﹏⊙b汗)端衰。
一開始學(xué)習(xí)Python的時(shí)候就模擬著試了試,除非借助于cookie那塊甘改,不然也是沒法成功的旅东。然而這次歪打正著。本學(xué)期有個(gè)《軟件工程導(dǎo)論》課程十艾,剛好講到了測(cè)試這塊抵代,然后就提到了自動(dòng)化測(cè)試,以及在此行業(yè)中的翹楚Selenium忘嫉,結(jié)果就是發(fā)現(xiàn)了新大陸一般荤牍,覺得拿來測(cè)試模擬登陸應(yīng)該會(huì)比較不錯(cuò)。
于是庆冕,真的成功啦康吵。在此記錄一下,走過的歷程愧杯,填過的坑涎才。
環(huán)境搭建
Selenium是一個(gè)支持多語言的自動(dòng)化測(cè)試框架鞋既,不管是Java力九, Ruby,還是Python邑闺,都能使用其支持的庫來進(jìn)行自動(dòng)化測(cè)試跌前。我本人最喜歡Python語言,所以這里將會(huì)以Python語言進(jìn)行測(cè)試陡舅。
驅(qū)動(dòng)
Selenium是典型的CS框架抵乓,瀏覽器作為Server執(zhí)行Client(selenium代碼)的請(qǐng)求,通過“代理”這么個(gè)理念實(shí)現(xiàn)自動(dòng)化測(cè)試靶衍。 這么說可能不太通俗灾炭,換句話就是selenium執(zhí)行的時(shí)候會(huì)調(diào)用瀏覽器,根據(jù)設(shè)置好的代碼運(yùn)行颅眶,最終實(shí)現(xiàn)自動(dòng)化測(cè)試蜈出。
selenium2之后,以webdriver代替Proxy功能涛酗,處理所有請(qǐng)求铡原。
所以不管怎么說偷厦,瀏覽器都是必不可少的啦。因此我們需要安裝一下瀏覽器驅(qū)動(dòng)燕刻。
關(guān)于瀏覽器驅(qū)動(dòng)的問題只泼,可能就是阻擋了大部分人使用selenium的攔路虎吧。
下載
下載驅(qū)動(dòng)的話卵洗,可以到 http://www.seleniumhq.org/projects/webdriver/
這個(gè)網(wǎng)址進(jìn)行下載请唱。按需下載即可,待會(huì)會(huì)講解怎么使用过蹂,我這里下載的是firefoxdriver.exe
selenium
安裝selenium也是很方便的籍滴。
如果您已安裝比較舊的版本:
pip install -U selenium
如果您還未安裝selenium:
pip install selenium
這樣就完事了。
驅(qū)動(dòng)安裝問題集
下面聊聊我在這個(gè)過程中遇到的一些奇怪的問題榴啸,可能不具備普適性孽惰。
未發(fā)現(xiàn)驅(qū)動(dòng)
如果驅(qū)動(dòng)沒有正確放置,就會(huì)報(bào)出下面的錯(cuò)誤鸥印。
解決辦法就是將剛才下載的driver放置到Python的Path或者放到任意一個(gè)系統(tǒng)能找得到的Path中勋功。我個(gè)人建議放置到Python的根目錄中,這樣便于管理库说。
firefox驅(qū)動(dòng)錯(cuò)誤
主要癥狀就是無法開啟狂鞋,閃退。這個(gè)時(shí)候我們需要下載一個(gè)geckodriver.exe潜的。
可以在下面的鏈接中找到適合自己系統(tǒng)版本的來使用骚揍。
https://github.com/mozilla/geckodriver/releases
下載完之后放置到Python路徑中即可,處理方法和剛才的那個(gè)一樣啰挪。然后問題就解決了(反正我是這么解決的啦)信不。
模擬登陸
下面開始步入正題了,使用selenium進(jìn)行模擬登陸其實(shí)就可以想象成有一雙無形的手在進(jìn)行用戶名亡呵,密碼填寫抽活,然后點(diǎn)擊按鈕等等。這樣就會(huì)變得很容易理解了锰什。
這里關(guān)于selenium選擇器等等的基礎(chǔ)性的知識(shí)點(diǎn)就不再講解了下硕,網(wǎng)上資料很多,也很詳細(xì)汁胆。相信大家一看就會(huì)明白的梭姓。
我自己最常用也最喜歡的就是:
driver.get_element_by_id()
driver.get_element_by_xpath()
然后要登錄QQ空間,就得先看看人家長(zhǎng)什么樣吧嫩码,如圖:
首敗
按下F12就可以查看網(wǎng)頁的源代碼了誉尖,所以什么用戶名啊,密碼啊谢谦,登陸按鈕啊都不是事了释牺。不多說萝衩,直接上代碼。
#coding: utf8
from selenium import webdriver
driver = webdriver.Firefox()
driver.get('http://i.qq.com/')
driver.find_element_by_id('switcher_plogin').click()
driver.find_element_by_name('u').clear()
driver.find_element_by_name('u').send_keys('你的QQ號(hào)')
driver.find_element_by_name('p').clear()
driver.find_element_by_name('p').send_keys('你的密碼')
driver.find_element_by_xpath('//*[@id="loginform"]/div[4]/a').click()
driver.find_element_by_id('login_button').click()
print driver.current_url
然而我發(fā)現(xiàn)我想多了没咙,真正的考驗(yàn)才剛剛開始猩谊。這樣根本就找不到網(wǎng)頁源代碼中看到的那些個(gè)id啊class什么的。
再敗
既然找不到祭刚,可能就是代碼的問題了牌捷。然后我又仔仔細(xì)細(xì)的查看了一下代碼,發(fā)現(xiàn)也沒啥錯(cuò)誤啊涡驮。然后不甘心暗甥,又去看了看網(wǎng)頁的源代碼。結(jié)果還真的被我發(fā)現(xiàn)了捉捅。
尼瑪撤防,這叫什么事嘛。
如下圖棒口,不難發(fā)現(xiàn)了吧寄月。
有一個(gè)iframe,怪不得Selenium找不到无牵,既然如此漾肮,那咱們就乘勝追擊。修改一下代碼唄茎毁。
#coding: utf8
from selenium import webdriver
driver = webdriver.Firefox()
driver.get('http://i.qq.com/')
driver.switch_to.frame('login_frame')
driver.find_element_by_id('switcher_plogin').click()
driver.find_element_by_name('u').clear()
driver.find_element_by_name('u').send_keys('你的QQ號(hào)')
driver.find_element_by_name('p').clear()
driver.find_element_by_name('p').send_keys('你的密碼')
driver.find_element_by_xpath('//*[@id="loginform"]/div[4]/a').click()
driver.find_element_by_id('login_button').click()
print driver.current_url
加上了這么一行:
driver.switch_to.frame('login_frame')
作用就是根據(jù)iframe的id或name來跳轉(zhuǎn)到這個(gè)iframe上克懊。
本以為完事大吉咯,終于可以秒贊了七蜘,耶谭溉。
然而事實(shí)給了我一個(gè)殘酷的打擊。到最后一個(gè)“登錄”按鈕點(diǎn)擊的時(shí)候停了下來崔梗。結(jié)果還是失敗了夜只。
成功
它越是這樣垒在,我就越想寫出來蒜魄。沒辦法,硬著頭皮上唄场躯,直覺上還是QQ空間源代碼的問題谈为,于是這次就直接繼續(xù)看源代碼去了。
果不其然踢关,發(fā)現(xiàn)了下圖這么個(gè)代碼伞鲫。
然后我就想使用JS來把這個(gè)故意隱藏不讓focus的給顯現(xiàn)出來。
恩签舞,我就是這么做的秕脓,然后真的就成功了柒瓣。核心就添加了下面的這行代碼。
driver.execute_script("document.getElementById('login_button').parentNode.hidefocus=false;")
下面貼出來完整的代碼吧吠架,方便參考芙贫。
#coding: utf8
from selenium import webdriver
driver = webdriver.Firefox()
driver.get('http://i.qq.com/')
driver.switch_to.frame('login_frame')
driver.find_element_by_id('switcher_plogin').click()
driver.find_element_by_name('u').clear()
driver.find_element_by_name('u').send_keys('你的QQ號(hào)')
driver.find_element_by_name('p').clear()
driver.find_element_by_name('p').send_keys('你的密碼')
driver.execute_script("document.getElementById('login_button').parentNode.hidefocus=false;")
driver.find_element_by_xpath('//*[@id="loginform"]/div[4]/a').click()
driver.find_element_by_id('login_button').click()
print driver.current_url
演示
下面使用一個(gè)gif圖來演示一下模擬登陸的效果,方便流暢性的觀看傍药,也更具說服力磺平。
總結(jié)
到此基本上已經(jīng)可以拿來使用了。無非在登陸成功的界面下使用Selenium模擬進(jìn)行一些點(diǎn)擊操作拐辽。如果想發(fā)點(diǎn)文字的話也是很方便的拣挪,send_keys可以很好的解決這個(gè)問題。什么秒贊俱诸,秒答都不是什么事了菠劝。
但是需要注意的是,QQ空間對(duì)登陸頻率是做了限制的睁搭,就算是手動(dòng)登陸闸英,連續(xù)幾次之后就會(huì)讓我們輸入驗(yàn)證碼。這也是一種安全機(jī)制罷了介袜。
如果有需要的話甫何,Python處理驗(yàn)證碼的模塊也是非常好用的。這里就不再介紹了遇伞。
最后辙喂,Selenium給我的感悟就是:我自己對(duì)Selenium有點(diǎn)大材小用了,這樣一款優(yōu)秀的測(cè)試框架鸠珠,卻拿來做這種小玩意巍耗,確實(shí)是有點(diǎn)說不過去。
另外我也認(rèn)識(shí)到了渐排,測(cè)試的目的是為了提供更好的服務(wù)炬太。而不是拿來當(dāng)做攻擊的手段。惡意的發(fā)水機(jī)驯耻,這種行為極不負(fù)責(zé)任亲族,希望我們都能謹(jǐn)言慎行,共同營(yíng)造一個(gè)和諧的網(wǎng)絡(luò)家園可缚。
心正了霎迫,人才會(huì)正直。感謝Selenium給我的這個(gè)啟迪帘靡。