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