1. 程式人生 > >Python3+Selenium爬取動態網頁資料

Python3+Selenium爬取動態網頁資料

背景:

有時候想獲取網頁的資訊,然後下載裡面的圖片資料等等

遇到的問題:

有時一些網頁是動態的,一些內容是通過js非同步拉取,甚至拉取時間是懶載入的,例如滾動到元素位置的時候才載入

解決方案:

這個時候就需要Selenium神器了

Selenium 是什麼?一句話,自動化測試工具。它支援各種瀏覽器,包括 Chrome,Safari,Firefox 等主流介面式瀏覽器,如果你在這些瀏覽器裡面安裝一個 Selenium 的外掛,那麼便可以方便地實現Web介面的測試。換句話說叫 Selenium 支援這些瀏覽器驅動。

PS:PhantomJS不也是一個瀏覽器嗎, Selenium 支援是肯定的,這樣二者便可以實現無縫對接了實現 ,PhantomJS是一個無介面的瀏覽器物件,為什麼不直接用瀏覽器而用一個沒介面的 PhantomJS 呢?答案是:效率高啊! 這樣構成了一完美的爬取流程:
Python+PhantomJS+Selenium 爬蟲三劍客


PhantomJS 用來渲染解析JS
Selenium 用來驅動以及與 Python 的對接,
Python 進行後期的處理

我們這裡單Selenium拎出來講,
簡介:http://www.51testing.com/zhuanti/webdriver.htm
官網:https://www.seleniumhq.org/docs/index.jsp
文件:https://selenium-python.readthedocs.io/index.html

實踐:

安裝

pip3 install selenium

你也可以下載原始碼安裝,下載後執行

python3 setup.py install

使用:

from selenium import webdriver
 
browser = webdriver.Chrome()
browser.get('http://www.baidu.com/')
html = driver.page_source

執行後會啟動瀏覽器
需要安裝瀏覽器驅動
https://sites.google.com/a/chromium.org/chromedriver/downloads
下載後把chromedriver放到/usr/local/bin

sudo mv /Users//Downloads/chromedriver /usr/local/bin

driver.get 方法會開啟請求的URL,WebDriver 會等待頁面完全載入完成之後才會返回,
即程式會等待頁面的所有內容載入完成,JS渲染完畢之後才繼續往下執行。注意:如果這裡用到了特別多的 Ajax 的話,程式可能不知道是否已經完全載入完畢。
page_source獲取網頁原始碼

懶載入動態頁面
有一些網頁,元素可能是需要滾動到特定位置才載入的,這種就需要設定一個等待時間來等待頁面元素出現才返回
這裡可以使用顯示等待WebDriverWait

from selenium import webdriver
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC

#顯式等待,直到offer-template-0出現
driver = webdriver.Chrome()
driver.get(url)

#滾動到某元素
target = driver.find_element_by_id('desc-lazyload-container')
driver.execute_script("arguments[0].scrollIntoView();", target)

try:
    WebDriverWait(driver, 10).until(
        EC.presence_of_element_located((By.ID, "offer-template-0"))
    )
except:
    driver.quit()    
    
html = driver.page_source

其中,presence_of_element_located是一個等待條件
下面是一些內建的等待條件,你可以直接呼叫這些條件,而不用自己寫某些等待條件了。

title_is
title_contains
presence_of_element_located
visibility_of_element_located
visibility_of
presence_of_all_elements_located
text_to_be_present_in_element
text_to_be_present_in_element_value
frame_to_be_available_and_switch_to_it
invisibility_of_element_located
element_to_be_clickable – it is Displayed and Enabled.
staleness_of
element_to_be_selected
element_located_to_be_selected
element_selection_state_to_be
element_located_selection_state_to_be
alert_is_present

頁面操作
這裡使用到find_element_by_id的頁面操作來獲取元素,例如:

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']")

然後通過

driver.execute_script("arguments[0].scrollIntoView();", target)

注入js,滾動到元素位置(懶載入)

我們還可以對元素執行其他模擬操作
獲取了元素之後,下一步當然就是向文字輸入內容了,可以利用下面的方法

element.send_keys("some text")

同樣你還可以利用 Keys 這個類來模擬點選某個按鍵。

element.send_keys("and some", Keys.ARROW_DOWN)

你可以對任何獲取到到元素使用 send_keys 方法,就像你在 GMail 裡面點擊發送鍵一樣。不過這樣會導致的結果就是輸入的文字不會自動清除。所以輸入的文字都會在原來的基礎上繼續輸入。你可以用下面的方法來清除輸入文字的內容。

element.clear()

這樣輸入的文字會被清除。

最後,爬取到最終完整的html後,就可以靠BeautifulSoup等工具繼續解析了