selenium——自動化測試工具,專門爲Web應用程序編寫的一個驗收測試工具,測試其兼容性,功能什麼的。然而讓蟲師們垂涎的並非以上的種種,而是其經過驅動瀏覽器得到的解析JavaScript的能力。因此說這貨在動態爬取方面簡直是掛逼級別的存在,相較於手動分析更簡單易用,節省分析打碼時間。css
雖然selenium因其「超能力」被很多人吹上天了,可是認清利弊,根據需求來選擇爬蟲工具,仍是挺重要的,因此這裏簡單說下以供參考:python
理由:打開一個/多個瀏覽器,瀏覽器裏還有n個窗口.....
下面很少說,進入正題git
本體直接pip安裝pip install selenium
github
驅動按需選擇:web
下載好後把解壓獲得的驅動放到設置了環境變量的路徑下就好了,若是你的python設置了環境變量,應該丟到python目錄下就好了。ajax
照例貼上文檔,2.53舊版中文,想學更多就給我啃
選好瀏覽器就建立實例,以後的操做都在這個實例之上,並介紹一些有用的option,本文以Chrome爲例。算法
from selenium import webdriver #其餘瀏覽器把Chrome換名就行 #option = webdriver.ChromeOptions() #option.set_headless() 設置無頭瀏覽器,就是隱藏界面後臺運行 driver = webdriver.Chrome() #建立driver實例 #driver = webdriver.Chrome(chrome_options=option) 建立實例並載入option url = '**********' driver.get(url) #driver.maximize_window() 最大化窗口 #driver.set_window_size(width,height) 設置窗口大小 print(driver.page_source) #打印網頁源碼 driver.quit() # 關閉瀏覽器
對付低級的動態網頁(ajax較少)就是這麼簡單,基本不用考慮動態問題,徒手擼動態的人表示羨慕。然而更多時候並不像這樣簡單,直接套用的話很容易致使源碼所見非所得,並且不少爬蟲並無簡單到拿個源碼就走的程度,它還要交互,模擬點擊滾動等等。因此還請往下看,不要看到這就投入實戰啦chrome
selenium提供多種方法對元素進行定位,返回WebElement對象,而上面提到的driver就至關於最大的WebElement對象npm
#如下都是單次定位,返回第一個定位到的。若是想屢次定位,給element加個s就行,返回的是符合元素的列表 element = driver.find_element_by_id() # 經過標籤的id定位,接收id屬性值 driver.find_element_by_name() # 經過標籤的name定位,接收name屬性值 driver.find_element_by_xpath() # 經過xpath定位,接收xpath表達式 driver.find_element_by_link_text() # 經過標籤的徹底文本定位,接收完整的文本 driver.find_element_by_partial_link_text() # 經過標籤的部分文本定位,接收部分文本 driver.find_element_by_tag_name() # 經過標籤名定位,接收標籤名 driver.find_element_by_class_name() # 經過標籤的class定位,接收class屬性值 driver.find_element_by_css_selector() # 經過css選擇器定位,接收其語法 #返回的WebElement對象能夠繼續往下定位
xpath和css就不展開講了,能實現精肯定位,必定要學其中一個,不知道的小夥伴們上網自學吧,不難windows
除了上面這些公有的方法,還有2個私有的方法來幫助頁面對象的定位。 這兩個方法就是 find_element 和 find_elements,須要導入By類輔助,接收一個By類屬性及其對應語法/值
from selenium.webdriver.common.by import By driver.find_element(By.XPATH,'//a[text()="dark"]') driver.find_elements(By.XPATH,'//a[text()="dark"]') '''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" '''
不少人在用selenium會遇到所見非所得,或者定位頁面元素的時候會定位不到的問題,這種狀況頗有多是frame在搞鬼,必須切換到相應frame中再進行定位。若是遇到以上問題,第一時間F12看下你所要的信息是否在frame標籤裏面。
frame標籤有frameset、frame、iframe三種,frameset跟其餘普通標籤沒有區別,不會影響到正常的定位,而frame與iframe對selenium定位而言是同樣的。
selenium提供了4種方法定位iframe並切換進去:
#對於<iframe name="frame1" id="dark">.....</iframe> driver.switch_to_frame(0) # 用frame的index來定位,第一個是0,以此類推 driver.switch_to_frame("frame1") # 用id來定位 driver.switch_to_frame("dark") # 用name來定位 driver.switch_to_frame(driver.find_element_by_tag_name("iframe")) # 用WebElement對象來定位
一般經過id和name就能實現,無此屬性時能夠經過WebElement對象,即用find_element系列方法所取得的對象來定位。若是你肯定每一個目標frame都是固定第幾個,那也能夠用index定位
切到frame中以後,就不能繼續操做主文檔的元素了,這時若是想操做主文檔內容,則需切回主文檔。
driver.switch_to_default_content()
嵌套frame的切換
若是frame裏包着frame而你要的frame是後者,那麼須要一層一層切換進去,切換方法四選一
driver.switch_to_frame("frame1") driver.switch_to_frame("frame2")
若是想回去上一個父frame,用driver.switch_to.parent_frame()
有時候點開一個連接就會彈出一個新窗口,若是要對其操做就要切換過去,方法和frame的切換差很少,但只接收window_handle(至關於窗口的名字)來進行切換。driver.switch_to_window("windowName")
切換前最好保存以前的handle和全部的handles以便於來回切換。
current_window = driver.current_window_handle # 獲取當前窗口handle name all_windows = driver.window_handles # 獲取全部窗口handle name # 若是window不是當前window,則切換到該window,即切換到新窗口 for window in all_windows: if window != current_window: driver.switch_to_window(window) #.... driver.switch_to_window(current_window) # 返回以前的窗口 driver.close() # 窗口的關閉用close()
經常使用的頁面交互有點擊,輸入文本等。交互的原則是先定位,後交互,好比你F12找到了某個文本框或某個可點擊項的標籤,那就先定位到那,再用如下的交互方法
from selenium.webdriver.common.keys import Keys # 首先定位到某個文本框或某個可點擊項(如超連接,按鈕), element = driver.find_element_by_xpath('//a[text()="dark"]') element.send_keys("some text") # 往文本框輸入文本 #element.send_keys("some text", Keys.ARROW_DOWN) 可使用 Keys 類來模擬輸入方向鍵 element.clear() # 清空文本框 #element.click() 若是此元素可點擊,可用click()方法
要注意的一點是,不是定位到就一定能交互,有時候目標會被網頁彈出來的東西覆蓋,致使沒法交互,因此要確保頁面乾淨無覆蓋
selenium能夠執行js,下拉滾動能夠經過此實現,所以就算不懂js也能夠記一些有用的js代碼
#driver.execute_script('js_str') driver.execute_script('window.scrollTo(0,10000)') # 移動到指定座標 driver.execute_script('window.scrollBy(0,10000)') # 相對當前座標移動 driver.execute_script('window.scrollTo(0, document.body.scrollHeight)') # 相對當前座標移動
如今很多web都都有使用ajax技術,即異步加載,有時候你要的東西都還沒加載到你就去定位了,就會拋出異常。爲了不此等血淋淋的慘狀,必需要待其加載一段時間後再進行後面的操做。這裏付一張不等待就獲取page_source的後果
最粗暴的方法就是使用time.sleep(),這很笨,由於你還要設置合適的時間,而不一樣網站加載的速度有異,容易形成時間的浪費。因此最好仍是使用selenium提供的兩種等待方法
顯式Wiats容許你設置一個加載時間的上限和一個條件,每隔0.5s就判斷一下所設條件,條件成立就繼續執行下面的代碼,若是過了時間上限仍是沒有成立,默認拋出NoSuchElementException 異常。這種相對智能的等待方法能最大化地節省時間,應該優先選擇使用
selenium提供了多種expected_conditions(EC)來設置條件,可是要注意有定位時EC的方法接收的是定位信息的元組(locator_tuple)而不是兩個參數,正確用法如 EC.presence_of_element_located((By.ID,"dark"))
這個條件檢測是否有id='dark'的元素
selenium提供的EC有如下方法,意思如其名,這裏註釋一些易搞錯的,選擇使用
title_is(str)
title_contains(str)
presence_of_element_located(locator_tuple)
visibility_of_element_located(locator_tuple) # 判斷某個元素是否可見
visibility_of(WebElement) # 同上,傳參不一樣
presence_of_all_elements_located(locator_tuple)
text_to_be_present_in_element(str) # 判斷某個元素中的text是否包含了指定字符串
text_to_be_present_in_element_value(str) # 判斷某個元素中的value屬性是否包含了預期的字符串
frame_to_be_available_and_switch_to_it
invisibility_of_element_located(locator_tuple)
element_to_be_clickable(locator_tuple)
staleness_of(WebElement) # 等待某個元素從的移除
element_to_be_selected(WebElement)
element_located_to_be_selected(locator_tuple)
element_selection_state_to_be(WebElement)
element_located_selection_state_to_be(locator_tuple)
alert_is_present() # 判斷頁面上是否存在alert
使用上一般搭配try語句
from selenium.webdriver.common.by import By from selenium.webdriver.support.ui import WebDriverWait # 導入顯式等待 from selenium.webdriver.support import expected_conditions as EC # 導入EC from selenium.common.exceptions import NoSuchElementException # WebDriverWait(driver,time).until(EC) 顯式waits try: element = WebDriverWait(driver,10).until(EC.presence_of_element_located((By.ID,"myDynamicElement"))) except NoSuchElementException: #..... finally: driver.quit()
隱式等待是在嘗試定位某個元素的時候,若是沒能成功,就等待固定長度的時間,默認0秒。一旦設置了隱式等待時間,它的做用範圍就是Webdriver對象實例的整個生命週期。driver.implicitly_wait(10)
這是用selenium幾分鐘弄出來的網易雲音樂單曲評論爬蟲,並且還模擬了評論翻頁,還截了圖。沒提取信息,提取的時候能夠用BeautifulSoup或正則提取,
from selenium import webdriver import time from selenium.common.exceptions import NoSuchElementException, TimeoutException from selenium.webdriver.support import expected_conditions as EC from selenium.webdriver.common.by import By from selenium.webdriver.support.ui import WebDriverWait driver = webdriver.Chrome() driver.maximize_window() driver.get("http://music.163.com/#/song?id=31877470") driver.switch_to_frame("contentFrame") time.sleep(5) driver.execute_script('window.scrollTo(0, document.body.scrollHeight)') driver.save_screenshot('E:/python3/gg.png') # 截圖 b = driver.find_element_by_xpath("//a[starts-with(@class,'zbtn znxt')]") b.click() try: WebDriverWait(driver, 10).until(EC.presence_of_element_located((By.XPATH,"//a[@data-type='reply']"))) print(driver.page_source) except NoSuchElementException: print('OMG') finally: driver.quit()
短短二十行就能作到這種程度(並且很多仍是import的),足以見得selenium強大。若是要手動分析,你還要分析js加密算法,寫上n倍的代碼。二者相比起來selenium真的很吸引人,簡直是懶人救星。你們權衡利弊按需選擇吧