tomo2chin2 commited on
Commit
e170610
·
verified ·
1 Parent(s): ee6f0ce

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +55 -68
app.py CHANGED
@@ -10,98 +10,82 @@ import tempfile
10
  import time
11
  import os
12
 
13
- def get_full_dimensions(driver):
14
- """
15
- <body>と<html>の scrollWidth/scrollHeight を比較して
16
- ページ全体の幅・高さを返す
17
- """
18
- body_w = driver.execute_script("return document.body.scrollWidth")
19
- body_h = driver.execute_script("return document.body.scrollHeight")
20
- html_w = driver.execute_script("return document.documentElement.scrollWidth")
21
- html_h = driver.execute_script("return document.documentElement.scrollHeight")
22
- full_width = max(body_w, html_w)
23
- full_height = max(body_h, html_h)
24
- return full_width, full_height
25
-
26
- def scroll_to_bottom(driver):
27
  """
28
- 一旦ページの最下部までスクロールし、
29
- Lazy Loadなどで追加要素が生成されるのを待つ
30
  """
31
- last_height = driver.execute_script("return document.body.scrollHeight")
32
- while True:
33
- driver.execute_script("window.scrollTo(0, document.body.scrollHeight);")
34
- time.sleep(1) # スクロール後の描画待ち
35
- new_height = driver.execute_script("return document.body.scrollHeight")
36
- if new_height == last_height:
37
- break
38
- last_height = new_height
39
 
40
- def render_fullpage_screenshot(html_code):
41
- # HTMLを一時ファイルに保存
42
  tmp_file = tempfile.NamedTemporaryFile(suffix=".html", delete=False)
43
  tmp_path = tmp_file.name
44
  tmp_file.write(html_code.encode('utf-8'))
45
  tmp_file.close()
46
 
47
- # ヘッドレスChrome起動オプション
48
  options = Options()
49
- options.add_argument("--headless")
50
- options.add_argument("--no-sandbox")
51
- options.add_argument("--disable-dev-shm-usage")
52
- options.add_argument("--force-device-scale-factor=1")
53
 
54
  try:
55
  driver = webdriver.Chrome(options=options)
56
- # 1) とりあえず適当なウィンドウサイズで開く
57
  driver.set_window_size(1200, 800)
58
  driver.get("file://" + tmp_path)
59
 
60
- # ページロード完了待ち
61
  WebDriverWait(driver, 10).until(
62
  EC.presence_of_element_located((By.TAG_NAME, "body"))
63
  )
 
 
 
 
 
 
 
 
 
64
  time.sleep(1)
65
 
66
- # ---- (A) 一度ページ全体のサイズを取得してウィンドウを拡張 ----
67
- w1, h1 = get_full_dimensions(driver)
68
- driver.set_window_size(w1, h1)
69
- time.sleep(1)
70
 
71
- # ---- (B) ページ下端までスクロールしてLazy Load等を発火させる ----
72
- scroll_to_bottom(driver)
73
- time.sleep(1)
74
 
75
- # 再度サイズを取得して変化があれば再設定
76
- w2, h2 = get_full_dimensions(driver)
77
- if (w2 != w1) or (h2 != h1):
78
- driver.set_window_size(w2, h2)
79
- time.sleep(1)
80
- # 念のためもう一度最下部へ
81
- scroll_to_bottom(driver)
82
- time.sleep(1)
83
 
84
- # ---- (C) スクロールバーを非表示にする(不要ならコメントアウト)----
85
- driver.execute_script("""
86
- document.documentElement.style.overflow = 'hidden';
87
- document.body.style.overflow = 'hidden';
88
- """)
89
- time.sleep(1)
90
 
91
- # overflow: hidden による再レイアウトでサイズが変わる可能性がある
92
- w3, h3 = get_full_dimensions(driver)
93
- driver.set_window_size(w3, h3)
94
- time.sleep(1)
 
95
 
96
- # ---- (D) ★最終的にトップへ戻す★ ----
97
- driver.execute_script("window.scrollTo(0, 0);")
98
- time.sleep(1)
 
99
 
100
- # ---- (E) スクリーンショット取得 ----
101
- png = driver.get_screenshot_as_png()
 
 
102
 
103
  except Exception as e:
104
- # エラー時は1x1の黒画像を返す
105
  return Image.new('RGB', (1, 1), color=(0, 0, 0))
106
 
107
  finally:
@@ -109,15 +93,18 @@ def render_fullpage_screenshot(html_code):
109
  if os.path.exists(tmp_path):
110
  os.remove(tmp_path)
111
 
112
- return Image.open(BytesIO(png))
113
 
114
  # Gradioインターフェース
115
  iface = gr.Interface(
116
  fn=render_fullpage_screenshot,
117
  inputs=gr.Textbox(lines=15, label="HTMLコード入力"),
118
- outputs=gr.Image(type="pil", label="ページ全体のスクリーンショット"),
119
- title="Full Page Screenshot App",
120
- description="HTMLをヘッドレスブラウザでレンダリングし、ページ全体を1枚の画像として取得します。"
 
 
 
121
  )
122
 
123
  if __name__ == "__main__":
 
10
  import time
11
  import os
12
 
13
+ def render_fullpage_screenshot(html_code):
 
 
 
 
 
 
 
 
 
 
 
 
 
14
  """
15
+ ページを少しずつスクロールしながら複数回のスクリーンショットを撮影し、
16
+ それらを縦方向に結合して1枚の長い画像にする。
17
  """
 
 
 
 
 
 
 
 
18
 
19
+ # 1) HTMLコードを一時ファイルに保存
 
20
  tmp_file = tempfile.NamedTemporaryFile(suffix=".html", delete=False)
21
  tmp_path = tmp_file.name
22
  tmp_file.write(html_code.encode('utf-8'))
23
  tmp_file.close()
24
 
25
+ # 2) ヘッドレスChrome(Chromium)起動オプション設定
26
  options = Options()
27
+ options.add_argument("--headless") # ヘッドレスモード
28
+ options.add_argument("--no-sandbox") # コンテナ環境でのサンドボックス無効化
29
+ options.add_argument("--disable-dev-shm-usage") # /dev/shmを使わない
30
+ options.add_argument("--force-device-scale-factor=1") # DPI/スケール固定
31
 
32
  try:
33
  driver = webdriver.Chrome(options=options)
34
+ # 適当な初期ウィンドウサイズに設定してページを読み込む
35
  driver.set_window_size(1200, 800)
36
  driver.get("file://" + tmp_path)
37
 
38
+ # 3) ページロード完了を待機
39
  WebDriverWait(driver, 10).until(
40
  EC.presence_of_element_located((By.TAG_NAME, "body"))
41
  )
42
+ # さらにフォントや外部リソースを読み込み終わるまで少し待つ
43
+ time.sleep(2)
44
+
45
+ # ---- スクロールバーを非表示にしたい場合 ----
46
+ # (ただし一部ページでレイアウトが変化する可能性があるので要注意)
47
+ driver.execute_script(
48
+ "document.documentElement.style.overflow = 'hidden';"
49
+ "document.body.style.overflow = 'hidden';"
50
+ )
51
  time.sleep(1)
52
 
53
+ # 4) 画面のビューポート高・ページ全体の高さを取得
54
+ viewport_height = driver.execute_script("return window.innerHeight")
55
+ scroll_height = driver.execute_script("return document.body.scrollHeight")
 
56
 
57
+ # スクロール+キャプチャを繰り返す
58
+ images = []
59
+ current_position = 0
60
 
61
+ while True:
62
+ # 現在の画面をスクリーンショット
63
+ png = driver.get_screenshot_as_png()
64
+ img = Image.open(BytesIO(png))
65
+ images.append(img)
 
 
 
66
 
67
+ # もし次のスクロールでページ末尾を超えるなら、ループを抜ける
68
+ if current_position + viewport_height >= scroll_height:
69
+ break
 
 
 
70
 
71
+ # 次のスクロール位置へ移動
72
+ current_position += viewport_height
73
+ driver.execute_script(f"window.scrollTo(0, {current_position})")
74
+ # スクロール後の描画待ち
75
+ time.sleep(1)
76
 
77
+ # 5) 取得した複数画像を縦方向に結合
78
+ total_width = max(img.width for img in images)
79
+ total_height = sum(img.height for img in images)
80
+ full_screenshot = Image.new('RGB', (total_width, total_height))
81
 
82
+ current_y = 0
83
+ for img in images:
84
+ full_screenshot.paste(img, (0, current_y))
85
+ current_y += img.height
86
 
87
  except Exception as e:
88
+ # 何らかのエラーが発生した場合、1x1の黒画像を返す
89
  return Image.new('RGB', (1, 1), color=(0, 0, 0))
90
 
91
  finally:
 
93
  if os.path.exists(tmp_path):
94
  os.remove(tmp_path)
95
 
96
+ return full_screenshot
97
 
98
  # Gradioインターフェース
99
  iface = gr.Interface(
100
  fn=render_fullpage_screenshot,
101
  inputs=gr.Textbox(lines=15, label="HTMLコード入力"),
102
+ outputs=gr.Image(type="pil", label="フルページスクリーンショット"),
103
+ title="Full Page Screenshot with Scrolling",
104
+ description=(
105
+ "ページを少しずつスクロールしながら複数回キャプチャを撮影し、"
106
+ "最終的に縦に結合して1枚の長い画像を生成します。"
107
+ )
108
  )
109
 
110
  if __name__ == "__main__":