javascript
driver.get调用iframe中的页面_【5分钟玩转Lighthouse】爬取JavaScript动态渲染页面
0x00 背景概述
通過【技術(shù)干貨 007 | Scrapy爬蟲初探】教程,大家應(yīng)該已經(jīng)對如何編寫爬蟲有了一定的認(rèn)識。但對于較為復(fù)雜的網(wǎng)站設(shè)計(jì),比如網(wǎng)站頁面使用了JavaScript動態(tài)渲染,入門級的爬蟲就不太適用。
本文針對JavaScript動態(tài)渲染頁面,使用selenium+scrapy,爬取levels.fyi中微軟公司員工的信息和薪酬(示例頁面),目的在于講述JavaScript頁面如何進(jìn)行爬取,并將程序部署在騰訊云輕量服務(wù)器Lighthouse中。
0x01 服務(wù)器準(zhǔn)備
輕量應(yīng)用服務(wù)器(Lighthouse)是一種易于使用和管理、適合承載輕量級業(yè)務(wù)負(fù)載的云服務(wù)器,能幫助中小企業(yè)及開發(fā)者在云端快速構(gòu)建網(wǎng)站、博客、電商、論壇等各類應(yīng)用以及開發(fā)測試環(huán)境,并提供應(yīng)用部署、配置和管理的全流程一站式服務(wù)。
這里我們先選擇LAMP鏡像,選擇套餐后進(jìn)行支付,就擁有了屬于你的Lighthouse鏡像! (購買傳送門->)
0x02 頁面分析
levels.fyi中進(jìn)入開發(fā)者模式,可以看到待爬取的元素其實(shí)是一個iframe,數(shù)據(jù)由script腳本生成:
我們需要獲取tbody下的每一個tr,并選擇我們需要的數(shù)據(jù)
我們直接使用Request獲取tbody,會發(fā)現(xiàn)該元素下并沒有任何數(shù)據(jù):
t_body = response.css("table#compTable tbody").extract()print(t_body)下面,我們講解下如何成功的獲取javaScript生成的tbody數(shù)據(jù)
0x03 Selenium獲取
Selenium是一個web自動化工具,運(yùn)行在瀏覽器中,使用腳本模擬用戶對瀏覽器進(jìn)行操作。在本例中,本質(zhì)上是使用Selenium等待javascript加載完成后,再獲取數(shù)據(jù)。Selenium的安裝和配置非常簡單,腳本編寫也非常容易。而缺點(diǎn)在于,相比起其他爬取方式,Selenium的爬取速度相對較慢。
Selenium安裝:pip install selenium
瀏覽器驅(qū)動下載:使用Selenium需要下載瀏覽器驅(qū)動,推薦下載Chrome版本,下載完成后mac可以直接放在/usr/local/bin,Windows需要在腳本里配置下路徑或者配置環(huán)境變量
建立scrapy項(xiàng)目,新建MicrosoftSpider,并進(jìn)行簡單的配置,方法與【技術(shù)干貨 007 | Scrapy爬蟲初探】一樣。
獲取driver對象:
driver = webdriver.Chrome()使用WebDriverWait,等待頁面加載完成。在這里,我們設(shè)置超時(shí)時(shí)間為5秒:
wait = WebDriverWait(self.driver, 5) wait.until(lambda driver: driver.find_element_by_xpath('//*[@id="compTable"]/tbody/tr[1]')) # 等待第一行內(nèi)容加載完成wait結(jié)束后,獲取一下tbody中的第一行數(shù)據(jù)試試
tr1 = self.driver.find_element_by_xpath('//*[@id="compTable"]/tbody/tr[1]').text # 每一行信息 print(tr1)我們已經(jīng)成功獲取到第一行數(shù)據(jù)了!在上述代碼中,我們使用了find_element_by_xpath函數(shù)。這個函數(shù)是Selenium中獲取元素的函數(shù),返回的是WebElement類型,可以通過text獲取元素的文本
接下來,我們使用同樣的方法,獲取‘下一頁’按鈕,并點(diǎn)擊該按鈕:
wait = WebDriverWait(self.driver, 1) wait.until(lambda driver: driver.find_element_by_css_selector('li.page-item.page-next')) # 等待內(nèi)容加載完成 next_page = self.driver.find_element_by_css_selector('li.page-item.page-next a') next_page.click() # 模擬點(diǎn)擊下一頁next_page同樣是WebElement類型。可以看到,WebElement除了text等基本屬性外,還具有click這樣的動作。實(shí)際上,這也是WebElement最常使用的方式。
其余方法可見WebElement API文檔。
現(xiàn)在已經(jīng)獲取了所有關(guān)鍵的元素了!接下來,就是爬取每一行的元素,并進(jìn)行循環(huán)點(diǎn)擊!
0x04 爬蟲的路上總是充滿坎坷
Selenium的教程到這里其實(shí)已經(jīng)結(jié)束了,但是如果有同學(xué)去嘗試爬取網(wǎng)站的活,會發(fā)現(xiàn)各種各樣神奇的bug。
這些bug并非程序的問題,而是因?yàn)橛兄寤ò碎T的網(wǎng)站。這些網(wǎng)站的設(shè)計(jì)者們腦海里可能有個哪吒在鬧海,讓你根本想不明白他在想什么。在這里也分享一下在爬取示例網(wǎng)站時(shí)的趣事。
JavaScript嵌套
如下圖,當(dāng)你點(diǎn)擊iframe的一行時(shí),會出來一個新的iframe,數(shù)據(jù)同樣是由JavaScript生成的。獲取新的iframe數(shù)據(jù)并不難,wait+find就可以得到。難點(diǎn)在于,當(dāng)每一行都點(diǎn)擊的時(shí)候,你要如何把新出現(xiàn)的iframe和他所屬的iframe關(guān)聯(lián)起來呢?畢竟,像下圖一樣,每個新出現(xiàn)的iframe的class都是"detail-view"。
最開始我嘗試兩個map,然后join,但是很難保證join后的結(jié)果是正確的。后來我發(fā)現(xiàn)了新的Iframe的特點(diǎn):當(dāng)再次點(diǎn)擊該行數(shù)據(jù)時(shí),新的Iframe會被關(guān)閉。這樣,就有了取巧的辦法:在循環(huán)爬取數(shù)據(jù)的時(shí)候,每次生成新的iFrame,并爬取數(shù)據(jù)后,再次調(diào)用click,把Iframe關(guān)閉。這樣,就可以保證每次根據(jù)'detail-view'獲取元素的時(shí)候,就只有唯一的一個Iframe。
這個解決辦法看起來毫無技術(shù)含量,并且增加了爬取的總耗時(shí):增加了一個click動作的耗時(shí)。但是就像在開頭說的一樣:寫爬蟲的時(shí)候,總是“不擇手段”的。當(dāng)你可以很快的想到一個解決爬蟲問題的方法,并且很容易實(shí)現(xiàn)時(shí),你就可以大膽的使用他,哪怕它并不是最優(yōu)的解決辦法。畢竟,在你費(fèi)腦筋想到更好的解決辦法時(shí),使用“笨”辦法爬取的數(shù)據(jù)可能已經(jīng)到手了。
爬取中斷
如果你嘗試爬取示例網(wǎng)站的時(shí)候,你會發(fā)現(xiàn),爬蟲在爬取到1000余條的時(shí)候,會被中斷,同時(shí)提示:元素‘page-link’無法被點(diǎn)擊,也就是點(diǎn)擊不了‘下一頁’按鈕。
最開始的時(shí)候,我以為是那一頁數(shù)據(jù)缺少了‘下一頁’按鈕的href,畢竟,類似按鈕缺少href,鏈接突然變成text這樣的事情實(shí)在是太普遍了。但是,在我找到該頁數(shù)據(jù)的時(shí)候,我發(fā)現(xiàn)并不是這樣的。該頁數(shù)據(jù)看起來非常的正常,‘下一頁’按鈕也是具有href,可以被正常點(diǎn)擊的。但是在我重復(fù)爬取了多次后,在爬取到該頁數(shù)據(jù)時(shí)爬蟲均會中斷,同時(shí)提示我元素‘page-link’無法被點(diǎn)擊。這個問題困擾了我很久,直到我發(fā)現(xiàn):
這是個可以和網(wǎng)站客服人員聯(lián)系的按鈕,在第125頁的時(shí)候,他神奇的出現(xiàn)在了‘下一頁’按鈕的上方,遮擋住了‘下一頁’按鈕,導(dǎo)致模擬器無法點(diǎn)擊到‘下一頁’按鈕。這個問題也是讓人有些哭笑不得。
如何解決呢?辦法其實(shí)非常的簡單,把模擬器的窗口調(diào)大。因?yàn)椤奶彀粹o‘的位置是依據(jù)當(dāng)前窗口大小,也就是相對位置,而’下一頁‘按鈕不一樣。這樣,就可以保證讓兩個按鈕分開:
數(shù)據(jù)也就可以正常爬取了。
之所以寫出這兩個例子,是因?yàn)檫@兩個解決方法其實(shí)都屬于‘怪邏輯’:一個莫名其妙的點(diǎn)擊,和一個莫名其妙的調(diào)大窗口。如果你僅僅去看代碼,你不會明白這兩行代碼的意義在哪里。但是對于這個網(wǎng)站而言,這兩行又是必需的。就像文章開頭提到的‘不擇手段’,在解決問題的時(shí)候,換一種角度去思考,可能會比從正面解決要容易得多。
0x05 參考資料
示例代碼github地址
更多騰訊云服務(wù)器技術(shù)干貨、優(yōu)惠活動、交流社區(qū),敬請關(guān)注「騰訊云服務(wù)器」微信公眾號(TencentCVM)
總結(jié)
以上是生活随笔為你收集整理的driver.get调用iframe中的页面_【5分钟玩转Lighthouse】爬取JavaScript动态渲染页面的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: python生成随机数方法_Python
- 下一篇: jquery页面跳转带cookie_JS