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

