動(dòng)態(tài)頁面的生成有很多種,常見的有兩種:
- 一種是直接通過Ajax返回的數(shù)據(jù)來顯示.對(duì)于這種,我們可以直接通過分析Ajax的接口來使用requests或者urllib等包直接來獲取接口傳輸?shù)臄?shù)據(jù),
- 另外一種是返回的數(shù)據(jù)在頁面上再進(jìn)行加工后才顯示的數(shù)據(jù),這種數(shù)據(jù)往往是通過js進(jìn)行各種復(fù)雜的計(jì)算得到的也是一種很常見的加密方式,通過requests并不能直接獲取
針對(duì)上面說的一種情況我們會(huì)在另一篇文章中詳細(xì)介紹,這里我們討論第二種,通過前端js加密的數(shù)據(jù)如何獲取,當(dāng)然我們可以直接分析他們的js來讀懂整個(gè)網(wǎng)站的js但是這需要很大的功夫去了解一個(gè)網(wǎng)站,對(duì)于一個(gè)大型網(wǎng)站可能網(wǎng)站的人員都不一定能全部理解整個(gè)網(wǎng)站的js加密方式. 對(duì)于我們爬蟲來說還有另外一種非常強(qiáng)大的可見即可爬的方式---selenium
selenium
這是一款自動(dòng)化測(cè)試工具,可以驅(qū)動(dòng)瀏覽器(有界面,無界面)來執(zhí)行特定的操作,可以模仿人的點(diǎn)擊下拉等各種基本操作,對(duì)于js加密的信息的抓取非常有效
安裝
這里我們會(huì)寫一篇詳細(xì)的安裝教程大家可以先搜索相關(guān)教程這里我們需要selenium 即可
selenium的大體功能演示
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
browser = webdriver.Firefox() # 創(chuàng)建一個(gè)瀏覽器對(duì)象,這里還可以使用chrome等瀏覽器
try:
browser.get('https://www.baidu.com')# 打開百度的網(wǎng)頁
input = browser.find_element_by_id('kw') # 找到id為kw的元素
input.send_keys('Python') # 給這個(gè)元素傳遞一個(gè)值'Python'
input.send_keys(Keys.ENTER) # 使用鍵盤的enter鍵
wait = WebDriverWait(browser,10) # 瀏覽器等待10s
wait.until(EC.presence_of_all_elements_located((By.ID,'content_left'))) # 等待直到出現(xiàn)'content_left'
print(browser.current_url) # 輸出瀏覽器當(dāng)前的url
print(browser.get_cookies()) # 輸出cookie
print(browser.page_source) # 輸出網(wǎng)頁的當(dāng)前源碼
finally:
browser.close() # 關(guān)閉瀏覽器
運(yùn)行代碼會(huì)發(fā)現(xiàn)火狐瀏覽器被啟動(dòng)然后自動(dòng)打開了百度的網(wǎng)頁然后在搜索框中輸入了 Python(如果看不清楚可以手動(dòng)添加time模塊進(jìn)行暫停觀察) 然后按下了回車鍵進(jìn)行搜索,顯示結(jié)果(同上看不清楚可以添加time模塊)然后關(guān)閉,在我們的終端顯示了很多內(nèi)容截取其中一點(diǎn)如下:
https://www.baidu.com/s?ie=utf-8&f=8&rsv_bp=0&rsv_idx=1&tn=baidu&wd=Python&rsv_pq=ef704a420000296f&rsv_t=da9d9XB5i%2Fps1vejnUbOp0RAAdpd4K6q%2BkAH7Cem%2FPrpHtStgPgxtv8ta7E&rqlang=cn&rsv_enter=1&rsv_sug3=6&rsv_sug2=0&inputT=242&rsv_sug4=242
[{'name': 'BAIDUID', 'value': '590E5CC2557B638BFA8336815259E51A:FG=1', 'path': '/', 'domain': '.baidu.com', 'expiry': 3682926116, 'secure': False, 'httpOnly': False}, {'name': 'BIDUPSID', 'value': '590E5CC2557B638BFA8336815259E51A', 'path': '/', 'domain': '.baidu.com', 'expiry': 3682926116, 'secure': False, 'httpOnly': False}, {'name': 'PSTM', 'value':
...
我們可以去瀏覽器中取對(duì)比發(fā)現(xiàn)這個(gè)和瀏覽器的數(shù)據(jù)是一樣的.也就是我們可以利用selenium來獲取網(wǎng)頁內(nèi)容,selenium就是我們?cè)O(shè)定的爬蟲,它按照我們給它設(shè)定的規(guī)則控制瀏覽器并讀取瀏覽器里的內(nèi)容.真正做到了可見即可爬.
操控步驟
- 創(chuàng)建瀏覽器對(duì)象
- 訪問頁面
- 查找需要的內(nèi)容
- 關(guān)閉瀏覽器
- 創(chuàng)建瀏覽器對(duì)象
我們可以利用創(chuàng)建完成的對(duì)象進(jìn)行各種操作
from selenium import webdriver
browser = webdriver.Chrome()
browser = webdriver.Firefox()
browser = webdriver.Edge()
browser = webdriver.PhantomJS()
browser = webdriver.Safari()
- 訪問頁面
使用get()方法來請(qǐng)求網(wǎng)頁,這里只需要傳入一個(gè)url即可.比如我們想訪問我們這個(gè)文章我們可以在上面代碼的基礎(chǔ)上運(yùn)行一下代碼
url = 'https://www.jianshu.com/p/9b36413506c7'
browser.get(url)
這里我們就可以打開我們指定的網(wǎng)頁,用起來非常方便.
- 查找節(jié)點(diǎn)
selenium 瀏覽器對(duì)象提供了很多方法供我們使用用來選擇節(jié)點(diǎn)信息.
find_element_by_id
find_element_by_name
find_element_by_xpath
find_element_by_link_text
find_element_by_tag_name
find_element_by_class_name
find_element_by_css_selector
eg:
browser.get('https://www.baidu.com')
login_button = driver.find_element_by_link_text('登錄')
這里還提供一個(gè)通用的方法:
find_element(By.ID,id) # 它需要兩個(gè)值,一個(gè)是查找方式,另外一個(gè)這是查找值
如果是多個(gè)值的話,我們可以使用find_elements_by 這樣的函數(shù)來進(jìn)行查找,也就是上面說的方法在element后面加上一個(gè)s對(duì)于通用的方法同樣的適用:
find_elements(By.ID,id)
- 節(jié)點(diǎn)交互
這里可以使用.click() send_keys() clear()等方法來模擬用戶的點(diǎn)擊,輸入,清空等操作
- 獲取節(jié)點(diǎn)信息
當(dāng)我們使用selecet_element方法以后會(huì)返回一個(gè)WebElement對(duì)象,這個(gè)類型提供給我們了很多節(jié)點(diǎn)信息的方法.
- 獲取屬性:
get_attribute()
eg:
login_button.get_attribute('class)
- 獲取文本值
每個(gè)WebElement都有text屬性通過這個(gè)方法我們可以提取標(biāo)簽的文本內(nèi)容
- 獲取id,位置,標(biāo)簽名和大小
WebElememt 節(jié)點(diǎn)還提供了一下其他的屬性:
id,location, tag_name, size ....這是比較常用的,具體的我們可以查看官方文檔
- 切換Frame
網(wǎng)頁中有一種節(jié)點(diǎn)是iframe,相當(dāng)于Frame,當(dāng)我們遇到這樣的頁面后可以使用switch_to.frame()來進(jìn)行切換,這里需要傳入一個(gè)參數(shù): 另外一個(gè)frame的名字
- 延時(shí)等待
在網(wǎng)頁中經(jīng)常會(huì)由于ajax等操作這會(huì)導(dǎo)致網(wǎng)頁延時(shí)才能加載出來,所以我們需要等待一定的時(shí)間,確保所有的節(jié)點(diǎn)都已經(jīng)加載出來了.
- 隱式等待
當(dāng)我們使用implicitly_wait()方法的時(shí)候也就是在執(zhí)行的時(shí)候,如果selenium沒有找到節(jié)點(diǎn),將會(huì)繼續(xù)等待,等待到我們給出的時(shí)間后再去查找一次,如果還是沒有出現(xiàn),將會(huì)拋出異常.
- 顯示等待
當(dāng)selenium在查找節(jié)點(diǎn)的時(shí)候如果,在規(guī)定的時(shí)間內(nèi)加載出來了這個(gè)節(jié)點(diǎn)就返回查找的節(jié)點(diǎn),如果到了規(guī)定的時(shí)間依舊沒有加載該節(jié)點(diǎn),就會(huì)拋出異常.
關(guān)于等待還有很多:
等待條件 |
含義 |
title_is |
標(biāo)題是某內(nèi)容 |
title_contains |
標(biāo)題包含某內(nèi)容 |
presence_of_element_located |
節(jié)點(diǎn)加載出來,傳入定位元祖,比如(By.ID,'p') |
visibiltiy_of_element_located |
節(jié)點(diǎn)可見,傳入定位元組 |
visiblity_of |
可見傳入節(jié)點(diǎn)對(duì)象 |
presence_of_all_elements_located |
所有節(jié)點(diǎn)加載出來 |
text_to_be_present_in_element |
某個(gè)節(jié)點(diǎn)文本包含某些文字 |
text_to_be_present_in_element_valve |
某個(gè)節(jié)點(diǎn)包含某個(gè)文字 |
frame_to_be_available_and_switch_to_it |
加載并切換 |
invisibility_of_element_located |
節(jié)點(diǎn)不可見 |
element_to_be_clickable |
節(jié)點(diǎn)可點(diǎn)擊 |
staleness_of |
判斷一個(gè)節(jié)點(diǎn)是否仍在DOM, 可判斷頁面是否已經(jīng)刷新 |
aert_is_present |
是否出現(xiàn)警告 |
前進(jìn)和后退
back() 和forward()方法可實(shí)現(xiàn)瀏覽器的后退和前進(jìn)功能
Cookies
可以對(duì)cookie進(jìn)行獲取,添加,刪除等操作
.get_cookie()
.delete_all_cookie()
.add_cookie({})
選項(xiàng)卡
browser.switch_to_window 可以切換選項(xiàng)卡
import time
from selenium import webdriver
browser = webdriver.Firefox()
browser.get('https://www.baidu.com')
browser.exexute_script('window.open()')
browser.switch_to_window(broser.window_hadles[1])
browser.get('https://www.taobao.com')
time.sleep(1)
browser.switch_to_window(browser.window_handles[0])
browser.get('https://www.')
11.異常的處理
可以使用try...except 來捕獲異常
|