File size: 4,582 Bytes
b26e489
 
e0538f9
 
 
 
b26e489
 
e0538f9
 
 
b26e489
803f7c6
 
600cc03
 
803f7c6
 
 
 
 
 
 
 
 
600cc03
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
fbe2dc1
600cc03
b26e489
 
 
 
e0538f9
fbe2dc1
e0538f9
fbe2dc1
 
 
 
e0538f9
b26e489
 
600cc03
fbe2dc1
b26e489
e0538f9
600cc03
e0538f9
 
 
600cc03
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
f1bfdc2
 
 
 
600cc03
fbe2dc1
600cc03
 
 
 
e0538f9
600cc03
b26e489
e0538f9
 
803f7c6
e0538f9
 
b26e489
 
 
 
e0538f9
b26e489
 
fbe2dc1
b26e489
fbe2dc1
b26e489
fbe2dc1
 
 
b26e489
 
 
 
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
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):
    """
    <body>と<html>の 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()