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

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

上期送書中獎(jiǎng)名單來咯,速來圍觀~






恭喜以上六位中獎(jiǎng)的童鞋,快加小編微信(Mayyy530),憑中獎(jiǎng)截圖來領(lǐng)獎(jiǎng)!先到先選哦~
兌獎(jiǎng)截止時(shí)間:9月3日16:00整
往期推薦
1、10 個(gè)“瘋狂”的 Python 項(xiàng)目創(chuàng)意(文末送書)
2、視頻剪輯什么鬼?Python 帶你高效創(chuàng)作短視頻
4、找不到阿里云盤資源?趕緊收藏這個(gè)福利網(wǎng)站!
5、Edge瀏覽器大翻車:頁(yè)面出現(xiàn)無法關(guān)閉的“中國(guó)特供版”廣告,網(wǎng)友炸了
1、10 個(gè)“瘋狂”的 Python 項(xiàng)目創(chuàng)意(文末送書)
2、視頻剪輯什么鬼?Python 帶你高效創(chuàng)作短視頻
4、找不到阿里云盤資源?趕緊收藏這個(gè)福利網(wǎng)站!
5、Edge瀏覽器大翻車:頁(yè)面出現(xiàn)無法關(guān)閉的“中國(guó)特供版”廣告,網(wǎng)友炸了
今天因?yàn)槟狞c(diǎn)贊和在看,讓我元?dú)鉂M滿!
