JavaScript動態渲染頁面,他的分頁部分有js生成,並不是原始的HTML代碼css
如淘寶使用request只能請求到頁面大體框架,沒法拿到商品數據,或部分網站換頁時url不發生變化。html
或者使用Ajax開發的網站(現在日頭條),他的接口有不少加密處理(搜索信息後信息URL通過加密處理,很難找到規律)python
Python中提供了不少模擬瀏覽器的庫,selenium ,pyV8等,來解決動態渲染的頁面。web
selenium是一個自動化測試工具,利用它能夠驅動瀏覽器執行特定的動做,如點擊、下拉等操做。同時也能夠獲取瀏覽器當前呈現的頁面渲染,作到可見便可爬。用於動態頁面爬取(通過js渲染的頁面)ajax
以谷歌瀏覽器爲例,瞭解selenium的使用chrome
須要安裝好谷歌瀏覽器,並配置好ChromeDriverapi
先去谷歌瀏覽器看版本,下載Chromedriver:http://chromedriver.storage.googleapis.com/index.html瀏覽器
配置環境變量:將下載好的可執行文件放入python的Scripts目錄下,添加至環境變量網絡
驗證:在cmd中執行ChromeDriver,會返回版本號session
解決安裝報錯問題:https://blog.csdn.net/ever_peng/article/details/80089095
from selenium import webdriver brower = webdriver.Chrome() #打開一個新的Crome頁面則環境配置成功
from selenium import webdriver#用於打開瀏覽器 from selenium.webdriver.support.wait import WebDriverWait#用於設置等待時間 from selenium.webdriver.common.keys import Keys#用於按鍵操做 from selenium.webdriver.common.by import By#用於匹配節點 from selenium.webdriver.support import expected_conditions as EC#用於等待時判斷節點是否加載,若是沒有,繼續在規定的時間加載 #打開谷歌瀏覽器 brower = webdriver.Chrome() try: #請求百度網站 brower.get('https://www.baidu.com') #獲取ID屬性爲kw的節點,用於輸入要搜索的信息 input = brower.find_element_by_id('kw') #在搜索框輸入python input.send_keys('python') input.send_keys(Keys.ENTER)#keys是獲取鍵盤的按鍵至關於一個回車操做 wait = WebDriverWait(brower,10)#等待頁面加載 #判斷頁面是否響應到id屬性爲content_left的內容 #寫的時候是以元組形式 注意括號的個數 wait.until(EC.presence_of_element_located((By.ID, 'content_left'))) finally: #關閉瀏覽器 #brower.close() pass
selenium支持多種瀏覽器,如chrome Firefox 也支持無界面的瀏覽器,如PhantomJS
from selenium import webdriver brower = webdriver.Chrome()#谷歌 brower = webdriver.Firefox ()#火狐 brower = webdriver.PhantomJS()#phantomJS #完成瀏覽器對象的初始化並將其賦值爲brower這個對象。由此調用broweer對象,讓瀏覽器執行對應的操做。
使用get()方法來請求網頁,參數傳輸連接url便可,如get方法訪問淘寶頁面,打印源代碼
from selenium import webdriver brower = webdriver.Chrome() brower.get('https://www.taobao.com') #獲取響應到的網頁源碼 print(brower.page_source)
selenium能夠驅動瀏覽器完成各類操做,如填充表格、模擬點擊等操做,如向某個輸入框輸入文本操做
根據xpath css選擇器進行選擇
#獲取id屬性爲「q」的節點 input_1 = brower.find_element_by_id('q') input_2 = brower.find_element_by_css_selector('#q') input_3 = brower.find_element_by_xpath('//*[@id='q']') print(input_1) print(type(input_1)) #<selenium.webdriver.remote.webelement.WebElement (session="af859fdfb659b14f954adaec944bb0ef", element="0.7941017431137989-1")> #<class 'selenium.webdriver.remote.webelement.WebElement'> 返回結果爲webElement類型
全部獲取單個節點的方法
browser.find_element_by_id browser.find_element_by_name browser.find_element_by_class_name #使用class_name匹配節點時,若是該節點class屬性有多個值時,只須要用其中一個值進行匹配,多個值同時匹配則產生異常 browser.find_element_by_tag_name browser.find_element_by_link_text browser.find_element_by_css_selector browser.find_element_by_xpath
此外,selenium還提供了通用方法find_element()
他須要傳入兩個參數,查找方式By和值,實際爲browser.find_element_by_id()的通用方法
browser.find_element(By.ID, 'q')
from selenium.webdriver.common.by import By browser.find_element(By.ID, 'q')
要匹配多個節點時使用find_element()只能獲取到一個節點,因此此時須要find_elements()方法,兩個之間的區別爲匹配多個節點時要用elements
selenium能夠驅動瀏覽器作一系列操做,常見的send_keys()方法,清空文字是使用clear()方法,點擊按鈕click()
練習:使用selenium請求京東,在搜索框輸入榮耀20,而後等頁面加載出內容後,睡眠3秒,再去搜索華爲p30 節點.clear() 節點.click() 節點.send_keys() from selenium.webdriver.support.wait import WebDriverWait from selenium.webdriver.common.keys import Keys from selenium import webdriver import time brower = webdriver.Chrome() try: brower.get('https://www.jd.com/') input = brower.find_element_by_id('key') input.send_keys('榮耀20') input.send_keys(Keys.ENTER) #按鈕操做 #button = brower.find_element+by_class_name('button') wait = WebDriverWait(brower,3)#等待頁面加載 time.sleep(3) print('3秒後') input = brower.find_element_by_id('key') input.clear() input.send_keys('榮耀P30') input.send_keys(Keys.ENTER) finally: pass 若是class屬性裏面有兩個值,中間用空格隔開,用class_name匹配節點的時候只須要匹配其中一個,多了是找不到的
經過page_source屬性能夠獲取網頁源代碼,接着可使用解析庫(如正則,bs4等)來提取信息。
selenium也提供了節點選擇方法,返回webElement類型,能夠經過一些方法提取節點屬性、文本等。
可使用get_attribute()方法來獲取節點的屬性,前提去先選中節點。
#獲取貓眼網的圖片連接 from selenium import webdriver brower = webdriver.Chrome() brower.get('https://maoyan.com/board/4') input_2 = brower.find_elements_by_xpath('//img[@class="board-img"]')#注意這裏是elements print(type(input_2)) for i in input_2: print(i.get_attribute('data-src'))
每個web element對象都有一個text屬性,經過該屬性能夠獲取節點的文本信息
#獲取top100電影名稱 name = browser.find_elements_by_xpath( '//p[@class="name"]/a') print(len(name)) for i in name: print(i.text)
selenium中get()方法會在網頁框架加載結束後執行,此時若是獲取page_source獲取網頁源碼可能獲得結果不是瀏覽器徹底加載後的頁面內容。
若是一些頁面有額外的ajax請求,則在此處須要延時等待一段時間,確保信息已經加載出來。
延時等待分爲:顯式等待和隱式等待
使用隱式等待的時候,若是selenium沒有在DOM中找到節點將繼續等待,直到超時設定時間後拋出timeout異常,默認時間爲0,以秒爲單位。
from selenium import webdriver brower = webdriver.Chrome() brower.implicitly_wait(10) brower.get('url')
獲取淘寶首頁內容,查看設置延時等待與不設置響應的內容是不是一致的
若是有延時等待,則程序在get()請求後開始在延時時給定的時間內加載數據,同時匹配網頁內容。
from selenium import webdriver browser = webdriver.Chrome() browser.implicitly_wait(20) browser.get('https://www.taobao .com/') #獲取信息 # print(browser.page_source) print(len(browser.find_elements _by_xpath('//h4[@class="aall"]'))) browser.close()
隱式等待效果通常,由於只規定了固定的時間,而頁面加載信息時間會受到網絡條件影響
顯式等待它指定要查找的內容,而後指定時間進行等待。若是在規定時間加載到這個節 點則返回查找的節點,若是在規定時間依然沒有加載到該節點數據,則拋出異常
#將下拉條從頂部拖拽到中間位置 brower.execute_script('window.scrollTo(0,document.body.scrollHeight/2)')
使用back()昂發進行後退,使用forward()方法進行前進
from selenium import webdriver import time browser=webdriver.Chrome() browser.get('https://www.baidu.com/') browser.get('https://www.taobao.com/') browser.get('https://www.jd.com/') browser.back() time.sleep(10) browser.forward()
from selenium.common.exceptions import TimeoutException #導入異常 try : pass except TimeoutException: pass finally: pass