Python利用Selenium實(shí)現(xiàn)全網(wǎng)頁(yè)截圖
無(wú)論是歸檔網(wǎng)站、測(cè)試頁(yè)面設(shè)計(jì),還是為報(bào)告記錄網(wǎng)頁(yè)內(nèi)容,一個(gè)可靠的截圖工具都能大大提升效率。本文將介紹如何使用Python、Selenium和wxPython構(gòu)建一個(gè)用戶友好的網(wǎng)頁(yè)截圖工具。該工具能在瀏覽器中顯示網(wǎng)頁(yè),自動(dòng)平滑滾動(dòng)到底部以觸發(fā)懶加載內(nèi)容,并將整個(gè)網(wǎng)頁(yè)截圖保存為PNG文件。
為什么需要一個(gè)網(wǎng)頁(yè)截圖工具
現(xiàn)代網(wǎng)頁(yè)通常是動(dòng)態(tài)的,會(huì)隨著用戶滾動(dòng)加載內(nèi)容(即懶加載)。傳統(tǒng)的截圖方法只能捕獲可見區(qū)域,可能會(huì)遺漏動(dòng)態(tài)加載的內(nèi)容。我們的工具解決了以下問(wèn)題:
- 顯示網(wǎng)頁(yè):通過(guò)可見的瀏覽器窗口,讓用戶可以看到網(wǎng)頁(yè)加載和滾動(dòng)的過(guò)程。
- 平滑滾動(dòng):自動(dòng)以平滑動(dòng)畫滾動(dòng)到底部,確保所有懶加載內(nèi)容都加載完成。
- 完整截圖:捕獲整個(gè)網(wǎng)頁(yè),包括超出視口的部分。
- 用戶友好界面:提供圖形界面,方便輸入U(xiǎn)RL、選擇保存路徑,并顯示進(jìn)度反饋。
使用技術(shù)
Python:核心編程語(yǔ)言,用于編寫工具邏輯。
Selenium:瀏覽器自動(dòng)化框架,用于控制Chrome瀏覽器并捕獲截圖。
wxPython:用于創(chuàng)建跨平臺(tái)的圖形用戶界面(GUI)。
ChromeDriver:Chrome的WebDriver,通過(guò)webdriver_manager自動(dòng)管理。
工作原理
該工具基于wxPython構(gòu)建,提供簡(jiǎn)單的圖形界面。用戶輸入網(wǎng)頁(yè)URL,選擇保存路徑,點(diǎn)擊按鈕即可開始截圖。以下是工作流程:
1. 用戶界面
工具使用wxPython創(chuàng)建了一個(gè)簡(jiǎn)潔的GUI,包含以下組件:
- URL輸入框:用戶輸入目標(biāo)網(wǎng)頁(yè)的URL(若無(wú)http://或https://前綴,自動(dòng)添加https://)。
- 保存路徑選擇:允許用戶選擇截圖保存的文件夾,默認(rèn)路徑為用戶的“圖片”文件夾。
- 截圖按鈕:觸發(fā)網(wǎng)頁(yè)加載和截圖過(guò)程。
- 進(jìn)度條:實(shí)時(shí)顯示滾動(dòng)和截圖進(jìn)度。
- 狀態(tài)欄:顯示當(dāng)前操作狀態(tài)(如“正在加載網(wǎng)頁(yè)”或“截圖已保存”)。
2. 網(wǎng)頁(yè)加載與滾動(dòng)
非無(wú)頭模式:工具使用Selenium控制Chrome瀏覽器,并以可見窗口運(yùn)行(移除--headless選項(xiàng)),讓用戶看到網(wǎng)頁(yè)的加載和滾動(dòng)過(guò)程。
平滑滾動(dòng):通過(guò)JavaScript的window.scrollTo方法實(shí)現(xiàn)平滑滾動(dòng)(behavior: 'smooth'),每次滾動(dòng)一小段(基于頁(yè)面高度和視口高度計(jì)算步數(shù)),并暫停0.5秒以確保內(nèi)容加載。
進(jìn)度反饋:滾動(dòng)過(guò)程中,進(jìn)度條根據(jù)滾動(dòng)步數(shù)更新,增強(qiáng)用戶體驗(yàn)。
3. 截圖捕獲
CDP方法:使用Chrome DevTools Protocol(CDP)的Page.captureScreenshot方法,一次性捕獲整個(gè)網(wǎng)頁(yè)(captureBeyondViewport: True),無(wú)需拼接。
保存為PNG:截圖以PNG格式保存,文件名為{域名}_{時(shí)間戳}.png,例如example.com_20250516_194023.png。
4. 錯(cuò)誤處理
驗(yàn)證URL和保存路徑的有效性,若無(wú)效則彈出提示。
捕獲所有異常,確保瀏覽器在錯(cuò)誤發(fā)生時(shí)正確關(guān)閉,并通過(guò)彈窗和狀態(tài)欄向用戶反饋詳細(xì)錯(cuò)誤信息。
代碼實(shí)現(xiàn)
以下是核心代碼片段,展示了滾動(dòng)和截圖邏輯:
import wx
import os
import time
from selenium import webdriver
from selenium.webdriver.chrome.options import Options
from selenium.webdriver.chrome.service import Service
from webdriver_manager.chrome import ChromeDriverManager
import base64
from urllib.parse import urlparse
import threading
class ScreenshotApp(wx.Frame):
def __init__(self, parent, title):
super(ScreenshotApp, self).__init__(parent, title=title, size=(600, 300))
self.InitUI()
self.Centre()
self.Show()
def InitUI(self):
panel = wx.Panel(self)
vbox = wx.BoxSizer(wx.VERTICAL)
# URL輸入?yún)^(qū)域
url_box = wx.BoxSizer(wx.HORIZONTAL)
url_label = wx.StaticText(panel, label="網(wǎng)頁(yè)URL:")
self.url_text = wx.TextCtrl(panel, size=(400, -1))
url_box.Add(url_label, flag=wx.RIGHT | wx.ALIGN_CENTER_VERTICAL, border=8)
url_box.Add(self.url_text, proportion=1)
# 保存路徑區(qū)域
path_box = wx.BoxSizer(wx.HORIZONTAL)
path_label = wx.StaticText(panel, label="保存路徑:")
self.path_text = wx.TextCtrl(panel, size=(300, -1))
browse_button = wx.Button(panel, label="瀏覽...")
path_box.Add(path_label, flag=wx.RIGHT | wx.ALIGN_CENTER_VERTICAL, border=8)
path_box.Add(self.path_text, proportion=1, flag=wx.RIGHT, border=5)
path_box.Add(browse_button)
# 截圖按鈕
screenshot_button = wx.Button(panel, label="截取網(wǎng)頁(yè)")
# 進(jìn)度條
self.progress_bar = wx.Gauge(panel, range=100, size=(400, 20))
self.progress_bar.SetValue(0)
# 狀態(tài)顯示區(qū)域
self.status_text = wx.StaticText(panel, label="")
# 添加到垂直布局
vbox.Add((-1, 20))
vbox.Add(url_box, flag=wx.EXPAND | wx.LEFT | wx.RIGHT, border=10)
vbox.Add((-1, 20))
vbox.Add(path_box, flag=wx.EXPAND | wx.LEFT | wx.RIGHT, border=10)
vbox.Add((-1, 30))
vbox.Add(screenshot_button, flag=wx.ALIGN_CENTER)
vbox.Add((-1, 20))
vbox.Add(self.progress_bar, flag=wx.EXPAND | wx.LEFT | wx.RIGHT, border=10)
vbox.Add((-1, 10))
vbox.Add(self.status_text, flag=wx.ALIGN_CENTER)
# 綁定事件
browse_button.Bind(wx.EVT_BUTTON, self.OnBrowse)
screenshot_button.Bind(wx.EVT_BUTTON, self.OnScreenshot)
# 設(shè)置默認(rèn)保存路徑為用戶的圖片文件夾
default_path = os.path.join(os.path.expanduser("~"), "Pictures")
self.path_text.SetValue(default_path)
panel.SetSizer(vbox)
def OnBrowse(self, event):
dialog = wx.DirDialog(self, "選擇保存截圖的文件夾", style=wx.DD_DEFAULT_STYLE)
if dialog.ShowModal() == wx.ID_OK:
self.path_text.SetValue(dialog.GetPath())
dialog.Destroy()
def OnScreenshot(self, event):
url = self.url_text.GetValue().strip()
save_path = self.path_text.GetValue().strip()
# 驗(yàn)證URL
if not url:
wx.MessageBox("請(qǐng)輸入有效的URL", "錯(cuò)誤", wx.OK | wx.ICON_ERROR)
return
# 如果URL沒(méi)有http前綴,添加https://
if not url.startswith(('http://', 'https://')):
url = 'https://' + url
self.url_text.SetValue(url)
# 驗(yàn)證保存路徑
if not os.path.exists(save_path):
try:
os.makedirs(save_path)
except Exception as e:
wx.MessageBox(f"創(chuàng)建保存路徑失敗: {str(e)}", "錯(cuò)誤", wx.OK | wx.ICON_ERROR)
return
self.status_text.SetLabel("正在加載網(wǎng)頁(yè)并滾動(dòng),請(qǐng)稍候...")
self.progress_bar.SetValue(0)
self.Layout()
# 使用線程避免界面凍結(jié)
thread = threading.Thread(target=self.take_screenshot, args=(url, save_path))
thread.daemon = True
thread.start()
def scroll_page(self, driver):
"""滾動(dòng)頁(yè)面以觸發(fā)所有懶加載內(nèi)容,顯示滾動(dòng)效果"""
total_height = driver.execute_script("return document.body.scrollHeight")
viewport_height = driver.execute_script("return window.innerHeight")
steps = max(1, total_height // viewport_height) # 計(jì)算滾動(dòng)步數(shù)
step_height = total_height / steps
for i in range(steps + 1):
scroll_position = int(i * step_height)
driver.execute_script(f"window.scrollTo({{top: {scroll_position}, behavior: 'smooth'}});")
wx.CallAfter(self.progress_bar.SetValue, int((i + 1) / (steps + 1) * 100))
time.sleep(0.5) # 等待平滑滾動(dòng)和內(nèi)容加載
time.sleep(1) # 確保所有內(nèi)容加載完成
def take_screenshot(self, url, save_path):
try:
# 設(shè)置Chrome選項(xiàng),移除無(wú)頭模式以顯示瀏覽器
chrome_options = Options()
chrome_options.add_argument("--disable-gpu")
chrome_options.add_argument("--disable-infobars")
chrome_options.add_argument("--disable-extensions")
chrome_options.add_argument("--window-size=1920,1080") # 設(shè)置初始窗口大小
# 啟動(dòng)瀏覽器
service = Service(ChromeDriverManager().install())
driver = webdriver.Chrome(service=service, options=chrome_options)
# 訪問(wèn)網(wǎng)頁(yè)
driver.get(url)
time.sleep(3) # 等待頁(yè)面初始加載
# 滾動(dòng)頁(yè)面以觸發(fā)懶加載內(nèi)容
self.scroll_page(driver)
# 獲取域名和時(shí)間戳
domain = urlparse(url).netloc or "webpage"
timestamp = time.strftime("%Y%m%d_%H%M%S")
# 使用CDP方法獲取完整頁(yè)面截圖
result = driver.execute_cdp_cmd('Page.captureScreenshot',
{'format': 'png', 'captureBeyondViewport': True})
image_data = base64.b64decode(result['data'])
save_file = os.path.join(save_path, f"{domain}_{timestamp}.png")
with open(save_file, 'wb') as f:
f.write(image_data)
driver.quit()
wx.CallAfter(self.screenshot_complete, save_file)
except Exception as e:
if 'driver' in locals():
driver.quit()
wx.CallAfter(self.screenshot_error, str(e))
def screenshot_complete(self, filepath):
self.status_text.SetLabel(f"截圖已保存至: {filepath}")
self.progress_bar.SetValue(100)
wx.MessageBox(f"截圖已保存至:\n{filepath}", "成功", wx.OK | wx.ICON_INFORMATION)
def screenshot_error(self, error_msg):
self.status_text.SetLabel(f"截圖失敗: {error_msg}")
self.progress_bar.SetValue(0)
wx.MessageBox(f"截圖失敗: {error_msg}", "錯(cuò)誤", wx.OK | wx.ICON_ERROR)
if __name__ == '__main__':
app = wx.App()
ScreenshotApp(None, title='網(wǎng)頁(yè)截圖工具')
app.MainLoop()安裝與運(yùn)行
環(huán)境要求
Python 3.8+
依賴庫(kù):pip install wxPython selenium webdriver_manager
運(yùn)行步驟
- 安裝依賴庫(kù)。
- 運(yùn)行代碼,打開GUI窗口。
- 輸入網(wǎng)頁(yè)URL(如example.com)。
- 選擇保存路徑(或使用默認(rèn)路徑)。
- 點(diǎn)擊“截取網(wǎng)頁(yè)”,觀察瀏覽器打開、平滑滾動(dòng)并截圖。
- 截圖完成后,查看保存的PNG文件。
優(yōu)勢(shì)與局限性
優(yōu)勢(shì)
- 直觀體驗(yàn):可見的瀏覽器窗口和進(jìn)度條讓用戶清楚操作進(jìn)程。
- 完整截圖:支持動(dòng)態(tài) 網(wǎng)頁(yè),確保捕獲所有內(nèi)容。
- 易用性:簡(jiǎn)單的GUI適合非技術(shù)用戶。
- 跨平臺(tái):wxPython和Selenium支持Windows、macOS和Linux。
局限性
- 性能:對(duì)于超長(zhǎng)網(wǎng)頁(yè),滾動(dòng)和加載可能需要較長(zhǎng)時(shí)間。
- 依賴性:需要安裝Chrome瀏覽器和ChromeDriver。
- CDP限制:某些Chrome版本可能不支持CDP截圖(可回退到拼接方法)。
運(yùn)行結(jié)果



到此這篇關(guān)于Python利用Selenium實(shí)現(xiàn)全網(wǎng)頁(yè)截圖的文章就介紹到這了,更多相關(guān)Python Selenium網(wǎng)頁(yè)截圖內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Python練習(xí)之操作SQLite數(shù)據(jù)庫(kù)
這篇文章主要介紹了Python練習(xí)之操作SQLite數(shù)據(jù)庫(kù),主要通過(guò)三個(gè)問(wèn)題如何創(chuàng)建SQLite數(shù)據(jù)庫(kù)?如何向SQLite表中插入數(shù)據(jù)?如何查詢SQLite表中的數(shù)據(jù)?展開文章主題詳情,需要的朋友可以參考一下2022-06-06
Python性能加速器__slots__屬性優(yōu)化內(nèi)存使用實(shí)例探索
Python中的__slots__屬性是一個(gè)特殊的屬性,允許程序員顯式地定義類的屬性,提供了一種方式來(lái)優(yōu)化類的內(nèi)存占用和提高訪問(wèn)速度,本文將深入探討__slots__屬性的概念、應(yīng)用和性能優(yōu)勢(shì)2024-01-01
如何利用Anaconda配置簡(jiǎn)單的Python環(huán)境
這篇文章主要為大家詳細(xì)介紹了如何利用Anaconda配置簡(jiǎn)單的Python環(huán)境,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2019-06-06
python爬蟲MeterSphere平臺(tái)執(zhí)行報(bào)告流程解析
這篇文章主要為大家介紹了python爬蟲MeterSphere平臺(tái)執(zhí)行報(bào)告流程解析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-12-12
python爬蟲爬取監(jiān)控教務(wù)系統(tǒng)的思路詳解
這篇文章主要介紹了python爬蟲監(jiān)控教務(wù)系統(tǒng),主要實(shí)現(xiàn)思路是對(duì)已有的成績(jī)進(jìn)行處理,變?yōu)閘ist集合,本文通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),需要的朋友可以參考下2020-01-01
python、Matlab求定積分的實(shí)現(xiàn)
今天小編就為大家分享一篇python、Matlab求定積分的實(shí)現(xiàn),具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2019-11-11
如何解決import torchvision報(bào)錯(cuò)問(wèn)題 DLL:找不到模塊
這篇文章主要介紹了如何解決import torchvision報(bào)錯(cuò)問(wèn)題 DLL:找不到模塊,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2024-01-01
在Python的Django框架中創(chuàng)建和使用模版
這篇文章主要介紹了在Python的Django框架中創(chuàng)建和使用模版的方法,包括使用manage.py shell來(lái)幫助設(shè)置模版的方法,需要的朋友可以參考下2015-07-07

