Python網絡爬蟲——Selenium庫

目錄

1 Ajax和動態HTML

1.1 用Selenium執行JavaScript

1.2  Selenium 的選擇器

1.3  隱式等待

          XPATH語法

1.4 處理重定向


1 Ajax和動態HTML

如果提交表單之後,網站的頁面不需要重新刷新,那麼你訪問的網站就在用 Ajax 技術。Ajax 其實並不是一門語言,而是用來完成網絡任務(可以認爲它與網絡數據採集差不多)的一系列技術。Ajax 全稱是 Asynchronous JavaScript and XML(異步 JavaScript 和 XML),網站不需要使用單獨的頁面請求就可以和網絡服務器進行交互(收發信息)。

和 Ajax 一樣,動態 HTML(dynamic HTML,DHTML)也是一系列用於解決網絡問題的技術集合。DHTML 是用客戶端語言改變頁面的 HTML 元素。

1.1 用Selenium執行JavaScript

Selenium(http://www.seleniumhq.org/)是一個強大的網絡數據採集工具。Selenium 可以讓瀏覽器自動加載頁面,獲取需要的數據,甚至頁面截屏,或者判斷網站上某些動作是否發生。

https://pypi.org/simple/selenium/ 可以下載 Selenium 庫,可以使用 PhantomJS(http://phantomjs.org/download.html)結合在一起,就可以運行一個非常強大的網絡爬蟲。

from selenium import webdriver
import time

driver = webdriver.PhantomJS(executable_path='/phantomjs-1.9.8-macosx/bin/phantomjs')#自己程序的路徑
driver.get("http://pythonscraping.com/pages/javascript/ajaxDemo.html")
time.sleep(3)
print(driver.find_element_by_id('content').text)
driver.close()

這段代碼用 PhantomJS 庫創建了一個新的 Selenium WebDriver,首先用 WebDriver 加載頁面,然後暫停執行 3 秒鐘,再查看頁面獲取(希望已經加載完成的)內容。

1.2  Selenium 的選擇器

在這個例子中,我們用的選擇器是 find_element_by_id,下面的選擇器也可以獲取同樣的結果:

driver.find_element_by_css_selector("#content")
driver.find_element_by_tag_name("div")

選擇頁面上具有同樣特徵的多個元素,可以用 elements (換成複數)來返回一個 Python 列表:

driver.find_elements_by_css_selector("#content")
driver.find_elements_by_css_selector("div")

用 BeautifulSoup 來解析網頁內容,可以用 WebDriver 的 page_source 函數返回頁面的源代碼字符串。

pageSource = driver.page_source
bsObj = BeautifulSoup(pageSource)
print(bsObj.find(id="content").get_text())

1.3  隱式等待

隱式等待是等 DOM 中某個狀態發生後再繼續運行代碼;顯式等待明確設置了等待時間。在 Selenium庫裏面元素被觸發的期望條件(expected condition)有很多種,包括:

  • 彈出一個提示框
  • 一個元素被選中(比如文本框)
  • 頁面的標題改變了,或者某個文字顯示在頁面上或者某個元素裏
  • 一個元素在 DOM 中變成可見的,或者一個元素從 DOM 中消失了

大多數的期望條件在使用前都需要你先指定等待的目標元素。元素用定位器(locator)指定,定位器是一種抽象的查詢語言,用 By 對象表示,可以用於不同的場合,包括創建選擇器。

創建選擇器,配合 WebDriver 的 find_element 函數使用:

print(driver.find_element(By.ID, "content").text)
等同於 print(driver.find_element_by_id("content").text)

下面的程序用 id 是 loadedButton 的按鈕檢查頁面是不是已經完全加載:

from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC

driver = webdriver.PhantomJS(executable_path='/phantomjs-1.9.8-macosx/bin/phantomjs')
driver.get("http://pythonscraping.com/pages/javascript/ajaxDemo.html")
try:
    element = WebDriverWait(driver, 10).until(EC.presence_of_element_located((By.ID, "loadedButton")))
finally:
    print(driver.find_element_by_id("content").text)
    driver.close()

定位器通過 By 對象進行選擇的策略:

•  ID
在上面的例子裏用過;通過 HTML 的 id 屬性查找元素。

•  CLASS_NAME
通過 HTML 的 class 屬性來查找元素。

•  CSS_SELECTOR
通過 CSS 的 class 、 id 、 tag 屬性名來查找元素,用 #idName 、 .className 、 tagName
表示。

•  LINK_TEXT
通過鏈接文字查找 HTML 的 <a> 標籤。例如,如果一個鏈接的文字是“Next”,就可以
用 (By.LINK_TEXT, "Next") 來選擇。

•  PARTIAL_LINK_TEXT
與 LINK_TEXT 類似,只是通過部分鏈接文字來查找。

•  NAME
通過 HTML 標籤的 name 屬性查找。這在處理 HTML 表單時非常方便。

•  TAG_NAME
通過 HTML 標籤的名稱查找。

•  XPATH
用 XPath 表達式(語法在下面介紹)選擇匹配的元素。

XPATH語法簡介:

XPath(XML Path,XML 路徑)是在 XML 文檔中導航和選擇元素的查詢語言。它由W3C 於 1999 年創建,在 Python、Java 和 C# 這些語言中有時會用 XPath 來處理 XML文檔。

在 XPath 語法中有四個重要概念:

  • • 根節點和非根節點

♦/div 選擇 div 節點,只有當它是文檔的根節點時
♦//div 選擇文檔中所有的 div 節點(包括非根節點)

  • • 通過屬性選擇節點

♦//@href 選擇帶 href 屬性的所有節點
♦//a[@href='http://google.com'] 選擇頁面中所有指向 Google 網站的鏈接

  • • 通過位置選擇節點

♦//a[3] 選擇文檔中的第三個鏈接
♦//table[last()] 選擇文檔中的最後一個表
♦//a[position() < 3] 選擇文檔中的前三個鏈接

  • • 星號( * )匹配任意字符或節點,可以在不同條件下使用

♦//table/tr/* 選擇所有表格行 tr 標籤的所有的子節點(這很適合選擇 th 和 td 標籤)
♦//div[@*] 選擇帶任意屬性的所有 div 標籤

1.4 處理重定向

客戶端重定向是在服務器將頁面內容發送到瀏覽器之前,由瀏覽器執行 JavaScript 完成的頁面跳轉,而不是服務器完成的跳轉。服務器端重定向一般都可以輕鬆地通過 Python 的 urllib 庫解決,不需要使用 Selenium客戶端重定向。

Selenium 可以執行 JavaScript 重定向,我們可以用一種智能的方法來檢測客戶端重定向是否完成,首先從頁面開始加載
時就“監視”DOM 中的一個元素,然後重複調用這個元素直到 Selenium 拋出一個StaleElementReferenceException 異常;也就是說,元素不在頁面的 DOM 裏了,說明這時網站已經跳轉:

from selenium import webdriver
import time
from selenium.webdriver.remote.webelement import WebElement
from selenium.common.exceptions import StaleElementReferenceException

def waitForLoad(driver):
    elem = driver.find_element_by_tag_name("html")
    count = 0
    while True:
        count += 1
        if count > 20:
            print("Timing out after 10 seconds and returning")
            return
        time.sleep(.5)
        try:
            elem == driver.find_element_by_tag_name("html")
        except StaleElementReferenceException:
            return

driver = webdriver.PhantomJS(executable_path='/phantomjs-1.9.8-macosx/bin/phantomjs')
driver.get("http://pythonscraping.com/pages/javascript/redirectDemo1.html")
waitForLoad(driver)
print(driver.page_source)

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章