爬蟲—Selenium使用


Selenium使用

  Selenium是一個自動化測試工具,可以驅動瀏覽器器執行特定的動作,如點擊,下拉等。同時還可以獲取瀏覽器當前呈現頁面的源代碼,可見即可爬。

1.准備

  我們使用谷歌Chrome瀏覽器為例子,在開始之前需要安裝Chrome瀏覽器並配置ChromeDriver。而且還需要安裝Python的Selenium庫。

2.基本使用

from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.common.keys import Keys
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.support.wait import WebDriverWait

# 聲明瀏覽器對象,將chromedriver驅動放在chrome瀏覽器安裝目錄下,指定驅動的絕對路徑
browser = webdriver.Chrome(executable_path=r'D:\Google\Chrome\Application\chromedriver')
try:
    browser.get('http://www.baidu.com')      
    keyword = browser.find_element_by_id('kw')
    keyword.send_keys('Python')
    keyword.send_keys(Keys.ENTER)
    wait = WebDriverWait(browser, 10)
    wait.until(EC.presence_of_element_located((By.ID, 'content_left')))
    print(browser.current_url)
    print(browser.get_cookies())
    print(browser.page_source)
finally:
    browser.close()

  運行結果:

https://www.baidu.com/s?ie=utf-8&f=8&rsv_bp=1&rsv_idx=1&tn=baidu&wd=Python&rsv_pq=962442bf0007ea18&rsv_t=753aQptBMQwu82UDxwDFL9MEWvHNLNqjPznV4pNUSDP%2Bimq4HPgY91krrlM&rqlang=cn&rsv_enter=1&rsv_sug3=6&rsv_sug2=0&inputT=125&rsv_sug4=125
[{'domain': '.baidu.com', 'httpOnly': False, 'name': 'H_PS_PSSID', 'path': '/', 'secure': False, 'value': '1465_21104_29135_28518_29098_28831_28585_26350_29133'}, {'domain': '.baidu.com', 'httpOnly': False, 'name': 'delPer', 'path': '/', 'secure': False, 'value': '0'}, {'domain': '.baidu.com', 'expiry': 3707115919.146628, 'httpOnly': False, 'name': 'BAIDUID', 'path': '/', 'secure': False, 'value': '3A3A4CD3F97428EF73BA5E8B09ECB3C3:FG=1'}, {'domain': '.baidu.com', 'expiry': 3707115919.14668, 'httpOnly': False, 'name': 'PSTM', 'path': '/', 'secure': False, 'value': '1559632270'}, {'domain': '.baidu.com', 'expiry': 3707115919.146663, 'httpOnly': False, 'name': 'BIDUPSID', 'path': '/', 'secure': False, 'value': '3A3A4CD3F97428EF73BA5E8B09ECB3C3'}, {'domain': 'www.baidu.com', 'httpOnly': False, 'name': 'BD_HOME', 'path': '/', 'secure': False, 'value': '0'}, {'domain': '.baidu.com', 'expiry': 1559718674.348966, 'httpOnly': False, 'name': 'BDORZ', 'path': '/', 'secure': False, 'value': 'B490B5EBF6F3CD402E515D22BCDA1598'}, {'domain': 'www.baidu.com', 'expiry': 1560496273, 'httpOnly': False, 'name': 'BD_UPN', 'path': '/', 'secure': False, 'value': '12314753'}, {'domain': 'www.baidu.com', 'httpOnly': False, 'name': 'BD_CK_SAM', 'path': '/', 'secure': False, 'value': '1'}, {'domain': 'www.baidu.com', 'expiry': 1559634866, 'httpOnly': False, 'name': 'H_PS_645EC', 'path': '/', 'secure': False, 'value': '1058c7aSaGElrxQn6SZOATLVXWtCzFAGCMEiW5OevaJTsJ938%2BGyVo1%2B72k'}, {'domain': '.baidu.com', 'httpOnly': False, 'name': 'PSINO', 'path': '/', 'secure': False, 'value': '5'}, {'domain': 'www.baidu.com', 'httpOnly': False, 'name': 'BDSVRTM', 'path': '/', 'secure': False, 'value': '173'}]
<!DOCTYPE html><!--STATUS OK--><html xmlns="http://www.w3.org/1999/xhtml"><head><script charset="utf-8" async="" src="https://ss0.bdstatic.com/-0U0bnSm1A5BphGlnYG/tam-ogel/5d4e9b24-dcc5-483a-b6da-be1e9e621891.js"></script>
    
    <meta http-equiv="content-type" content="text/html;charset=utf-8" /><style data-for="result" id="css_result" type="text/css">body{color:#333;background:#fff;padding:6px 0 0;margin:0;position:relative;min-width:900px}body,th,td,.p1,.p2{font-family:arial}p,form,ol,ul,li,dl,dt,dd,h3{margin:0;padding:0;list-style:none}input{padding-top:0;padding-bottom:0;-moz-box-sizing:border-box;-webkit-box-sizing:border-box;box-sizing:border-box}table,img{border:0}td{font-size:9pt;line-height:18px}em{font-style:normal;color:#c00}a em{text-decoration:underline}cite{font-style:normal;......

  運行代碼后發現,會自動彈出一個Chrome瀏覽器,首先跳轉到百度,然后輸入Python,接着跳轉到搜索結果。結果加載出來后,控制台會打印當前url,Cookies和網頁源碼。可以看到我們得到的都是瀏覽器中真實顯示的內容。這樣使用Selenium驅動瀏覽器加載網頁可以直接獲取到動態渲染的結果。

3.查找節點

  Selenium可以驅動瀏覽器完成各種操作,比如點擊模擬,表單填寫。例如,我們如果想要在某一輸入框內輸入文本,首先需要找到這個輸入框的位置,也就是在網頁中的所在節點的位置。

  ♦單個節點

  

  想要在百度搜索框中輸入文本,首先觀察它的源碼。我們可以發它的name屬性為wd,id為kw,還有一些其他屬性。此時我們可以用多種方式來獲取它。

# 單個節點
browser.get('http://www.baidu.com')
input1 = browser.find_element_by_id('kw')                   # 使用屬性選擇
input2 = browser.find_element_by_css_selector('#kw')        # 使用css選擇
input3 = browser.find_element_by_xpath('//*[@id="kw"]')     # 使用xpath選擇
print(input1)
print(input2)
print(input3)
browser.close()

   運行結果:

<selenium.webdriver.remote.webelement.WebElement (session="77121972a5b1ff253e30e6912a609acc", element="0.1322124037138812-1")>
<selenium.webdriver.remote.webelement.WebElement (session="77121972a5b1ff253e30e6912a609acc", element="0.1322124037138812-1")>
<selenium.webdriver.remote.webelement.WebElement (session="77121972a5b1ff253e30e6912a609acc", element="0.1322124037138812-1")>

  可以看到三個方式返回的結果是完全一致的。當然還有其他很多方法可以使用。

  ♦多個節點

    如果查找的目標只有一個,那么完全可以使用find_element()方法,如果有個多目標,find_element()方法只能查找到第一個,要想全部查找到,需要使用find_elements()方法。方法名后面多了一個s。

    比如,想要查找淘寶網左側導航欄上面的所有條目:

                      

  

# 多個節點,淘寶導航欄條目為例
browser.get('https://www.taobao.com')
items = browser.find_elements_by_css_selector('.service-bd li')
print(items)
browser.close()

    運行結果:

selenium.webdriver.remote.webelement.WebElement (session="d0d87044954d7497862d2f93b0480667", element="0.5258543885521916-1")>, <selenium.webdriver.remote.webelement.WebElement (session="d0d87044954d7497862d2f93b0480667", element="0.5258543885521916-2")>, <selenium.webdriver.remote.webelement.WebElement (session="d0d87044954d7497862d2f93b0480667", element="0.5258543885521916-3")>, <selenium.webdriver.remote.webelement.WebElement ......

    這里可以看到,獲取的內容為一個列表類型,列表中的每個元素都是WebElement類型。

4.節點操作

  Selenium提供了一些方法來模擬瀏覽器的動作,輸入文字使用send_key()方法,清空使用clear()方法,點擊按鈕方使用click()方法。 

# 2.節點交互
import time

browser = webdriver.Chrome(executable_path=r'D:\Google\Chrome\Application\chromedriver')
browser.get('http://www.baidu.com')
input_word = browser.find_element_by_id('kw')
input_word.send_keys('apple')
time.sleep(2)
input_word.clear()
input_word.send_keys('cherry')
button = browser.find_element_by_id('su')
time.sleep(3)
button.click()
browser.close()

5.動作鏈操作    

  鼠標拖拽,鍵盤按鍵等等,這些動作是使用動作鏈操作來完成的。下面以菜鳥教程的網站為例:

# 5.動作鏈操作
from selenium import webdriver
from selenium.webdriver import ActionChains
import time

browser = webdriver.Chrome(executable_path=r'D:\Google\Chrome\Application\chromedriver')
url = 'http://www.runoob.com/try/try.php?filename=jqueryui-api-droppable'
browser.get(url)
browser.switch_to.frame('iframeResult')
s1 = browser.find_element_by_css_selector('#draggable')
s2 = browser.find_element_by_css_selector('#droppable')
actions = ActionChains(browser)
actions.drag_and_drop(s1, s2)
actions.perform()
time.sleep(2)
browser.close()

  執行代碼,會打開網站頁面,然后自動拖動其中一個拖拽示例拖拽到目標位置。

6.操作JavaScript

  Selenium中模擬操作JavaScript使用execute_script()方法來實現。訪問網站,滑動到底部,最后彈出“OK”。 

# 6.模擬JavaScript操作
from selenium import webdriver
import time

browser = webdriver.Chrome(executable_path=r'D:\Google\Chrome\Application\chromedriver')
browser.get('https://www.zhihu.com/explore')
browser.execute_script('window.scrollTo(0,document.body.scrollHeight)')
browser.execute_script('alert("OK")')
time.sleep(3)
browser.close()

7.獲取節點信息

  ♦獲取屬性

  使用get_attribute()方法來獲取節點屬性,先選中這個節點: 

# 7.1獲取屬性
browser = webdriver.Chrome(executable_path=r'D:\Google\Chrome\Application\chromedriver')
browser.get('https://www.zhihu.com/explore')
logo = browser.find_element_by_id('zh-top-link-logo')
print(logo)
print(logo.get_attribute('class'))
browser.close()

  運行結果:

<selenium.webdriver.remote.webelement.WebElement (session="13c1e08b7569415b9027cdfec9703a0e", element="0.2490095895940252-1")>
zu-top-link-logo
  ♦獲取文本

  每個WebElement節點都有其text屬性,直接調用這個屬性就得到其內部的文本信息。 獲取百度首頁新聞的文本內容。  

# 7.2獲取文本信息
browser = webdriver.Chrome(executable_path=r'D:\Google\Chrome\Application\chromedriver')
browser.get('http://www.baidu.com')
icons = browser.find_element_by_name('tj_trnews')
print(icons.text)

  運行結果:

新聞
  ♦獲取id,位置,標簽名,大小
# 7.3獲取id,位置,標簽名,大小
browser = webdriver.Chrome(executable_path=r'D:\Google\Chrome\Application\chromedriver')
browser.get('http://www.baidu.com')
icons = browser.find_element_by_name('tj_trnews')
print(icons.id)
print(icons.location)
print(icons.tag_name)
print(icons.size)

  運行結果:

0.4808968979713124-1
{'x': 557, 'y': 19}
a
{'height': 24, 'width': 26}

8.切換Frame

  網頁中有一種節點叫做iframe,也就是子Frame,相當於頁面的子頁面,它的結構和外部網頁一致。Selenium默認是在父級Frame里面操作,如果頁面中還有子Frame,不能直接獲取到子頁面的數據,需要使用switch_to.frame()切換Frame。

# 8.切換Frame
from selenium import webdriver
from selenium.common.exceptions import NoSuchElementException

browser = webdriver.Chrome(executable_path=r'D:\Google\Chrome\Application\chromedriver')
url = 'http://www.runoob.com/try/try.php?filename=jqueryui-api-droppable'
browser.get(url)
browser.switch_to.frame('iframeResult')  
try:
    logo_first = browser.find_element_by_class_name('logo')
except NoSuchElementException:
    print("Failed")
browser.switch_to.parent_frame()  # 切換到父級Frame
logo = browser.find_element_by_class_name('logo')
print(logo)
print(logo.text)

  運行結果:

Failed
<selenium.webdriver.remote.webelement.WebElement (session="497ccfe660416ed053ba4b08b5c7351f", element="0.03506166807633293-2")>
RUNOOB.COM

9.延時等待

  在Selenium中,get()方法會在網頁加載結束后執行,此時獲取page_source可能並不是瀏覽器完全加載的數據。如果有額外的Ajax請求,不一定能獲取成功。所有需要延時等待一定時間,確保數據已經加載出來。

  ♦隱式等待

  如果Selenium沒有在DOM中找到節點,將繼續等待,超出設定時間后就會拋出沒有節點的異常。

# 9.延時等待
# 9.1隱式等待:沒有找到繼續等待,超時拋出異常
browser = webdriver.Chrome(executable_path=r'D:\Google\Chrome\Application\chromedriver')
browser.implicitly_wait(10)
browser.get('https://www.zhihu.com/explore')
que = browser.find_element_by_class_name('zu-top-add-question')
print(que)
  ♦顯式等待

  指定一個節點,設置最長等待時間。如果規定的時間內加載出來了,就返回要查找的節點;超出時間則拋出異常。  

# 9.2顯式等待
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.support.wait import WebDriverWait


browser = webdriver.Chrome(executable_path=r'D:\Google\Chrome\Application\chromedriver')
browser.get('https://www.taobao.com/')
wait = WebDriverWait(browser, 10)
su = wait.until(EC.presence_of_element_located((By.ID, 'q')))  # 等待條件,節點出現
button = wait.until(EC.element_to_be_clickable((By.CSS_SELECTOR, '.btn-search')))  # 等待條件,按鈕可以點擊
print(su, button)

  運行結果:

<selenium.webdriver.remote.webelement.WebElement (session="69f58b354be01e63e367e29756e64f18", element="0.005030458042517338-1")> <selenium.webdriver.remote.webelement.WebElement (session="69f58b354be01e63e367e29756e64f18", element="0.005030458042517338-2")>

  如果10秒內沒有加載成功,就會拋出TimeoutException異常。

10.窗口管理

  瀏覽器訪問網頁時會開啟一個個窗口,我們也可以使用Selenium對多個窗口進行操作。

# 10.窗口管理
import time
from selenium import webdriver


browser = webdriver.Chrome(executable_path=r'D:\Google\Chrome\Application\chromedriver')
browser.get('http://www.baidu.com')
browser.execute_script('window.open()')
print(browser.window_handles)
browser.switch_to.window(browser.window_handles[1])
browser.get('https://www.taobao.com')
time.sleep(2)
browser.switch_to.window(browser.window_handles[0])
browser.get('https://www.zhihu.com/explore')

  window.open()開啟新窗口,windo_handlers獲取當前開啟的所有窗口,返回的是窗口代號的列表。使用switch_to.window()切換窗口。

  先訪問百度,然后打開新窗口,再訪問淘寶,最后切換回正在訪問百度的第一個窗口,接着訪問知乎。

11.異常處理

  使用Selenium過程難免會出現異常,例如超時,節點為找到等。一旦出現異常,程序便不會運行了。使用try except語句來捕獲異常:

# 11.異常處理
from selenium import webdriver
from selenium.common.exceptions import TimeoutException, NoSuchElementException


browser = webdriver.Chrome(executable_path=r'D:\Google\Chrome\Application\chromedriver')
browser.get('http://www.baidu.com')
try:
    browser.find_element_by_class_name('hello')
except TimeoutException:
    print('Time out')
try:
    browser.find_element_by_class_name('hello')
except NoSuchElementException:
    print('No Element')
finally:
    browser.close()

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM