Python利用Selenium實(shí)現(xiàn)全網(wǎng)頁截圖
無論是歸檔網(wǎng)站、測試頁面設(shè)計(jì),還是為報告記錄網(wǎng)頁內(nèi)容,一個可靠的截圖工具都能大大提升效率。本文將介紹如何使用Python、Selenium和wxPython構(gòu)建一個用戶友好的網(wǎng)頁截圖工具。該工具能在瀏覽器中顯示網(wǎng)頁,自動平滑滾動到底部以觸發(fā)懶加載內(nèi)容,并將整個網(wǎng)頁截圖保存為PNG文件。
為什么需要一個網(wǎng)頁截圖工具
現(xiàn)代網(wǎng)頁通常是動態(tài)的,會隨著用戶滾動加載內(nèi)容(即懶加載)。傳統(tǒng)的截圖方法只能捕獲可見區(qū)域,可能會遺漏動態(tài)加載的內(nèi)容。我們的工具解決了以下問題:
- 顯示網(wǎng)頁:通過可見的瀏覽器窗口,讓用戶可以看到網(wǎng)頁加載和滾動的過程。
- 平滑滾動:自動以平滑動畫滾動到底部,確保所有懶加載內(nèi)容都加載完成。
- 完整截圖:捕獲整個網(wǎng)頁,包括超出視口的部分。
- 用戶友好界面:提供圖形界面,方便輸入URL、選擇保存路徑,并顯示進(jìn)度反饋。
使用技術(shù)
Python:核心編程語言,用于編寫工具邏輯。
Selenium:瀏覽器自動化框架,用于控制Chrome瀏覽器并捕獲截圖。
wxPython:用于創(chuàng)建跨平臺的圖形用戶界面(GUI)。
ChromeDriver:Chrome的WebDriver,通過webdriver_manager自動管理。
工作原理
該工具基于wxPython構(gòu)建,提供簡單的圖形界面。用戶輸入網(wǎng)頁URL,選擇保存路徑,點(diǎn)擊按鈕即可開始截圖。以下是工作流程:
1. 用戶界面
工具使用wxPython創(chuàng)建了一個簡潔的GUI,包含以下組件:
- URL輸入框:用戶輸入目標(biāo)網(wǎng)頁的URL(若無http://或https://前綴,自動添加https://)。
- 保存路徑選擇:允許用戶選擇截圖保存的文件夾,默認(rèn)路徑為用戶的“圖片”文件夾。
- 截圖按鈕:觸發(fā)網(wǎng)頁加載和截圖過程。
- 進(jìn)度條:實(shí)時顯示滾動和截圖進(jìn)度。
- 狀態(tài)欄:顯示當(dāng)前操作狀態(tài)(如“正在加載網(wǎng)頁”或“截圖已保存”)。
2. 網(wǎng)頁加載與滾動
非無頭模式:工具使用Selenium控制Chrome瀏覽器,并以可見窗口運(yùn)行(移除--headless選項(xiàng)),讓用戶看到網(wǎng)頁的加載和滾動過程。
平滑滾動:通過JavaScript的window.scrollTo方法實(shí)現(xiàn)平滑滾動(behavior: 'smooth'),每次滾動一小段(基于頁面高度和視口高度計(jì)算步數(shù)),并暫停0.5秒以確保內(nèi)容加載。
進(jìn)度反饋:滾動過程中,進(jìn)度條根據(jù)滾動步數(shù)更新,增強(qiáng)用戶體驗(yàn)。
3. 截圖捕獲
CDP方法:使用Chrome DevTools Protocol(CDP)的Page.captureScreenshot方法,一次性捕獲整個網(wǎng)頁(captureBeyondViewport: True),無需拼接。
保存為PNG:截圖以PNG格式保存,文件名為{域名}_{時間戳}.png,例如example.com_20250516_194023.png。
4. 錯誤處理
驗(yàn)證URL和保存路徑的有效性,若無效則彈出提示。
捕獲所有異常,確保瀏覽器在錯誤發(fā)生時正確關(guān)閉,并通過彈窗和狀態(tài)欄向用戶反饋詳細(xì)錯誤信息。
代碼實(shí)現(xiàn)
以下是核心代碼片段,展示了滾動和截圖邏輯:
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)頁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)頁")
# 進(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("請輸入有效的URL", "錯誤", wx.OK | wx.ICON_ERROR)
return
# 如果URL沒有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)}", "錯誤", wx.OK | wx.ICON_ERROR)
return
self.status_text.SetLabel("正在加載網(wǎ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):
"""滾動頁面以觸發(fā)所有懶加載內(nèi)容,顯示滾動效果"""
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ì)算滾動步數(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) # 等待平滑滾動和內(nèi)容加載
time.sleep(1) # 確保所有內(nèi)容加載完成
def take_screenshot(self, url, save_path):
try:
# 設(shè)置Chrome選項(xiàng),移除無頭模式以顯示瀏覽器
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è)置初始窗口大小
# 啟動瀏覽器
service = Service(ChromeDriverManager().install())
driver = webdriver.Chrome(service=service, options=chrome_options)
# 訪問網(wǎng)頁
driver.get(url)
time.sleep(3) # 等待頁面初始加載
# 滾動頁面以觸發(fā)懶加載內(nèi)容
self.scroll_page(driver)
# 獲取域名和時間戳
domain = urlparse(url).netloc or "webpage"
timestamp = time.strftime("%Y%m%d_%H%M%S")
# 使用CDP方法獲取完整頁面截圖
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}", "錯誤", wx.OK | wx.ICON_ERROR)
if __name__ == '__main__':
app = wx.App()
ScreenshotApp(None, title='網(wǎng)頁截圖工具')
app.MainLoop()安裝與運(yùn)行
環(huán)境要求
Python 3.8+
依賴庫:pip install wxPython selenium webdriver_manager
運(yùn)行步驟
- 安裝依賴庫。
- 運(yùn)行代碼,打開GUI窗口。
- 輸入網(wǎng)頁URL(如example.com)。
- 選擇保存路徑(或使用默認(rèn)路徑)。
- 點(diǎn)擊“截取網(wǎng)頁”,觀察瀏覽器打開、平滑滾動并截圖。
- 截圖完成后,查看保存的PNG文件。
優(yōu)勢與局限性
優(yōu)勢
- 直觀體驗(yàn):可見的瀏覽器窗口和進(jìn)度條讓用戶清楚操作進(jìn)程。
- 完整截圖:支持動態(tài) 網(wǎng)頁,確保捕獲所有內(nèi)容。
- 易用性:簡單的GUI適合非技術(shù)用戶。
- 跨平臺:wxPython和Selenium支持Windows、macOS和Linux。
局限性
- 性能:對于超長網(wǎng)頁,滾動和加載可能需要較長時間。
- 依賴性:需要安裝Chrome瀏覽器和ChromeDriver。
- CDP限制:某些Chrome版本可能不支持CDP截圖(可回退到拼接方法)。
運(yùn)行結(jié)果



到此這篇關(guān)于Python利用Selenium實(shí)現(xiàn)全網(wǎng)頁截圖的文章就介紹到這了,更多相關(guān)Python Selenium網(wǎng)頁截圖內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Python實(shí)現(xiàn)從SQL型數(shù)據(jù)庫讀寫dataframe型數(shù)據(jù)的方法【基于pandas】
這篇文章主要介紹了Python實(shí)現(xiàn)從SQL型數(shù)據(jù)庫讀寫dataframe型數(shù)據(jù)的方法,涉及Python基于pandas的數(shù)據(jù)庫讀寫相關(guān)操作技巧,需要的朋友可以參考下2019-03-03
Python+Matplotlib實(shí)現(xiàn)繪制三維折線圖
立體圖視覺上層次分明色彩鮮艷,具有很強(qiáng)的視覺沖擊力,讓觀看的人駐景時間長,留下深刻的印象。今天我們就通過這篇文章來了解如何用python中的matplotlib庫繪制漂亮的三維折線圖吧2023-03-03
python numpy linspace函數(shù)使用詳解
本文介紹了Python Numpy庫中的linspace函數(shù),該函數(shù)用于生成均勻分布的數(shù)值序列,通過示例和詳細(xì)參數(shù)解釋,幫助讀者理解如何使用linspace函數(shù),最后,對比了linspace和arange函數(shù)之間的主要差異,感興趣的朋友跟隨小編一起看看吧2024-12-12
Django認(rèn)證系統(tǒng)user對象實(shí)現(xiàn)過程解析
這篇文章主要介紹了Django認(rèn)證系統(tǒng)user對象實(shí)現(xiàn)過程解析,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下2020-03-03
python通過scapy獲取局域網(wǎng)所有主機(jī)mac地址示例
這篇文章主要介紹了python通過scapy獲取局域網(wǎng)所有主機(jī)mac地址示例,需要的朋友可以參考下2014-05-05
python錯誤:AttributeError: ''module'' object has no attribute
這篇文章主要介紹了python錯誤:AttributeError: 'module' object has no attribute 'setdefaultencoding'問題的解決方法,需要的朋友可以參考下2014-08-08

