tomo2chin2 commited on
Commit
b0d5ffc
·
verified ·
1 Parent(s): 3e66b8f

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +105 -113
app.py CHANGED
@@ -1,126 +1,118 @@
1
  import gradio as gr
2
- import os
3
- import tempfile
4
  from selenium import webdriver
5
  from selenium.webdriver.chrome.options import Options
6
- from selenium.common.exceptions import WebDriverException
 
 
 
7
  import time
8
  import base64
9
- from PIL import Image
10
- import io
 
 
 
 
 
 
 
 
 
11
 
12
- def setup_driver():
13
- """ヘッドレスChromeドライバーをセットアップして返す"""
14
- options = webdriver.ChromeOptions()
15
- options.add_argument("--headless")
 
 
16
  options.add_argument("--no-sandbox")
17
  options.add_argument("--disable-dev-shm-usage")
18
- # 一貫したスクリーンショットのためにウィンドウサイズを設定
19
- options.add_argument("--window-size=1280,1024")
20
-
21
  try:
22
  driver = webdriver.Chrome(options=options)
23
- return driver
24
- except WebDriverException as e:
25
- print(f"WebDriverの初期化に失敗しました: {e}")
26
- return None
27
-
28
- def capture_screenshot(html_content, css_content=""):
29
- """SeleniumでレンダリングされたHTMLコンテンツのスクリーンショットを撮影する"""
30
- driver = setup_driver()
31
- if not driver:
32
- return None, "Chrome WebDriverの初期化に失敗しました"
33
-
34
- try:
35
- # 一時的なHTMLファイルを作成
36
- with tempfile.NamedTemporaryFile(suffix='.html', delete=False) as f:
37
- html_file = f.name
38
- combined_html = f"""
39
- <!DOCTYPE html>
40
- <html>
41
- <head>
42
- <meta charset="UTF-8">
43
- <style>
44
- {css_content}
45
- </style>
46
- </head>
47
- <body>
48
- {html_content}
49
- </body>
50
- </html>
51
- """
52
- f.write(combined_html.encode('utf-8'))
53
-
54
- # HTMLファイルに移動
55
- driver.get(f"file://{html_file}")
56
- time.sleep(1) # レンダリングの時間を確保
57
-
58
- # スクリーンショットを撮影
59
- screenshot = tempfile.NamedTemporaryFile(suffix='.png', delete=False)
60
- driver.save_screenshot(screenshot.name)
61
- screenshot.close()
62
-
63
- # 表示用に画像を読み込む
64
- img = Image.open(screenshot.name)
65
-
66
- # 後始末
67
- os.unlink(html_file)
68
-
69
- return img, None
 
70
  except Exception as e:
71
- return None, f"スクリーンショットの撮影時にエラーが発生しました: {str(e)}"
72
- finally:
73
  driver.quit()
 
74
 
75
- def render_html(html_code, css_code=""):
76
- """HTMLコードをレンダリングしてスクリーンショットを撮影"""
77
- # HTMLを画像に変換
78
- image, error = capture_screenshot(html_code, css_code)
79
-
80
- if error:
81
- return None, gr.HTML(f"<div style='color: red;'>{error}</div>")
82
-
83
- # Gradioの HTML コンポーネントでHTMLを表示
84
- html_display = f"""
85
- <div style="border: 1px solid #ddd; padding: 10px; margin-bottom: 20px;">
86
- <h3>HTMLプレビュー:</h3>
87
- <iframe srcdoc="{html_code.replace('"', '&quot;')}"
88
- style="width: 100%; height: 300px; border: 1px solid #ddd;"></iframe>
89
- </div>
90
- """
91
-
92
- return image, gr.HTML(html_display)
93
-
94
- # Gradioインターフェースを作成
95
- with gr.Blocks() as demo:
96
- gr.Markdown("# HTMLレンダラー(スクリーンショット機能付き)")
97
- gr.Markdown("以下にHTMLコードを入力して、ヘッドレスChromeでレンダリングしスクリーンショットを撮影します。")
98
-
99
- with gr.Row():
100
- with gr.Column():
101
- html_input = gr.Textbox(
102
- label="HTMLコード",
103
- placeholder="ここにHTMLコードを入力...",
104
- lines=10,
105
- value="<h1>こんにちは、世界!</h1><p>これはSeleniumとヘッドレスChromeによるGradioのテストです。</p>"
106
- )
107
- css_input = gr.Textbox(
108
- label="CSSコード(オプション)",
109
- placeholder="ここにCSSコードを入力...",
110
- lines=5,
111
- value="body { font-family: 'Noto Sans JP', sans-serif; margin: 20px; } h1 { color: blue; }"
112
- )
113
- render_button = gr.Button("レンダリングしてスクリーンショットを撮影")
114
-
115
- with gr.Column():
116
- screenshot_output = gr.Image(label="スクリーンショット")
117
- html_preview = gr.HTML(label="HTMLプレビュー")
118
-
119
- render_button.click(
120
- render_html,
121
- inputs=[html_input, css_input],
122
- outputs=[screenshot_output, html_preview]
123
- )
124
-
125
- # アプリを起動
126
- demo.launch()
 
1
  import gradio as gr
 
 
2
  from selenium import webdriver
3
  from selenium.webdriver.chrome.options import Options
4
+ from selenium.common.exceptions import WebDriverException, TimeoutException
5
+ import tempfile
6
+ import os
7
+ from PIL import Image
8
  import time
9
  import base64
10
+ import validators # URLバリデーション用
11
+
12
+
13
+ def take_screenshot(url_or_html, wait_time=3, screenshot_type="url"):
14
+ """
15
+ URLまたはHTMLコードからフルページスクリーンショットを取得する関数。
16
+
17
+ Args:
18
+ url_or_html (str): スクリーンショットを取得するURLまたはHTMLコード。
19
+ wait_time (int): ページ読み込みの待機時間(秒)。
20
+ screenshot_type (str): "url" または "html" を指定。
21
 
22
+ Returns:
23
+ tuple: (PIL.Image.Image, str) スクリーンショット画像とメッセージのタプル。
24
+ エラーの場合は (None, str) を返す。
25
+ """
26
+ options = Options()
27
+ options.add_argument("--headless=new") # 新しいヘッドレスモード
28
  options.add_argument("--no-sandbox")
29
  options.add_argument("--disable-dev-shm-usage")
30
+ options.add_argument("--disable-gpu")
31
+ options.add_argument("--window-position=-2400,-2400") # Windowsでのバグ回避
32
+
33
  try:
34
  driver = webdriver.Chrome(options=options)
35
+
36
+ if screenshot_type == "url":
37
+ # URLバリデーション
38
+ if not validators.url(url_or_html):
39
+ raise ValueError("無効なURLです。")
40
+ driver.get(url_or_html)
41
+
42
+ elif screenshot_type == "html":
43
+ # HTMLをbase64にエンコードしてdata URLとして読み込む
44
+ html_base64 = base64.b64encode(url_or_html.encode('utf-8')).decode('utf-8')
45
+ driver.get(f"data:text/html;base64,{html_base64}")
46
+ else:
47
+ raise ValueError("screenshot_typeは'url'または'html'を指定してください。")
48
+
49
+ time.sleep(wait_time) # ページの読み込みを待機
50
+
51
+ # フルページサイズを取得 (JavaScript)
52
+ width = driver.execute_script(
53
+ "return Math.max(document.body.scrollWidth, document.body.offsetWidth, "
54
+ "document.documentElement.clientWidth, document.documentElement.scrollWidth, "
55
+ "document.documentElement.offsetWidth);"
56
+ )
57
+ height = driver.execute_script(
58
+ "return Math.max(document.body.scrollHeight, document.body.offsetHeight, "
59
+ "document.documentElement.clientHeight, document.documentElement.scrollHeight, "
60
+ "document.documentElement.offsetHeight);"
61
+ )
62
+
63
+ # ウィンドウサイズを設定(巨大なページに対する制限付き)
64
+ driver.set_window_size(min(width + 100, 1920), min(height + 100, 5000)) # 最大幅1920px, 最大高さ5000px
65
+ time.sleep(1) # レンダリング待機
66
+
67
+ # スクリーンショットを一時ファイルに保存
68
+ with tempfile.NamedTemporaryFile(suffix=".png", delete=False) as temp:
69
+ temp_filename = temp.name
70
+ driver.save_screenshot(temp_filename)
71
+
72
+ driver.quit()
73
+
74
+ # 画像を読み込んで返す
75
+ image = Image.open(temp_filename)
76
+ os.unlink(temp_filename) # 一時ファイルを削除
77
+
78
+ return image, "スクリーンショットを取得しました。"
79
+
80
+ except (WebDriverException, TimeoutException, ValueError) as e:
81
+ driver.quit()
82
+ return None, f"エラー: {str(e)}"
83
  except Exception as e:
 
 
84
  driver.quit()
85
+ return None, f"予期しないエラー: {str(e)}"
86
 
87
+ # Gradioインターフェース (URLとHTMLの両方に対応)
88
+ with gr.Blocks(title="Web Screenshot Tool") as demo:
89
+ gr.Markdown("# ウェブページ & HTML スクリーンショットツール")
90
+ gr.Markdown("URLまたはHTMLコードを入力して、フルページのスクリーンショットを取得します。")
91
+
92
+ with gr.Tab("URLから取得"):
93
+ url_input = gr.Textbox(label="URL", placeholder="https://example.com")
94
+ url_wait_time = gr.Slider(minimum=1, maximum=10, value=3, step=1, label="待機時間 (秒)")
95
+ url_button = gr.Button("スクリーンショットを取得 (URL)")
96
+ url_image_out = gr.Image(label="スクリーンショット (URL)")
97
+ url_text_out = gr.Textbox(label="結果 (URL)")
98
+
99
+ url_button.click(
100
+ take_screenshot,
101
+ inputs=[url_input, url_wait_time, gr.State("url")], # "url"を指定
102
+ outputs=[url_image_out, url_text_out]
103
+ )
104
+
105
+ with gr.Tab("HTMLから取得"):
106
+ html_input = gr.Textbox(label="HTMLコード", placeholder="<p>Hello, world!</p>", lines=5)
107
+ html_wait_time = gr.Slider(minimum=1, maximum=10, value=3, step=1, label="待機時間 (秒)")
108
+ html_button = gr.Button("スクリーンショットを取得 (HTML)")
109
+ html_image_out = gr.Image(label="スクリーンショット (HTML)")
110
+ html_text_out = gr.Textbox(label="結果 (HTML)")
111
+
112
+ html_button.click(
113
+ take_screenshot,
114
+ inputs=[html_input, html_wait_time, gr.State("html")], # "html"を指定
115
+ outputs=[html_image_out, html_text_out]
116
+ )
117
+
118
+ demo.launch()