forked from jbiaojerry/ebook-treasure-chest
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathgenerate_search_demo_gif.py
More file actions
executable file
·229 lines (201 loc) · 8.32 KB
/
Copy pathgenerate_search_demo_gif.py
File metadata and controls
executable file
·229 lines (201 loc) · 8.32 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
自動生成 GitHub Pages 搜尋功能演示 GIF
使用 playwright 自動化瀏覽器操作並錄製 GIF
"""
import asyncio
import time
import io
from pathlib import Path
from PIL import Image
import subprocess
import sys
ROOT = Path(__file__).parent.parent
OUTPUT_GIF = ROOT / ".github" / "search-demo.gif"
GITHUB_PAGES_URL = "https://jbiaojerry.github.io/ebook-treasure-chest/"
def check_dependencies():
"""檢查依賴是否安裝"""
missing = []
# 檢查 playwright
try:
import playwright
except ImportError:
missing.append("playwright")
# 檢查 Pillow
try:
import PIL
except ImportError:
missing.append("Pillow")
if missing:
print(f"❌ 缺少以下依賴: {', '.join(missing)}")
print("\n請安裝依賴:")
if "playwright" in missing:
print(" pip install playwright")
print(" playwright install chromium")
if "Pillow" in missing:
print(" pip install Pillow")
return False
return True
async def wait_for_search_results(page, timeout=5000):
"""等待搜尋結果出現"""
try:
# 等待搜尋結果容器有內容(不是"正在載入")
await page.wait_for_function(
"""() => {
const results = document.getElementById('search-results');
if (!results) return false;
const text = results.innerText || '';
return text.length > 0 && !text.includes('正在載入');
}""",
timeout=timeout
)
# 額外等待一下確保渲染完成
await asyncio.sleep(0.5)
return True
except:
return False
async def scroll_to_search_results(page):
"""滾動到搜尋結果區域,確保搜尋結果在視口內"""
try:
# 獲取搜尋結果元素
search_results = page.locator('#search-results')
if await search_results.count() > 0:
# 滾動到搜尋結果區域
await search_results.scroll_into_view_if_needed()
await asyncio.sleep(0.3)
# 稍微向上滾動一點,讓搜尋框也可見
await page.evaluate("window.scrollBy(0, -100)")
await asyncio.sleep(0.2)
except Exception as e:
print(f" ⚠️ 滾動到搜尋結果時出錯: {e}")
async def generate_gif():
"""生成搜尋功能演示 GIF"""
try:
from playwright.async_api import async_playwright
except ImportError:
print("❌ 請先安裝 playwright: pip install playwright && playwright install chromium")
return False
print("🚀 開始生成搜尋功能演示 GIF...")
print(f"📡 訪問頁面: {GITHUB_PAGES_URL}")
screenshots = []
async with async_playwright() as p:
# 啟動瀏覽器(無頭模式)
browser = await p.chromium.launch(headless=False) # 設定為 False 以便觀察
context = await browser.new_context(
viewport={'width': 1280, 'height': 720},
device_scale_factor=1
)
page = await context.new_page()
try:
# 步驟 1: 訪問頁面
print("📄 步驟 1: 載入頁面...")
await page.goto(GITHUB_PAGES_URL, wait_until='networkidle', timeout=30000)
await asyncio.sleep(2) # 等待頁面完全載入
screenshots.append(await page.screenshot())
print(" ✅ 頁面載入完成")
# 步驟 2: 等待資料載入
print("⏳ 步驟 2: 等待資料載入...")
# 等待搜尋框出現,說明頁面已載入
await page.wait_for_selector('input[type="text"]', timeout=10000)
await asyncio.sleep(3) # 等待 all-books.json 載入
# 檢查資料是否載入完成
data_loaded = await page.evaluate("""() => {
return window.books && window.books.length > 0;
}""")
if data_loaded:
print(f" ✅ 資料載入完成(已載入書籍資料)")
else:
print(f" ⚠️ 資料可能還在載入中,繼續...")
screenshots.append(await page.screenshot())
# 步驟 3: 輸入搜尋關鍵詞 "文學"
print("🔍 步驟 3: 搜尋 '文學'...")
search_input = page.locator('input[type="text"]')
await search_input.fill("文學")
await asyncio.sleep(0.5) # 等待輸入完成
# 等待搜尋結果出現
await wait_for_search_results(page, timeout=5000)
# 滾動到搜尋結果
await scroll_to_search_results(page)
screenshots.append(await page.screenshot())
print(" ✅ 搜尋完成,已展示搜尋結果")
# 步驟 4: 清空並搜尋 "文學 鋼鐵是怎麼煉成的"
print("🔍 步驟 4: 搜尋 '文學 鋼鐵是怎麼煉成的'...")
await search_input.fill("")
await asyncio.sleep(0.5)
await search_input.fill("文學 鋼鐵是怎麼煉成的")
await asyncio.sleep(0.5)
# 等待搜尋結果
await wait_for_search_results(page, timeout=5000)
await scroll_to_search_results(page)
screenshots.append(await page.screenshot())
print(" ✅ 搜尋完成,已展示搜尋結果")
# 步驟 5: 多關鍵詞搜尋
print("🔍 步驟 5: 多關鍵詞搜尋 '溝通 樊登 職場'...")
await search_input.fill("")
await asyncio.sleep(0.5)
await search_input.fill("溝通 樊登 職場")
await asyncio.sleep(0.5)
# 等待搜尋結果
await wait_for_search_results(page, timeout=5000)
await scroll_to_search_results(page)
screenshots.append(await page.screenshot())
print(" ✅ 多關鍵詞搜尋完成,已展示搜尋結果")
# 步驟 6: 展示最終結果(多停留一會)
await asyncio.sleep(1)
await scroll_to_search_results(page)
screenshots.append(await page.screenshot())
except Exception as e:
print(f"❌ 錄製過程中出錯: {e}")
import traceback
traceback.print_exc()
return False
finally:
await browser.close()
# 將截圖轉換為 GIF
print("\n🎬 步驟 6: 生成 GIF 動畫...")
try:
# 將截圖轉換為 PIL Image
images = [Image.open(io.BytesIO(img)) for img in screenshots]
# 儲存為 GIF
OUTPUT_GIF.parent.mkdir(parents=True, exist_ok=True)
# 第一幀顯示時間稍長,其他幀正常顯示
durations = [2000] + [1500] * (len(images) - 1) # 第一幀 2 秒,其他 1.5 秒
# 使用 save_all 儲存多幀,但需要手動設定每幀的持續時間
# 由於 PIL 的 save_all 不支援每幀不同 duration,我們使用固定值
images[0].save(
OUTPUT_GIF,
save_all=True,
append_images=images[1:],
duration=1500, # 每幀 1.5 秒
loop=0,
optimize=True
)
file_size = OUTPUT_GIF.stat().st_size / 1024
print(f"✅ GIF 已生成: {OUTPUT_GIF}")
print(f"📦 檔案大小: {file_size:.1f} KB")
print(f"🖼️ 幀數: {len(images)}")
return True
except Exception as e:
print(f"❌ 生成 GIF 時出錯: {e}")
import traceback
traceback.print_exc()
return False
def main():
"""主函式"""
if not check_dependencies():
sys.exit(1)
# 執行非同步函式
success = asyncio.run(generate_gif())
if success:
print("\n🎉 完成!搜尋功能演示 GIF 已生成")
print(f"📁 檔案位置: {OUTPUT_GIF}")
print("\n💡 提示: 如果 GIF 質量不理想,可以調整以下引數:")
print(" - duration: 每幀顯示時間(毫秒)")
print(" - viewport: 瀏覽器視窗大小")
print(" - 等待時間: asyncio.sleep() 的延遲")
else:
print("\n❌ 生成失敗,請檢查錯誤資訊")
sys.exit(1)
if __name__ == "__main__":
main()