13. Selenium與PhantomJS
Selenium是一個Web的自動化測試工具,最初是為網(wǎng)站自動化測試而開發(fā)的,類型像我們玩游戲用的按鍵精靈,可以按指定的命令自動操作,不同是Selenium 可以直接運行在瀏覽器上,它支持所有主流的瀏覽器(包括PhantomJS這些無界面的瀏覽器)。
Selenium 可以根據(jù)我們的指令,讓瀏覽器自動加載頁面,獲取需要的數(shù)據(jù),甚至頁面截屏,或者判斷網(wǎng)站上某些動作是否發(fā)生。
PyPI網(wǎng)站下載 Selenium庫 https://pypi.python.org/simple/selenium ,也可以用 第三方管理器
pip用命令安裝:pip install selenium
Selenium 官方參考文檔:http://selenium-python.readthedocs.io/index.html
2. PhantomJS
PhantomJS 是一個基于Webkit的“無界面”(headless)瀏覽器,它會把網(wǎng)站加載到內(nèi)存并執(zhí)行頁面上的 JavaScript,因為不會展示圖形界面,所以運行起來比完整的瀏覽器要高效
如果我們把 Selenium 和 PhantomJS 結(jié)合在一起,就可以運行一個非常強大的網(wǎng)絡爬蟲了,這個爬蟲可以處理 JavaScrip、Cookie、headers,以及任何我們真實用戶需要做的事情
2.1注意:PhantomJS(python2)
只能從它的官方網(wǎng)站http://phantomjs.org/download.html) 下載。 因為 PhantomJS 是一個功能完善(雖然無界面)的瀏覽器而非一個 Python 庫,所以它不需要像 Python 的其他庫一樣安裝,但我們可以通過Selenium調(diào)用PhantomJS來直接使用。
PhantomJS 官方參考文檔:http://phantomjs.org/documentation
2.2 python3使用的瀏覽器
隨著Python3的普及,Selenium3也跟上了行程。而Selenium3最大的變化是去掉了Selenium RC,另外就是Webdriver從各自瀏覽器中脫離,必須單獨下載
2.1.1 安裝Firefox geckodriver
安裝firefox最新版本,添加Firefox可執(zhí)行程序到系統(tǒng)環(huán)境變量。記得關(guān)閉firefox的自動更新
firefox下載地下:https://github.com/mozilla/geckodriver/releases
將下載的geckodriver.exe 放到path路徑下 D:\Python\Python36\
2.1.2 安裝ChromeDriver
http://chromedriver.storage.googleapis.com/index.html
注意版本號要對應
下載下來的文件解壓到
Python36\Scripts
chrome59版本以后可以變成無頭的瀏覽器,加以下參數(shù)
options = webdriver.ChromeOptions()
options.add_argument('--headless')
chrome = webdriver.Chrome(chrome_options=options)
chrome.get("http://ww.baidu.com")
3. 使用方式
Selenium 庫里有個叫 WebDriver 的 API。WebDriver 有點兒像可以加載網(wǎng)站的瀏覽器,但是它也可以像 BeautifulSoup 或者其他 Selector 對象一樣用來查找頁面元素,與頁面上的元素進行交互 (發(fā)送文本、點擊等),以及執(zhí)行其他動作來運行網(wǎng)絡爬蟲
3.1 簡單例子
# 導入 webdriver
from selenium import webdriver
# 要想調(diào)用鍵盤按鍵操作需要引入keys包
from selenium.webdriver.common.keys import Keys
# 調(diào)用環(huán)境變量指定的PhantomJS瀏覽器創(chuàng)建瀏覽器對象
driver = webdriver.PhantomJS()
# 如果沒有在環(huán)境變量指定PhantomJS位置
# driver = webdriver.PhantomJS(executable_path="./phantomjs"))
# get方法會一直等到頁面被完全加載,然后才會繼續(xù)程序,通常測試會在這里選擇 time.sleep(2)
driver.get("http://www.baidu.com/")
# 獲取頁面名為 wrapper的id標簽的文本內(nèi)容
data = driver.find_element_by_id("wrapper").text
# 打印數(shù)據(jù)內(nèi)容
print(data)
# 打印頁面標題 "百度一下,你就知道"
print(driver.title)
# 生成當前頁面快照并保存
driver.save_screenshot("baidu.png")
# id="kw"是百度搜索輸入框,輸入字符串"長城"
driver.find_element_by_id("kw").send_keys("尚學堂")
# id="su"是百度搜索按鈕,click() 是模擬點擊
driver.find_element_by_id("su").click()
# 獲取新的頁面快照
driver.save_screenshot("尚學.png")
# 打印網(wǎng)頁渲染后的源代碼
print(driver.page_source)
# 獲取當前頁面Cookie
print(driver.get_cookies())
# ctrl+a 全選輸入框內(nèi)容
driver.find_element_by_id("kw").send_keys(Keys.CONTROL,'a')
# ctrl+x 剪切輸入框內(nèi)容
driver.find_element_by_id("kw").send_keys(Keys.CONTROL,'x')
# 輸入框重新輸入內(nèi)容
driver.find_element_by_id("kw").send_keys("python爬蟲")
# 模擬Enter回車鍵
driver.find_element_by_id("su").send_keys(Keys.RETURN)
# 清除輸入框內(nèi)容
driver.find_element_by_id("kw").clear()
# 生成新的頁面快照
driver.save_screenshot("python爬蟲.png")
# 獲取當前url
print(driver.current_url)
# 關(guān)閉當前頁面,如果只有一個頁面,會關(guān)閉瀏覽器
# driver.close()
# 關(guān)閉瀏覽器
driver.quit()
4 頁面操作
4.1 頁面交互
僅僅抓取頁面沒有多大卵用,我們真正要做的是做到和頁面交互,比如點擊,輸入等等。那么前提就是要找到頁面中的元素。WebDriver提供了各種方法來尋找元素。例如下面有一個表單輸入框
<input type="text" name="passwd" id="passwd-id" />
4.1.1 獲取
element = driver.find_element_by_id("passwd-id")
element = driver.find_element_by_name("passwd")
element = driver.find_elements_by_tag_name("input")
element = driver.find_element_by_xpath("//input[@id='passwd-id']")
注意:
文本必須完全匹配才可以,所以這并不是一個很好的匹配方式
在用 xpath 的時候還需要注意的如果有多個元素匹配了 xpath,它只會返回第一個匹配的元素。如果沒有找到,那么會拋出 NoSuchElementException 的異常
4.1.2 輸入內(nèi)容
element.send_keys("some text")
4.1.3 模擬點擊某個按鍵
element.send_keys("and some", Keys.ARROW_DOWN)
4.1.4 清空文本
element.clear()
4.1.5 元素拖拽
要完成元素的拖拽,首先你需要指定被拖動的元素和拖動目標元素,然后利用 ActionChains 類來實現(xiàn)
以下實現(xiàn)元素從 source 拖動到 target 的操作
element = driver.find_element_by_name("source")
target = driver.find_element_by_name("target")
from selenium.webdriver import ActionChains
action_chains = ActionChains(driver)
action_chains.drag_and_drop(element, target).perform()
4.1.6 歷史記錄
操作頁面的前進和后退功能
driver.forward()
driver.back()
5 API
5.1 元素選取
5.1.1 單個元素選取
find_element_by_id
find_element_by_name
find_element_by_xpath
find_element_by_link_text
find_element_by_partial_link_text
find_element_by_tag_name
find_element_by_class_name
find_element_by_css_selector
5.1.2 多個元素選取
find_elements_by_name
find_elements_by_xpath
find_elements_by_link_text
find_elements_by_partial_link_text
find_elements_by_tag_name
find_elements_by_class_name
find_elements_by_css_selector
5.1.3 利用 By 類來確定哪種選擇方式
from selenium.webdriver.common.by import By
driver.find_element(By.XPATH, '//button[text()="Some text"]')
driver.find_elements(By.XPATH, '//button')
By 類的一些屬性如下
ID = "id"
XPATH = "xpath"
LINK_TEXT = "link text"
PARTIAL_LINK_TEXT = "partial link text"
NAME = "name"
TAG_NAME = "tag name"
CLASS_NAME = "class name"
CSS_SELECTOR = "css selector"
6 等待
6.1 隱式等待
到了一定的時間發(fā)現(xiàn)元素還沒有加載,則繼續(xù)等待我們指定的時間,如果超過了我們指定的時間還沒有加載就會拋出異常,如果沒有需要等待的時候就已經(jīng)加載完畢就會立即執(zhí)行
from selenium import webdriver
url = 'https://www.guazi.com/nj/buy/'
driver = webdriver.Chrome()
driver.get(url)
driver.implicitly_wait(100)
print(driver.find_element_by_class_name('next'))
print(driver.page_source)
6.2 顯示等待
指定一個等待條件,并且指定一個最長等待時間,會在這個時間內(nèi)進行判斷是否滿足等待條件,如果成立就會立即返回,如果不成立,就會一直等待,直到等待你指定的最長等待時間,如果還是不滿足,就會拋出異常,如果滿足了就會正常返回
? ?url = 'https://www.guazi.com/nj/buy/'
? ?driver = webdriver.Chrome()
? ?driver.get(url)
? ?wait = WebDriverWait(driver,10)
? ?wait.until(EC.presence_of_element_located((By.CLASS_NAME, 'next')))
? ?print(driver.page_source)
presence_of_element_located ?
元素加載出,傳入定位元組,如(By.ID, 'p')
presence_of_all_elements_located
所有元素加載出
element_to_be_clickable
元素可點擊
element_located_to_be_selected
元素可選擇,傳入定位元組