import gradio as gr from selenium import webdriver from selenium.webdriver.chrome.options import Options from selenium.webdriver.common.by import By from selenium.webdriver.support.ui import WebDriverWait from selenium.webdriver.support import expected_conditions as EC from PIL import Image from io import BytesIO import tempfile import time import os def get_full_dimensions(driver): """ との scrollWidth/scrollHeight を比較して ページ全体の幅・高さを返す """ body_w = driver.execute_script("return document.body.scrollWidth") body_h = driver.execute_script("return document.body.scrollHeight") html_w = driver.execute_script("return document.documentElement.scrollWidth") html_h = driver.execute_script("return document.documentElement.scrollHeight") full_width = max(body_w, html_w) full_height = max(body_h, html_h) return full_width, full_height def scroll_to_bottom(driver): """ 一旦ページの最下部までスクロールし、 Lazy Loadなどで追加要素が生成されるのを待つ """ # 現在の高さ last_height = driver.execute_script("return document.body.scrollHeight") while True: # 最下部までスクロール driver.execute_script("window.scrollTo(0, document.body.scrollHeight);") time.sleep(1) # スクロール後の描画待ち new_height = driver.execute_script("return document.body.scrollHeight") if new_height == last_height: break last_height = new_height def render_fullpage_screenshot(html_code): # HTMLを一時ファイルに保存 tmp_file = tempfile.NamedTemporaryFile(suffix=".html", delete=False) tmp_path = tmp_file.name tmp_file.write(html_code.encode('utf-8')) tmp_file.close() # ヘッドレスChrome起動オプション options = Options() options.add_argument("--headless") options.add_argument("--no-sandbox") options.add_argument("--disable-dev-shm-usage") options.add_argument("--force-device-scale-factor=1") try: driver = webdriver.Chrome(options=options) # 1) とりあえず適当なウィンドウサイズで開く driver.set_window_size(1200, 800) driver.get("file://" + tmp_path) # ページロード完了待ち WebDriverWait(driver, 10).until( EC.presence_of_element_located((By.TAG_NAME, "body")) ) time.sleep(1) # 2) ページ全体サイズを取得してウィンドウを拡張 # → Lazy Loadがあればスクロールして要素を読み込む max_iterations = 3 for _ in range(max_iterations): # ページ全体の幅・高さを取得 w1, h1 = get_full_dimensions(driver) # ウィンドウをそのサイズに合わせる driver.set_window_size(w1, h1) time.sleep(1) # 一度最下部までスクロールし、Lazy Load等を促す scroll_to_bottom(driver) # 再度サイズを取得 w2, h2 = get_full_dimensions(driver) # 変化がなければ打ち切り if (w1 == w2) and (h1 == h2): break # 3) 最後にスクロールバーを消したい場合はここでoverflow: hidden driver.execute_script(""" document.documentElement.style.overflow = 'hidden'; document.body.style.overflow = 'hidden'; """) time.sleep(1) # overflow: hidden による再レイアウトを考慮してもう一度調整 w3, h3 = get_full_dimensions(driver) driver.set_window_size(w3, h3) time.sleep(1) # 4) 最終的にスクリーンショットを撮る png = driver.get_screenshot_as_png() except Exception as e: # エラー時は1x1の黒画像を返す return Image.new('RGB', (1, 1), color=(0, 0, 0)) finally: driver.quit() if os.path.exists(tmp_path): os.remove(tmp_path) return Image.open(BytesIO(png)) # Gradioインターフェース iface = gr.Interface( fn=render_fullpage_screenshot, inputs=gr.Textbox(lines=15, label="HTMLコード入力"), outputs=gr.Image(type="pil", label="ページ全体のスクリーンショット"), title="Full Page Screenshot App", description="HTMLをヘッドレスブラウザでレンダリングし、ページ全体を1枚の画像として取得します。" ) if __name__ == "__main__": iface.launch()