Spaces:
Sleeping
Sleeping
Refactor Dockerfile and update screenshot capture: streamline Chrome and ChromeDriver installation, enhance memory settings, and improve cleanup process in the capture function.
Browse files- Dockerfile +38 -8
- pyproject.toml +1 -0
- src/modules/apps/__init__.py +26 -6
Dockerfile
CHANGED
|
@@ -1,19 +1,49 @@
|
|
| 1 |
# Use a Python image with uv pre-installed
|
| 2 |
FROM ghcr.io/astral-sh/uv:python3.11-bookworm
|
| 3 |
|
| 4 |
-
# Install Chrome and dependencies
|
|
|
|
| 5 |
RUN wget -q -O - https://dl-ssl.google.com/linux/linux_signing_key.pub | apt-key add -
|
| 6 |
RUN sh -c 'echo "deb [arch=amd64] http://dl.google.com/linux/chrome/deb/ stable main" >> /etc/apt/sources.list.d/google-chrome.list'
|
| 7 |
-
RUN apt-get -y update
|
| 8 |
-
|
| 9 |
-
|
| 10 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 11 |
RUN apt-get install -yqq unzip
|
| 12 |
-
RUN
|
| 13 |
-
|
|
|
|
|
|
|
|
|
|
| 14 |
|
| 15 |
-
#
|
| 16 |
ENV DISPLAY=:99
|
|
|
|
|
|
|
|
|
|
|
|
|
| 17 |
|
| 18 |
# Create a non-root user
|
| 19 |
RUN useradd -m -u 1000 appuser
|
|
|
|
| 1 |
# Use a Python image with uv pre-installed
|
| 2 |
FROM ghcr.io/astral-sh/uv:python3.11-bookworm
|
| 3 |
|
| 4 |
+
# Install Chrome and its dependencies
|
| 5 |
+
RUN apt-get -y update && apt-get install -y wget gnupg2
|
| 6 |
RUN wget -q -O - https://dl-ssl.google.com/linux/linux_signing_key.pub | apt-key add -
|
| 7 |
RUN sh -c 'echo "deb [arch=amd64] http://dl.google.com/linux/chrome/deb/ stable main" >> /etc/apt/sources.list.d/google-chrome.list'
|
| 8 |
+
RUN apt-get -y update && apt-get install -y \
|
| 9 |
+
google-chrome-stable \
|
| 10 |
+
fonts-ipafont-gothic \
|
| 11 |
+
fonts-wqy-zenhei \
|
| 12 |
+
fonts-thai-tlwg \
|
| 13 |
+
fonts-kacst \
|
| 14 |
+
fonts-symbola \
|
| 15 |
+
fonts-noto \
|
| 16 |
+
fonts-freefont-ttf \
|
| 17 |
+
libxss1 \
|
| 18 |
+
libx11-xcb1 \
|
| 19 |
+
libxcomposite1 \
|
| 20 |
+
libxcursor1 \
|
| 21 |
+
libxdamage1 \
|
| 22 |
+
libxi6 \
|
| 23 |
+
libxtst6 \
|
| 24 |
+
libnss3 \
|
| 25 |
+
libcups2 \
|
| 26 |
+
libxrandr2 \
|
| 27 |
+
libasound2 \
|
| 28 |
+
libatk1.0-0 \
|
| 29 |
+
libatk-bridge2.0-0 \
|
| 30 |
+
libgtk-3-0 \
|
| 31 |
+
libgbm1
|
| 32 |
+
|
| 33 |
+
# Install chromedriver
|
| 34 |
RUN apt-get install -yqq unzip
|
| 35 |
+
RUN CHROMEDRIVER_VERSION=$(curl -sS chromedriver.storage.googleapis.com/LATEST_RELEASE) && \
|
| 36 |
+
wget -O /tmp/chromedriver.zip http://chromedriver.storage.googleapis.com/$CHROMEDRIVER_VERSION/chromedriver_linux64.zip && \
|
| 37 |
+
unzip /tmp/chromedriver.zip chromedriver -d /usr/local/bin/ && \
|
| 38 |
+
chmod +x /usr/local/bin/chromedriver && \
|
| 39 |
+
rm /tmp/chromedriver.zip
|
| 40 |
|
| 41 |
+
# Set display port and shared memory settings
|
| 42 |
ENV DISPLAY=:99
|
| 43 |
+
ENV DBUS_SESSION_BUS_ADDRESS=/dev/null
|
| 44 |
+
|
| 45 |
+
# Create a shared memory volume
|
| 46 |
+
VOLUME /dev/shm
|
| 47 |
|
| 48 |
# Create a non-root user
|
| 49 |
RUN useradd -m -u 1000 appuser
|
pyproject.toml
CHANGED
|
@@ -11,6 +11,7 @@ dependencies = [
|
|
| 11 |
"numpy>=2.2.3",
|
| 12 |
"pytest>=8.3.4",
|
| 13 |
"selenium>=4.29.0",
|
|
|
|
| 14 |
]
|
| 15 |
|
| 16 |
[tool.black]
|
|
|
|
| 11 |
"numpy>=2.2.3",
|
| 12 |
"pytest>=8.3.4",
|
| 13 |
"selenium>=4.29.0",
|
| 14 |
+
"psutil>=5.9.0",
|
| 15 |
]
|
| 16 |
|
| 17 |
[tool.black]
|
src/modules/apps/__init__.py
CHANGED
|
@@ -19,8 +19,9 @@ def capture_page(url: str, output_file: str = "screenshot.png"):
|
|
| 19 |
:param output_file: The filename to save the screenshot.
|
| 20 |
"""
|
| 21 |
options = Options()
|
|
|
|
| 22 |
# Basic options
|
| 23 |
-
options.add_argument('--headless')
|
| 24 |
options.add_argument('--no-sandbox') # Required in Docker
|
| 25 |
options.add_argument('--disable-dev-shm-usage') # Required in Docker
|
| 26 |
|
|
@@ -32,16 +33,24 @@ def capture_page(url: str, output_file: str = "screenshot.png"):
|
|
| 32 |
|
| 33 |
# Resource configuration
|
| 34 |
options.add_argument('--window-size=1920,1080')
|
| 35 |
-
options.add_argument('--
|
| 36 |
-
options.add_argument('--disable-features=site-per-process')
|
| 37 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 38 |
|
| 39 |
# Additional stability options
|
| 40 |
options.add_argument('--ignore-certificate-errors')
|
| 41 |
-
options.add_argument('--allow-insecure-localhost')
|
| 42 |
options.add_argument('--disable-setuid-sandbox')
|
| 43 |
options.add_argument('--disable-web-security')
|
| 44 |
|
|
|
|
|
|
|
|
|
|
|
|
|
| 45 |
# Set up Chrome service with explicit path to chromedriver and logging
|
| 46 |
service = Service(
|
| 47 |
executable_path='/usr/local/bin/chromedriver',
|
|
@@ -83,7 +92,18 @@ def capture_page(url: str, output_file: str = "screenshot.png"):
|
|
| 83 |
raise
|
| 84 |
finally:
|
| 85 |
print("Closing Chrome...")
|
| 86 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 87 |
|
| 88 |
except Exception as e:
|
| 89 |
print(f"Error initializing Chrome: {str(e)}")
|
|
|
|
| 19 |
:param output_file: The filename to save the screenshot.
|
| 20 |
"""
|
| 21 |
options = Options()
|
| 22 |
+
|
| 23 |
# Basic options
|
| 24 |
+
options.add_argument('--headless=new') # New headless mode
|
| 25 |
options.add_argument('--no-sandbox') # Required in Docker
|
| 26 |
options.add_argument('--disable-dev-shm-usage') # Required in Docker
|
| 27 |
|
|
|
|
| 33 |
|
| 34 |
# Resource configuration
|
| 35 |
options.add_argument('--window-size=1920,1080')
|
| 36 |
+
options.add_argument('--disable-features=NetworkService,NetworkServiceInProcess')
|
| 37 |
+
options.add_argument('--disable-features=site-per-process')
|
| 38 |
+
|
| 39 |
+
# Memory and process settings
|
| 40 |
+
options.add_argument('--single-process') # Run in single process mode
|
| 41 |
+
options.add_argument('--memory-pressure-off')
|
| 42 |
+
options.add_argument('--disable-crash-reporter')
|
| 43 |
+
options.add_argument('--disable-breakpad') # Disable crash reporting
|
| 44 |
|
| 45 |
# Additional stability options
|
| 46 |
options.add_argument('--ignore-certificate-errors')
|
|
|
|
| 47 |
options.add_argument('--disable-setuid-sandbox')
|
| 48 |
options.add_argument('--disable-web-security')
|
| 49 |
|
| 50 |
+
# Set specific shared memory /dev/shm size (if needed)
|
| 51 |
+
options.add_argument('--disable-dev-shm-usage')
|
| 52 |
+
options.add_argument('--shm-size=2g')
|
| 53 |
+
|
| 54 |
# Set up Chrome service with explicit path to chromedriver and logging
|
| 55 |
service = Service(
|
| 56 |
executable_path='/usr/local/bin/chromedriver',
|
|
|
|
| 92 |
raise
|
| 93 |
finally:
|
| 94 |
print("Closing Chrome...")
|
| 95 |
+
try:
|
| 96 |
+
driver.close() # Close current window
|
| 97 |
+
driver.quit() # Quit browser completely
|
| 98 |
+
import psutil # For process cleanup
|
| 99 |
+
current_pid = os.getpid()
|
| 100 |
+
current_process = psutil.Process(current_pid)
|
| 101 |
+
children = current_process.children(recursive=True)
|
| 102 |
+
for child in children:
|
| 103 |
+
if 'chrome' in child.name().lower():
|
| 104 |
+
child.terminate()
|
| 105 |
+
except Exception as cleanup_error:
|
| 106 |
+
print(f"Error during cleanup: {cleanup_error}")
|
| 107 |
|
| 108 |
except Exception as e:
|
| 109 |
print(f"Error initializing Chrome: {str(e)}")
|