在上一篇筆記《Ajax數據爬取簡介》中我們提到,在爬取動態渲染頁面的數據時(通常為Ajax),我們可以使用AJAX URL分析法和Selenium模擬瀏覽器行為兩種方法,其中前者已經分析一般思維已敘述,在本節中我們主要介紹如何使用Selenium模擬瀏覽器行為來獲取數據。
一、准備工作
在正式介紹使用之前,我們需要先安裝selenium庫,安裝庫的過程和之前一樣,我們可以直接使用命令’pip install selenium’。安裝完成后我們還需要配置好用於驅動瀏覽器行為的驅動器driver,每一個瀏覽器對應的driver都是不同的,具體可以參看下表:
下載完對應版本的XXXdriver.exe文件后,將其放入我們python安裝路徑的scripts目錄下即可,以供全局使用。例如,以Chrome為例,我的chromedriver.exe便可放在’C:\Users\UnikFox\AppData\Local\Programs\Python\Python36\Scripts’。
此外,這里要留意的是,每個瀏覽器版本的driver也是不同的,在下載頁可以看到各driver所支持的瀏覽器版本。
二、基本使用
1.啟動瀏覽器並訪問頁面
模擬瀏覽器的啟動只需要實例化selenium的webdriver模塊中相應的對象即可,然后通過這個對象的get(url)方法便可請求URL映射的頁面,之后我們就可以通過訪問這一個對象的屬性來獲取相應的頁面數據信息。這里我們仍以Chrome為例,運行后我們便可發現其自動地打開了一個Chrome瀏覽器,並在頂部顯示“Chrome正受到自動測試軟件地字樣”,說明我們使用selenium成功地打開了瀏覽器,同時我們還會發現也已經進入了我們所請求的頁面。
## 模擬啟動瀏覽器 # 導入webdriver模塊 from selenium import webdriver # 實例化webdriver對象 browser = webdriver.Chrome() # 請求頁面 browser.get('https://www.baidu.com') # 獲取網頁源代碼 html_text = browser.page_source
2.關閉頁面
在我們模擬完成后,可以使用browser對象的close()和quit()方法關閉頁面,其主要區別是前者為關閉當前頁面,而后者為退出整個瀏覽器。
# 關閉當前頁面 browser.close() # 退出整個瀏覽器 browser.quit()
3.解析元素
在我們獲取到頁面的HTML源文本后,如要對其進行解析,實際上我們可以使用之前介紹的lxml和beautifulsoup兩種解析方法,不過這里我們主要來說明一下使用selenium的解析策略。
在selenium中,我們解析元素都是通過browser來實現的,解析的方法可以是通過元素id、元素名name、類名class_name、CSS選擇器或者xpath語法,在實際中具體使用時我們只需要調用browser的相關方法即可。
例如,如果我們要解析百度中的輸入框input元素,則可以使用如下的解析方法:
HTML源文本:
<span class="bg s_ipt_wr quickdelete-wrap">
<span class="soutu-btn"></span>
<input id="kw" name="wd" class="s_ipt" value="" maxlength="255" autocomplete="off">
<a href="javascript:;" id="quickdelete" title="清空" class="quickdelete" style="top: 0px; right: 0px; display: none;"></a>
</span>
## 解析元素 from selenium import webdriver browser = webdriver.Chrome() browser.get('https://www.baidu.com') # 通過id解析 inputTag = browser.find_element_by_id('kw') # 通過name解析 inputTag = browser.find_element_by_name('wd') # 通過class_name解析 inputTag = browser.find_element_by_class_name('s_ipt') # 通過CSS選擇器解析 inputTag = browser.find_element_by_css_selector('.quickdelete-wrap > input') # 通過xpath解析 inputTag = browser.find_element_by_xpath('//input[@id="kw"]') print(type(inputTag)) # Output: <class 'selenium.webdriver.remote.webelement.WebElement'> print(inputTag) # Output: <selenium.webdriver.remote.webelement.WebElement (session="446090034e5c7eb8f63ae5975428cd5d", element="0.07898054563855905-1")>
其實,在實際爬蟲中我們更多的情況是需要解析多個元素,此時我們便可以通過’browser.find_elements_by_XXX()’來解析,和單個元素解析不同,其返回的是一個WebElement元素列表,即find_element是獲取第一個滿足條件的元素,而find_elements則是獲取所有滿足條件的元素。
此外,通過上述這種解析可能不夠靈活,因為它都將解析方法都固定了,實際上selenium還為我們提供了一種可靈活選擇解析方法的解析函數,這樣上述示例便可等價為:
## 使用By來解析元素 from selenium import webdriver # 導入By對象 from selenium.webdriver.common.by import By browser = webdriver.Chrome() browser.get('https://www.baidu.com') # 通過id解析 inputTag = browser.find_element(By.ID,'su') # 通過name解析 inputTag = browser.find_element(By.NAME,'wd') # 通過class_name解析 inputTag = browser.find_element(By.CLASS_NAME,'s_ipt') # 通過CSS選擇器解析 inputTag = browser.find_element(By.CSS_SELECTOR,'.quickdelete-wrap > input') # 通過xpath解析 inputTag = browser.find_element(By.XPATH,'//input[@id="kw"]')
4.提取元素信息
在我們獲取到元素后,就要對元素的內容進行提取,提取對象包括元素的文本信息和元素的屬性信息,分別對應着text屬性和get_attribute(),使用示例如下:
HTML源文本:
<p id="cp">©2018 Baidu 使用百度前必讀 意見反饋 京ICP證030173號 京公網安備11000002000001號 </p>
copyright = browser.find_element_by_id('cp')
print(copyright.text) #©2018 Baidu 使用百度前必讀 意見反饋 京ICP證030173號 京公網安備11000002000001號
print(inputTag.get_attribute('id')) #cp
5.操作元素
元素的操作主要是點擊和輸入,在selenium中實現方式也很簡便,只需要對相應待操作元素使用click()和send_keys()方法即可,使用示例如下:
#使用send_keys和click方法模擬輸入和點擊
inputTag = browser.find_element_by_id('kw')
inputTag.send_keys('python')inputTag.click()
此外,在輸入中若要清除已輸入的內容,則可以使用clear()方法。對於任何與點擊操作有關的行為都可以用這種方法實現,比如說單選和復選,前提只需要獲取相應的元素就行了。
除了表單和單復選外,處理較多的還有下拉選擇,因下拉點擊后還需要選中元素,我們不能直接進行操作。不過我們可以借助selenium的一個類selenium.webdriver.support.ui.Select來實現,先將下拉選擇元素作為參數傳入這個類中實例化對象,然后我們就可以使用這個對象進行選擇了。使用示例如下:
## 模擬下拉選擇操作 from selenium import webdriver # 導入selenium提供的下拉選擇類 from selenium.webdriver.support.ui import Select # <此處省略部分代碼> # 選中下拉標簽並實例化Select對象 selectTag = Select(driver.find_element_by_name("FoodMenu")) # 三種選擇方式 # 根據序列索引選擇(從0開始) selectTag.select_by_index(1) # 根據屬性值value選擇 selectTag.select_by_value("Fish") # 根據可視文本選擇 selectTag.select_by_visible_text("魚") # 取消選中所有選項 selectTag.deselect_all()
三、其他使用
1.行為鏈
首先,什么是行為鏈呢?在上述的示例中,我們都是通過對單個元素執行單步操作完成的,其實還存有另一些操作,它們沒有特定的執行對象,比如鼠標拖拽、鍵盤按鍵等,這些動作是用另一種方式來執行的,常分為多步,這就是行為鏈,又稱為動作鏈。
由於行為鏈在爬蟲中運用得不多,在此以將鼠標移動到某個元素上並執行點擊事件為示例簡單介紹一下:
## 使用行為鏈示例 from selenium import webdriver # 導入行為鏈模塊 from selenium.webdriver import ActionChains # <此處省略部分代碼> #獲取操作對象元素 inputTag = browser.find_element_by_id('kw') submitTag = browser.find_element_by_id('su') # 實例化行為鏈,傳入參數webdriver對象 actions = ActionChains(browser) # 有序化定義行為鏈對象得執行步驟 actions.move_to_element(inputTag) actions.send_keys_to_element(inputTag,'python') actions.move_to_element(submitTag) actions.click(submitTag) # 執行行為鏈 actions.perform()
此外,還有如下得常見鼠標操作得方法:
點擊但不松開鼠標:click_and_hold(element)
右鍵點擊:context_click(element)
雙擊:double_click(element)
2.Cookie操作
使用Selenium我們可以很方便地對Cookie進行獲取、添加和刪除操作,使用示例如下:
## Cookie操作 from selenium import webdriver browser = webdriver.Chrome() browser.get('https://www.baidu.com') # 獲取所有Cookie print(browser.get_cookies()) #[{'domain': '.baidu.com', 'httpOnly': False, 'name': 'H_PS_PSSID', 'path': '/', 'secure': False, 'value': '26523_1465_21094_27244_20930'}, ...,{'domain': '.baidu.com', 'expiry': 3686218697.591083, 'httpOnly': False, 'name': 'PSTM', 'path': '/', 'secure': False, 'value': '1538735048'}] # 獲取指定名的Cookie print(browser.get_cookie('PSTM')) #{'domain': '.baidu.com', 'expiry': 3686218697.591083, 'httpOnly': False, 'name': 'PSTM', 'path': '/', 'secure': False, 'value': '1538735048'} # 添加Cookie browser.add_cookie({'name':'name','domain':'www.baidu.com','value':'UnikFox'}) print(browser.get_cookies()) #[{'domain': '.baidu.com', 'httpOnly': False, 'name': 'H_PS_PSSID', 'path': '/', 'secure': False, 'value': '26523_1465_21094_27244_20930'}...{'domain': 'www.baidu.com', 'expiry': 2169455052, 'httpOnly': False, 'name': 'name', 'path': '/', 'secure': True, 'value': 'UnikFox'}] # 刪除指定名的Cookie browser.delete_cookie('name') print(browser.get_cookies()) #[{'domain': '.baidu.com', 'httpOnly': False, 'name': 'H_PS_PSSID', 'path': '/', 'secure': False, 'value': '26523_1465_21094_27244_20930'}, ...,{'domain': '.baidu.com', 'expiry': 3686218697.591083, 'httpOnly': False, 'name': 'PSTM', 'path': '/', 'secure': False, 'value': '1538735048'}] # 刪除所有Cookie browser.delete_all_cookies() print(browser.get_cookies()) #[]
3.頁面等待
由於很多時候我們無法預知頁面元素需要花多長的時間進行加載,這時候我們就需要使用等待技術等待頁面加載完成在進行解析。常用的等待方式分為顯式等待和隱式等待。其中,顯式等待即靜態等待,無論是否加載完成都會等待,類似於time.sleep();而隱式等待則是條件等待,通常會設置一個條件,在等待的期間當條件滿足時就會結束等待,若等待時間到了條件仍未滿足就會拋出TimeoutException錯誤。
使用示例如下:
## 頁面等待 from selenium import webdriver # 導入等待類 from selenium.webdriver.support.ui import WebDriverWait # 導入判斷條件 from selenium.webdriver.support import expected_conditions as EC # 導入檢索條件 from selenium.webdriver.common.by import By browser = webdriver.Chrome() browser.get('https://www.douban.com') # 隱式等待 browser.implicitly_wait(10) browser.find_element_by_id('123456') # 顯式等待加載 element= WebDriverWait(browser,10).until(
# 調用判斷條件檢查元素是否已加載顯示 EC.presence_of_element_located((By.ID,'123456')) #傳入檢索元組(方法,值) ) print(element) browser.quit()
一些其他的等待條件:
presence_of_element_located():某個元素已加載完畢
presence_of_all_emement_located():網頁中所有滿足條件的元素都已加載完畢
element_to_be_cliable():某個元素已可以點擊
4.打開新標簽頁面與切換頁面
如果有時候一個瀏覽器需要打開不同的標簽頁面(這里不是新打開一個瀏覽器),我們可以借助browser的execute_script("window.open(url)")方法來實現,不過要注意的是,雖然打開了一個新的標簽頁面,但並沒有切換過去,browser訪問的還是原來的頁面,我們可以通過browser.current_url來查看當前頁面URL。
對於擁有多個子標簽的頁面,如果我們想要切換不同的頁面,可以借助selenium提供的switch_to_window()切換方法,該方法接收待切換頁面的對象,具體可通過browser.window_handles列表索引得到,而這給列表里的元素是按照browser訪問頁面的先后順序自動定的。
使用示例如下:
## 打開新標簽頁面和切換頁面 from selenium import webdriver browser = webdriver.Chrome() browser.get('https://www.baidu.com') #打開一個新的標簽頁面 browser.execute_script("window.open('https://www.douban.com')") # 查看當前訪問得頁面 print(browser.current_url) # https://www.baidu.com/ # 查看window_handles記錄列表 print(browser.window_handles) # ['CDwindow-9F7F732D4DCD86446392EADF4D719F07', 'CDwindow-A61A3EE061BC15495FF17AB629309A0B'] #切換頁面 browser.switch_to.window(browser.window_handles[1]) print(browser.current_url) # https://www.douban.com/
5.使用代理
在Selenium中我們也可以進行代理設置,不同的瀏覽器設置代理得方式不同,這里我們以Chrome為例介紹設置代理得方法。
在Chrome中設置代理,首先需要獲取設置對象webdriver.ChromeOptions(),再使用該對象得add_argument()方法對其添加代理參數,最后再實例化瀏覽器驅動對象webdrive.Chrome(),同時傳入參數設置對象即可。
使用示例如下:
from selenium import webdriver # 不使用代理 browser = webdriver.Chrome() browser.get('http://httpbin.org/ip') """ { "origin": "36.157.132.78" } """ # 使用代理 # 獲取設置對象 options = webdriver.ChromeOptions() # 新增設置參數 options.add_argument("--proxy-server=http://134.175.68.57:80") # 實例化瀏覽器並傳入設置選擇參數 browser = webdriver.Chrome(chrome_options=options) browser.get('http://httpbin.org/ip') """ { "origin": "134.175.68.57" } """