盧守東 盧明俊
摘要:網(wǎng)絡(luò)爬蟲的應(yīng)用十分廣泛,其所要完成的任務(wù)與所要處理的網(wǎng)站往往差異巨大。針對(duì)某些網(wǎng)絡(luò)爬蟲所需要的自動(dòng)登錄功能,介紹一種基于Selenium的解決方案,并通過具體的實(shí)例說明有關(guān)的編程技術(shù)。
關(guān)鍵詞:網(wǎng)絡(luò)爬蟲;自動(dòng)登錄;Selenium;Python
中圖分類號(hào):TP311? ? ? 文獻(xiàn)標(biāo)識(shí)碼:A
文章編號(hào):1009-3044(2023)34-0048-04
開放科學(xué)(資源服務(wù))標(biāo)識(shí)碼(OSID)
0 引言
目前,網(wǎng)絡(luò)爬蟲方興未艾,其主要用途就是按照一定的規(guī)則從萬維網(wǎng)中自動(dòng)地抓取所需要的有關(guān)數(shù)據(jù)或信息[1]。然后,有些網(wǎng)站出于安全方面或其他因素的考慮,要求登錄成功后方可執(zhí)行相應(yīng)的功能或訪問相應(yīng)的頁(yè)面。顯然,對(duì)于此類網(wǎng)站,作為網(wǎng)絡(luò)爬蟲,就必須具備相應(yīng)的自動(dòng)登錄功能。在此,將以Windows為系統(tǒng)平臺(tái),以Python為編程語(yǔ)言,介紹基于Selenium的網(wǎng)站自動(dòng)登錄技術(shù),供大家參考。
1 Selenium簡(jiǎn)介
Selenium是一個(gè)完全開源的Web自動(dòng)化工具,主要用于Web應(yīng)用程序的自動(dòng)化測(cè)試[2]。Selenium測(cè)試直接運(yùn)行在瀏覽器中,可完全模擬用戶的實(shí)際操作。與其他測(cè)試工具相比,Selenium具有優(yōu)異的跨平臺(tái)性與兼容性,可運(yùn)行于Windows、Linux、Macintosh等系統(tǒng)平臺(tái),并支持IE、Chrome、Firefox、Safari、Opera、Edge等瀏覽器。
在Python中,可借助Selenium庫(kù)與相應(yīng)的瀏覽器驅(qū)動(dòng),模擬用戶在瀏覽器中的操作,從而實(shí)現(xiàn)自動(dòng)登錄功能。在此基礎(chǔ)上,可進(jìn)一步獲取有關(guān)網(wǎng)頁(yè)的源代碼,并實(shí)現(xiàn)網(wǎng)絡(luò)爬蟲的具體功能。
2 關(guān)鍵技術(shù)
2.1 Selenium與瀏覽器驅(qū)動(dòng)的安裝
在Python中,Selenium是一個(gè)第三方庫(kù),必須另行安裝,方法之一就是執(zhí)行命令“pip install selenium -i https://pypi.tuna.tsinghua.edu.cn/simple”[3]。作為應(yīng)用實(shí)例的開發(fā)環(huán)境,在此為Python 3.8.18安裝了Selenium 4.13.0。
Selenium庫(kù)安裝成功后,還要安裝相應(yīng)的瀏覽器驅(qū)動(dòng)。各瀏覽器的驅(qū)動(dòng)是互不相同的,須從各自的地址分別下載。以Chrome瀏覽器為例,可從地址“https://chromedriver.storage.googleapis.com/index.html”下載與其版本相對(duì)應(yīng)的驅(qū)動(dòng)chromedriver.exe,然后并將其復(fù)制到Python的安裝目錄中[4]。
2.2 瀏覽器的啟動(dòng)與網(wǎng)頁(yè)的訪問
先從Selenium庫(kù)導(dǎo)入webdriver模塊,再調(diào)用該模塊的Chrome()函數(shù)即可啟動(dòng)Chrome瀏覽器,并返回相應(yīng)的瀏覽器對(duì)象。接著,通過瀏覽器對(duì)象調(diào)用get()方法,即可根據(jù)指定的網(wǎng)址訪問相應(yīng)的網(wǎng)頁(yè)。為獲取當(dāng)前頁(yè)面的源代碼,可訪問瀏覽器對(duì)象的page_source屬性。若調(diào)用瀏覽器對(duì)象的refresh()或save_screenshot()方法,可刷新當(dāng)前頁(yè)面或?yàn)楫?dāng)前頁(yè)面拍照(保存為指定的.png圖片)。若調(diào)用瀏覽器對(duì)象的maximize_window()或minimize_window()方法,可最大化或最小化瀏覽器窗口。若調(diào)用瀏覽器對(duì)象的close()或quit()方法,則可關(guān)閉當(dāng)前頁(yè)面或退出瀏覽器。例如:
from selenium import webdriver
browser=webdriver.Chrome()? #啟動(dòng)Chrome瀏覽器
browser.maximize_window()? #最大化瀏覽器窗口
browser.get('https://www.cctv.com')? #訪問央視網(wǎng)主頁(yè)
browser.save_screenshot('cctv.png')? #為頁(yè)面拍照
print(browser.page_source)? #打印頁(yè)面源代碼
browser.quit()? #退出瀏覽器
2.3 頁(yè)面元素的查找與獲取
在selenium.webdriver.common.by模塊的支持下,通過調(diào)用瀏覽器對(duì)象的find_element()或find_elements()方法,可根據(jù)元素的ID、Name、CSS類名、Xpath路徑、標(biāo)簽名、鏈接文本等在頁(yè)面中查找元素,并返回相應(yīng)的元素對(duì)象或元素對(duì)象列表。
2.4 頁(yè)面元素的交互操作
對(duì)于所獲取到的頁(yè)面元素對(duì)象,可進(jìn)一步調(diào)用其交互方法,執(zhí)行相應(yīng)的交互操作。例如,對(duì)于文本框?qū)ο?,可調(diào)用send_keys()方法模擬從鍵盤向其輸入指定的內(nèi)容,或在elenium.webdriver.common.keys模塊的支持下模擬輸入指定的鍵盤按鍵;對(duì)于按鈕、超鏈接等對(duì)象,可調(diào)用click()方法模擬在其上的執(zhí)行單擊操作。
例如,若頁(yè)面的表單中有一個(gè)文本框與一個(gè)提交按鈕,其id分別為cxtj與ok,為自動(dòng)在文件框中輸入selenium并單擊提交按鈕,則關(guān)鍵代碼如下:
from selenium import webdriver
from selenium.webdriver.common.by import By
browser=webdriver.Chrome()
……
cxtj=browser.find_element(By.ID,'cxtj')
cxtj.send_keys('selenium')
ok=browser.find_element(By.ID,'ok')
ok.click()
……
2.5 等待的設(shè)置
頁(yè)面中某些元素的加載可能需要較長(zhǎng)的時(shí)間,因此適當(dāng)?shù)牡却袝r(shí)候是必要的。Selenium支持兩種等待方式,即隱式等待與顯式等待[5]。隱式等待可設(shè)定一個(gè)最長(zhǎng)的等待時(shí)間,在此時(shí)間內(nèi),會(huì)以輪詢的方式不斷地查找指定的元素,直至找到為止。若超過設(shè)定的等待時(shí)間依然未能找到指定的元素,則會(huì)拋出NoSuchElementException異常。顯式等待同樣可以設(shè)定一個(gè)最長(zhǎng)的等待時(shí)間,但同時(shí)要指定相應(yīng)的檢測(cè)條件(如指定元素是否出現(xiàn)或可見等)。在此時(shí)間內(nèi),會(huì)以一定的時(shí)間間隔進(jìn)行檢測(cè),直至符合條件為止。若超過設(shè)定的等待時(shí)間依然未能滿足指定的條件,則會(huì)拋出TimeoutException異常。
隱式等待是全局性的,且用法較為簡(jiǎn)單,只需調(diào)用瀏覽器對(duì)象的implicitly_wait()方法直接設(shè)置等待時(shí)間(以秒為單位)即可。顯式等待則較為靈活,但用法較為復(fù)雜,須先調(diào)用selenium.webdriver.support.ui模塊的WebDriverWait()函數(shù)根據(jù)指定的瀏覽器對(duì)象與等待時(shí)間(以秒為單位)等參數(shù)創(chuàng)建一個(gè)等待對(duì)象,然后再調(diào)用等待對(duì)象的until()或 until_not()方法設(shè)置相應(yīng)檢測(cè)條件。至于具體的檢測(cè)條件,可通過調(diào)用selenium.webdriver.support.expected_conditions模塊的有關(guān)函數(shù)加以指定。例如,調(diào)用presence_of_element_located()函數(shù)可判斷指定的元素是否已加載到頁(yè)面的DOM樹中,而調(diào)用element_to_be_clickable()函數(shù)則可判斷指定的元素是否可點(diǎn)擊。
例如,為確保id為cxtj元素已被成功加載,可采用顯式等待,關(guān)鍵代碼如下(最長(zhǎng)等待時(shí)間為10秒):
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_ conditions as EC
browser=webdriver.Chrome()
……
wait=WebDriverWait(browser,10)
wait.until(EC.presence_of_element_located((By.ID,'cxtj')))
……
2.6 框架的切換
有些頁(yè)面中會(huì)包含有一些框架(Frame/IFrame) ,從而嵌入了另外的頁(yè)面。由于Selenium每次只能操作一個(gè)頁(yè)面中的元素,因此要訪問框架中嵌入頁(yè)面的元素,就必須先切換至相應(yīng)的框架。為此,只需調(diào)用瀏覽器對(duì)象switch_to屬性的frame()方法即可。例如,為切換至name屬性值為login的iframe框架,代碼如下:
login=browser.find_element(By.NAME,'login')
browser.switch_to.frame(login)
切換至框架后,便無法繼續(xù)操作主文檔中的元素。此時(shí),若要返回到主文檔,可調(diào)用瀏覽器對(duì)象switch_to屬性的default_content()方法。
2.7 Cookies的處理
Selenium為Cookies的處理提供了全面的支持,通過調(diào)用瀏覽器對(duì)象的add_cookie()方法,即可根據(jù)名稱與值添加指定的Cookie。此外,調(diào)用get_cookie()或delete_cookie()方法可根據(jù)名稱獲取或刪除指定的Cookie,調(diào)用get_cookies()或delete_all_cookies()方法可獲取或刪除所有的Cookie。例如:
browser.add_cookie({'name':'username','value':'admin'})
browser.add_cookie({'name':'password','value':'12345'})
在此,添加了兩個(gè)Cookie,其名稱分別為username與password,值則分別為admin與12345。
3 應(yīng)用實(shí)例
3.1 自動(dòng)登錄豆瓣網(wǎng)站并進(jìn)行查詢
豆瓣網(wǎng)站的網(wǎng)址為https://www.douban.com。在瀏覽器中打開豆瓣網(wǎng)站的主頁(yè),并借助開發(fā)者工具進(jìn)行分析,可知其中的登錄界面(如圖1所示)其實(shí)是嵌入到Iframe框架的一個(gè)頁(yè)面,相應(yīng)的Iframe元素為:
<iframe style="height: 300px; width: 300px;" frameborder="0" src="http://accounts.douban.com/passport/login_ popup?login_source=anony"></iframe>
其Xpath路徑為“//*[@id="anony-reg-new"]/div/div[1]/iframe”。
登錄界面中有“短信登錄/注冊(cè)”與“密碼登錄”兩個(gè)標(biāo)簽,后者所對(duì)應(yīng)的元素為:
<li class="account-tab-account on">密碼登錄</li>
其Xpath路徑為“/html/body/div[1]/div[1]/ul[1]/li[2]”。
在“密碼登錄”界面中,“手機(jī)號(hào)/郵箱”與“密碼”元素的id分別為username與password,而“登錄豆瓣”按鈕所對(duì)應(yīng)的元素為:
<a class="btn btn-account ">登錄豆瓣</a>
其Xpath路徑為“/html/body/div[1]/div[2]/div[1]/div[5]/a”。
在登錄成功后所打開的主頁(yè)面中(如圖2所示),“搜索你感興趣的內(nèi)容和人...”文本框的name為q,而“搜索”按鈕所對(duì)應(yīng)的元素為:
<input type="submit" value="搜索">
其Xpath路徑為“//*[@id="db-nav-sns"]/div/div/div[2]/form/fieldset/div[2]/input”。
根據(jù)以上分析結(jié)果,即可編程實(shí)現(xiàn)豆瓣網(wǎng)站的自動(dòng)登錄與信息查詢(在此查詢關(guān)鍵字“開國(guó)大典”) ,代碼如下:
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
import time
browser=webdriver.Chrome()
browser.maximize_window()
try:
browser.get('https://www.douban.com')
iframe=browser.find_element(By.XPATH,'//*[@id="anony-reg-new"]/div/div[1]/iframe')
browser.switch_to.frame(iframe)
li=browser.find_element(By.XPATH,'/html/body/div[1]/div[1]/ul[1]/li[2]')
li.click()
username=browser.find_element(By.ID,'username')
username.send_keys('180...')? #在此應(yīng)指定真正的用戶名(手機(jī)號(hào)或郵箱)
password=browser.find_element(By.ID,'password')
password.send_keys('pw...')? #在此應(yīng)指定真正的密碼
button=browser.find_element(By.XPATH,'/html/body/div[1]/div[2]/div[1]/div[5]/a')
button.click()
time.sleep(10)
wait=WebDriverWait(browser,30)
wait.until(EC.presence_of_element_located((By.NAME,'q')))
q=browser.find_element(By.NAME,'q')
q.send_keys('開國(guó)大典')
s=browser.find_element(By.XPATH,'//*[@id="db-nav-sns"]/div/div/div[2]/form/fieldset/div[2]/input')
s.click()
time.sleep(5)
browser.save_screenshot('douban.png')
finally:
browser.quit()
運(yùn)行程序后所生成的圖片如圖3所示。在右上角,可看到登錄用戶的昵稱,說明已成功登錄豆瓣網(wǎng)站。
3.2 自動(dòng)登錄百度賬戶并進(jìn)行查詢
百度的網(wǎng)址為https://www.baidu.com。在瀏覽器中打開百度主頁(yè),并成功登錄百度賬戶,然后借助開發(fā)者工具進(jìn)行查看與分析,找到BAIDUID與BDUSS這兩個(gè)Cookie并記錄其值。同時(shí),通過元素的檢查功能,獲知“關(guān)鍵詞”文本框與“百度一下”按鈕所對(duì)應(yīng)元素的id,分別為kw與su。
根據(jù)以上分析結(jié)果,即可編程實(shí)現(xiàn)百度賬戶的自動(dòng)登錄(基于Cookie) 與信息查詢(在此查詢關(guān)鍵字“開國(guó)大典”) ,代碼如下:
from selenium import webdriver
from selenium.webdriver.common.by import By
import time
browser=webdriver.Chrome()
browser.maximize_window()
browser.get("https://www.baidu.com")
time.sleep(5)
browser.add_cookie({'name':'BAIDUID','value':'DF...'})? #在此應(yīng)指定真正的BAIDUID值
browser.add_cookie({'name':'BDUSS','value':'5W...'})? #在此應(yīng)指定真正的BDUSS值
browser.refresh()
time.sleep(5)
keyword=browser.find_element(By.ID,'kw')
keyword.send_keys('開國(guó)大典')
button=browser.find_element(By.ID,'su')
button.click()
time.sleep(5)
browser.save_screenshot('baidu.png')
browser.quit()
運(yùn)行程序后所生成的圖片如圖4所示。在右上角,可看到登錄用戶的名稱,說明已成功登錄百度賬戶。
4 結(jié)束語(yǔ)
網(wǎng)絡(luò)爬蟲的應(yīng)用十分廣泛,其所要完成的任務(wù)與所要處理的網(wǎng)站各有不同,具體的實(shí)現(xiàn)技術(shù)也各種各樣。實(shí)際的應(yīng)用表明,如果網(wǎng)絡(luò)爬蟲需要實(shí)現(xiàn)網(wǎng)站的自動(dòng)登錄功能,那么基于Selenium的解決方案無疑是頗為靈活、行之有效的。
參考文獻(xiàn):
[1] 網(wǎng)絡(luò)爬蟲_百度百科[EB/OL].[2022-10-20].https://baike.baidu.com/item/%E7%BD%91%E7%BB%9C%E7%88%AC%E8%99%AB/5162711?fr=ge_ala.
[2] Selenium(WEB自動(dòng)化工具)_百度百科[EB/OL].[2022-10-18].https://baike.baidu.com/item/Selenium/18266?fr=ge_ala.
[3] 鄧勁生,莊春華.實(shí)戰(zhàn)深度學(xué)習(xí):原理、框架及應(yīng)用[M].北京:清華大學(xué)出版社,2021.
[4] 夏敏捷.Python爬蟲超詳細(xì)實(shí)戰(zhàn)攻略[M].北京:清華大學(xué)出版社,2021.
[5] Selenium詳細(xì)介紹[EB/OL].[2022-10-18].https://blog.csdn.net/weixin_44030265/article/details/127439655#t1.
【通聯(lián)編輯:謝媛媛】