我用 Selenium 爬了京東商城,結(jié)果……

文 | 極光
來源:Python 技術(shù)「ID: pythonall」
今天跟大家一起學(xué)習(xí)下 Python 如何使用 Selenium 進(jìn)行自動化操作網(wǎng)頁。
如何加載元素
眾所周知現(xiàn)在的網(wǎng)站,頁面內(nèi)容非常復(fù)雜,而且加載的內(nèi)容種類繁多,所以加載時間就會比較長。平時我們看到的大部分網(wǎng)站頁面都做了優(yōu)化,比如 baidu.com,或者 jd.com,但為了提升頁面打開速度,他們又都采用了不同的方案:
百度首頁采用了極簡的方式,讓自己搜索首頁盡量加載少量的內(nèi)容,以提高打開頁面的速度。
京東首頁則不可能采用百度那樣的方案,因?yàn)闃I(yè)務(wù)方向不同,京東作為電商需要給客戶展示盡量多的內(nèi)容,所以它采用了延時加載的方式,也就是先加載用戶能看到的內(nèi)容,然后再慢慢加載那些用戶不能直觀看到的內(nèi)容,從而大大提高了頁面打開的速度。
上次我們用 selenium 寫了個爬取京東商城搜索出來的 ps5國行 的產(chǎn)品名稱和價格,在這里把代碼再放出來看下。
# 導(dǎo)入庫
from selenium import webdriver
import time
# executable_path 用于指定driver存放路徑
browser = webdriver.Chrome(executable_path='/Users/xx/python/chromedriver')
# 打開京東官網(wǎng)
browser.get('https://www.jd.com/')
# browser.find_element_by_id("kw").send_keys("python selenium")
# 獲取輸入框?qū)ο?/span>
search = browser.find_element_by_xpath('//*[@id="key"]')
# 輸入想要搜索的關(guān)鍵詞,如"ps5國行"
search.send_keys('ps5國行')
# 獲取搜索按鈕對象并單擊
browser.find_element_by_xpath('//*[@id="search"]/div/div[2]/button').click()
# 將滾動條移動到頁面底部,用于加載所有信息
javascript = "var q=document.documentElement.scrollTop=50000"
# 執(zhí)行 javascript 移動滾動條
browser.execute_script(javascript)
# 等待3秒,有些異步加載的數(shù)據(jù)加載慢
time.sleep(3)
# 通過查看頁面源碼得到金額的 xpath 路徑,并獲取金額
prices = browser.find_elements_by_xpath('//*[@id="J_goodsList"]/ul/li/div/div[2]/strong/i')
# 通過查看頁面源碼得到商品標(biāo)題的 xpath 路徑,并獲取商品標(biāo)題
names = browser.find_elements_by_xpath('//*[@id="J_goodsList"]/ul/li/div/div[3]/a/em')
# 遍歷打印出當(dāng)前頁所有標(biāo)題和金額
for name,price in zip(names,prices):
print(name.text.replace('\n',''),price.text)
#退出瀏覽器
browser.quit()
元素等待
上面代碼中,在搜索完成后,我們只看到第一頁內(nèi)容,其實(shí)還沒在屏幕上展示的內(nèi)容是沒有加載的,這樣我們就沒辦法獲取所有搜索出的產(chǎn)品信息。
這里就需要我先用 selenium 操作滾動條,將滾動條移動到頁面底部,用于加載所有信息,這時你會發(fā)現(xiàn),產(chǎn)品信息不會立刻加載出來,還需要等待幾秒鐘,當(dāng)然等多久主要還是看網(wǎng)速。
在這里我設(shè)置的是等待 3 秒,調(diào)用了 time.sleep(3) 方法來實(shí)現(xiàn)。
強(qiáng)制等待
強(qiáng)制等待是一種簡單又粗暴的方式,也就是強(qiáng)制將進(jìn)程暫停,等待參數(shù)傳入的相應(yīng)時間。比如我們上面用的 time.sleep(3),它不會管你頁面是否已經(jīng)加載完,都會等 3 秒的時間。
如果 3 秒后內(nèi)容加載完了還好,如果沒有加載完,它也不會再等了,直接開始執(zhí)行下面的代碼,所以經(jīng)常會遇到不可預(yù)知的問題。
這種方式主要用來簡單調(diào)試代碼時使用,平時非常不建議使用。
隱式等待
隱式等待也叫隱性等待,跟強(qiáng)制等待最大的不同就是,隱性等待可以實(shí)現(xiàn)智能等待,只要設(shè)置一個最大等待時間,在這個時間內(nèi)網(wǎng)頁內(nèi)容只要加載完成就可以立即進(jìn)行后續(xù)操作,不需要再等到最大時間。
# 導(dǎo)入庫
from selenium import webdriver
import time
# executable_path 用于指定driver存放路徑
browser = webdriver.Chrome(executable_path='/Users/xx/python/chromedriver')
# 隱性等待最長等20秒
driver.implicitly_wait(20)
# 打開京東官網(wǎng)
browser.get('https://www.jd.com/')
#退出瀏覽器
browser.quit()
不過使用隱性等待有幾點(diǎn)需要注意:
如果等待到最大時間,網(wǎng)頁還沒有加載完成,那依然還會繼續(xù)執(zhí)行下一步操作。
這里指的網(wǎng)頁加載完成,是指瀏覽器的加載頁面狀態(tài)顯示完成(也就是加載的小圈不再轉(zhuǎn)),實(shí)際使用中經(jīng)常會遇到大部分內(nèi)容都加載完了,但有少量 js 腳本一直加載中,導(dǎo)致整個頁面狀態(tài)還是加載中,這時就會仍需要等待 20 秒才會執(zhí)行下一步操作。
跟
sleep()方法不同,隱式等待方法implicitly_wait(20)設(shè)置一次后是全局有效的,也就是在整個 driver 的周期都起作用,不用每個操作前都設(shè)置一遍。
那這些問題有沒有解決方法?或者有沒有其他更好的方法實(shí)現(xiàn)元素等待?當(dāng)然有,那就是顯式等待。
顯式等待
顯式等待其實(shí)就是 wait 模塊下的 WebDriverWait 類對象,通過 until() 方法和 until_not() 方法實(shí)現(xiàn)元素等待。
until():當(dāng)某個元素加載完成,或者其他設(shè)置的條件成立,則會繼續(xù)執(zhí)行后續(xù)操作。如果還不滿足條件,則會間隔一定時間檢測一下條件是否成立,直到達(dá)到設(shè)置的最大時間,最后拋出異常 TimeoutException。
until_not():跟 until() 方法相反,當(dāng)判斷某個元素,或者某個條件不成立時,才會繼續(xù)執(zhí)行下一步操作。
# 方法參數(shù)說明
WebDriverWait(driver, 超時時間, 頻率, 忽略異常).until(可執(zhí)行的方法, 超時會返回信息內(nèi)容)
下面我們來看這段代碼
# 導(dǎo)入庫
from selenium import webdriver
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as ECS
from selenium.webdriver.common.by import By
import time
# executable_path 用于指定driver存放路徑
browser = webdriver.Chrome(executable_path='/Users/xx/python/chromedriver')
# 打開京東官網(wǎng)
browser.get('https://www.jd.com/')
# 定位要查找的元素
loc = (By.LINK_TEXT, "打開")
try:
# 等待5秒,直到發(fā)現(xiàn)元素
WebDriverWait(driver, 5).until(ECS.presence_of_element_located(loc))
except:
# 沒有發(fā)現(xiàn)元素則會打印提示
print("沒有找到對應(yīng)元素!")
finally:
# 發(fā)現(xiàn)元素則執(zhí)行下面的方法
driver.find_element_by_link_text('打開').click()
#退出瀏覽器
browser.quit()
使用 WebDriverWait 調(diào)用可執(zhí)行方法,除了可定位的元素,還可以使用 selenium 提供的 expected_conditions 模塊中的各種條件,也可以使用 WebElement 的 is_enabled(),is_selected(),is_displayed() 等等方法。
總結(jié)
好了,今天我們又介紹了下 selenium 元素加載時的三種等待方法,以及等待方法的優(yōu)缺點(diǎn),在使用場景下該如何操作等。并寫了一些簡單例子,給大家學(xué)習(xí)參考,后續(xù)還會為大家介紹更多。OK,今天就聊這些,如果你喜歡記得點(diǎn) 在看。

上期送書中獎名單來咯,速來圍觀~






恭喜以上六位中獎的童鞋,快加小編微信(Mayyy530),憑中獎截圖來領(lǐng)獎!先到先選哦~
兌獎截止時間:9月3日16:00整
往期推薦
1、10 個“瘋狂”的 Python 項(xiàng)目創(chuàng)意(文末送書)
1、10 個“瘋狂”的 Python 項(xiàng)目創(chuàng)意(文末送書)
今天因?yàn)槟狞c(diǎn)贊和在看,讓我元?dú)鉂M滿!
