一、為什么我抓不到網(wǎng)頁(yè)的全部html內(nèi)容
有時(shí)候,我們?cè)谟胾rllib或者requests庫(kù)抓取頁(yè)面時(shí),得到的html源代碼和瀏覽器中看到的不一樣。這將是我們面臨的一個(gè)非常常見(jiàn)的問(wèn)題?,F(xiàn)在網(wǎng)頁(yè)越來(lái)越多地采用Ajax、前端模塊化工具來(lái)構(gòu)建,整個(gè)網(wǎng)頁(yè)可能都是由JavaScript渲染出來(lái)的,也就是說(shuō)原始的HTML代碼可能就是一個(gè)空殼,例如:
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>
this is a demo
</title>
</head>
<body>
<div id="container">
</div>
</body>
<script src="app.js">
</script>
</html>
body節(jié)點(diǎn)里面只有一個(gè)id為container的節(jié)點(diǎn),但是需要注意在body節(jié)點(diǎn)后引入了app.js, 它便負(fù)責(zé)整個(gè)網(wǎng)站的渲染。
在瀏覽器中打開(kāi)這個(gè)頁(yè)面時(shí),首先會(huì)加載這個(gè)HTML內(nèi)容,接著瀏覽器會(huì)發(fā)現(xiàn)其中引入了一個(gè)app.js文件,然后便會(huì)接著去請(qǐng)求這個(gè)文件,獲取到該文件后,便會(huì)執(zhí)行其中的JavaScript代碼,而JavaScript則會(huì)改變HTML中的節(jié)點(diǎn),向其中添加內(nèi)容,最后得到完整的頁(yè)面。
但是在用urllib或者requests等庫(kù)請(qǐng)求當(dāng)前頁(yè)面時(shí),我們得到的只是這個(gè)HTML代碼,它不會(huì)幫助我們?nèi)ダ^續(xù)加載這個(gè)JavaScript文件,這樣也就看不到瀏覽器中的內(nèi)容了。
而且,JavaScript動(dòng)態(tài)渲染的頁(yè)面可不止Ajax這一種,還有其他各種原因會(huì)導(dǎo)致我們得到的源代碼和瀏覽器中看到的不一樣。
對(duì)于抓不到全部html內(nèi)容的情況,我們能采取什么應(yīng)對(duì)措施呢,本文介紹一種可行的方法,就是通過(guò)Selenium webdriver來(lái)模擬瀏覽器運(yùn)行的方式,這樣就可以做到在瀏覽器中看到是什么樣,抓取的源碼就是什么樣,也就是可見(jiàn)即可爬。這樣,我們就不用再去管網(wǎng)頁(yè)內(nèi)部的JavaScript用了什么算法渲染頁(yè)面,也不用管網(wǎng)頁(yè)后臺(tái)的Ajax接口到底有哪些參數(shù)。所有的這些,都交給Selenium webdriver來(lái)幫我們完成。
二、Selenium的基本使用
Selenium是一個(gè)自動(dòng)化測(cè)試工具,利用它可以驅(qū)動(dòng)瀏覽器執(zhí)行特定的動(dòng)作,如點(diǎn)擊、下拉等操作,同時(shí)還可以獲取瀏覽器當(dāng)前呈現(xiàn)的頁(yè)面的源代碼,做到可見(jiàn)即可爬。對(duì)于一些JavaScript動(dòng)態(tài)渲染的頁(yè)面來(lái)說(shuō),此種抓取方式非常有效。
Selenium webdriver的安裝和基本使用方法,可以參考另一篇文章。
Python使用Selenium WebDriver的入門介紹及安裝教程
Selenium的官方網(wǎng)站:
Selenium WebDriver
一些基本的用法,此處不再贅述。
三、使用Selenium抓取全部HTML
先看使用requests庫(kù)直接提取到的代碼,可以發(fā)現(xiàn)并不是完整的:
使用Selenium拿到的html代碼,可以看到已經(jīng)可以通過(guò)src屬性提取到圖片的url:
文章來(lái)源:http://www.zghlxwxcb.cn/news/detail-400218.html
示例代碼如下,詳細(xì)的解讀可以參考每一步的注釋:文章來(lái)源地址http://www.zghlxwxcb.cn/news/detail-400218.html
from selenium.webdriver import Firefox, FirefoxOptions
from selenium.webdriver.support.wait import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.common.by import By
class ContentPageParser():
def __init__(self, content_page_url) -> None:
self.content_url = content_page_url # 抓取content_page_url頁(yè)面上全部的圖片url
self.img_src = [] # 保存當(dāng)前頁(yè)面上所有的圖片url
def visit_content_page_with_firefox(self):
option = FirefoxOptions()
# 設(shè)置瀏覽器為無(wú)頭模式,使用過(guò)程中不會(huì)彈出瀏覽器頁(yè)面
option.headless = True
self.driver = Firefox(options=option)
try:
# 打開(kāi)待抓取的url頁(yè)面
self.driver.get(self.content_url)
# 設(shè)置靈活等待,最長(zhǎng)等待10s,輪詢間隔為1s
wait = WebDriverWait(self.driver, timeout=10, poll_frequency=1)
# 使用css選擇器進(jìn)行元素定位,直到元素可見(jiàn)為止
wait.until(EC.visibility_of_element_located((By.CSS_SELECTOR, 'img[class="showimg"]')))
# 使用css選擇器查找所有元素
imgs = self.driver.find_elements(By.CSS_SELECTOR, 'img[class="showimg"]')
# 提取所有圖片的url
for img in imgs:
self.img_src.append(img.get_attribute('src'))
except Exception as e:
print(repr(e))
finally:
# 關(guān)閉webdriver
self.driver.close()
def get_img_src(self):
return self.img_src
if __name__ == '__main__':
content_parser = ContentPageParser('https://xxx/content_48495.html')
content_parser.visit_content_page_with_firefox()
img = content_parser.get_img_src()
print(img)
到了這里,關(guān)于Python使用Selenium Webdriver爬取網(wǎng)頁(yè)所有內(nèi)容的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!