[Python] Selenium driverless on Google Cloud Run

Discussão em 'Python' iniciado por Stack, Julho 19, 2025.

  1. Stack

    Stack Membro Participativo

    I am trying to run selenium driverless on google cloud run but I get the error:

    "selenium_driverless.types.webelement.NoSuchElementException"

    And this happens when trying to locate an email text field. I can run this code just fine on my computer and it works great on headless and headful. How can I fix this issue? I already gave the cloud run instance 16 Gib memory and 4 cores so there's enough recourses. I think the env is still missing something, probs an issue in my Dockerfile.

    Dockerfile

    # Use Python 3.11 slim image as base
    FROM python:3.11-slim

    # Set environment variables
    ENV PYTHONUNBUFFERED=1
    ENV PYTHONDONTWRITEBYTECODE=1
    ENV PORT=8080

    # Install system dependencies required for Chrome and Selenium
    RUN apt-get update && apt-get install -y \
    wget \
    gnupg2 \
    unzip \
    curl \
    xvfb \
    xauth \
    ca-certificates \
    fonts-liberation \
    fonts-freefont-ttf \
    libasound2 \
    libatk-bridge2.0-0 \
    libatk1.0-0 \
    libatspi2.0-0 \
    libcups2 \
    libdbus-1-3 \
    libdrm2 \
    libgtk-3-0 \
    libnspr4 \
    libnss3 \
    libwayland-client0 \
    libxcomposite1 \
    libxdamage1 \
    libxfixes3 \
    libxkbcommon0 \
    libxrandr2 \
    xdg-utils \
    libu2f-udev \
    libvulkan1 \
    gpg \
    && rm -rf /var/lib/apt/lists/*

    # Add Google Chrome's signing key and repository (no apt-key usage)
    RUN mkdir -p /etc/apt/keyrings && \
    curl -fsSL https://dl.google.com/linux/linux_signing_key.pub | gpg --dearmor -o /etc/apt/keyrings/google.gpg && \
    echo "deb [arch=amd64 signed-by=/etc/apt/keyrings/google.gpg] http://dl.google.com/linux/chrome/deb/ stable main" \
    > /etc/apt/sources.list.d/google-chrome.list

    # Install Google Chrome
    RUN apt-get update && apt-get install -y \
    google-chrome-stable \
    && rm -rf /var/lib/apt/lists/*

    # Verify Chrome installation
    RUN google-chrome --version

    # Create a non-root user for security
    RUN useradd -m -u 1000 appuser

    # Set the working directory
    WORKDIR /app

    # Copy requirements first for better Docker layer caching
    COPY requirements.txt .

    # Install Python dependencies
    RUN pip install --no-cache-dir -r requirements.txt

    # Copy application files
    COPY . .

    # Create necessary directories and set permissions
    RUN mkdir -p /app/temp \
    && mkdir -p /home/appuser/.config/google-chrome \
    && chown -R appuser:appuser /app \
    && chown -R appuser:appuser /home/appuser \
    && chmod +x /app

    # Switch to non-root user
    USER appuser

    # Expose the port
    EXPOSE 8080

    # Run the application
    CMD ["python", "main.py"]


    python code

    from flask import Flask, request, jsonify, make_response
    from datetime import datetime, timezone, timedelta
    from selenium_driverless.types.by import By
    from selenium_driverless import webdriver
    from google.oauth2 import service_account
    from google.cloud import firestore
    from flask_cors import CORS
    from typing import Optional
    import traceback
    import warnings
    import asyncio
    import random
    import time
    import json
    import os

    app = Flask(__name__)

    CORS(app, origins=[
    "https://theprofilebuilder.com",
    "http://localhost:3000",
    "http://127.0.0.1:3000"
    ])

    async def extend_auth(db, email, password, retry_count=0):
    proxy = random_proxy()
    if not proxy:
    print("No proxy available")

    try:
    options = webdriver.ChromeOptions()

    options.binary_location = CHROME_PATH if TEST_MODE else "/usr/bin/google-chrome"

    options.add_argument("--disable-features=DisableLoadExtensionCommandLineSwitch")
    options.add_argument("--headless=new")
    options.add_argument('--no-sandbox')
    options.add_argument('--disable-dev-shm-usage')
    options.add_argument('--disable-gpu')
    options.add_argument('--disable-software-rasterizer')

    async with webdriver.Chrome(options=options) as driver:
    # Set up proxy if available
    if proxy:
    ip, port, username, proxyPass = parse_proxy(proxy)
    proxy_url = f"http://{username}:{proxyPass}@{ip}:{port}/"
    await driver.set_single_proxy(proxy_url)

    try:
    # Navigate to the signin page
    await driver.get("https://app.paywithextend.com/signin", wait_load=True)

    await asyncio.sleep(1.0)

    # Wait for email field and fill it
    # Error here which is "Page interaction error: NoSuchElementException()"
    email_field = await driver.find_element(By.ID, 'email', timeout=10)
    await email_field.send_keys(email)

    except Exception as page_error:
    print(f"Page interaction error: {repr(page_error)}")
    traceback.print_exc()

    return None

    except Exception as e:
    print(f"Browser automation error: {e}")

    return None

    @app.route('/authtask', methods=['GET', 'POST', 'OPTIONS'])
    def authtask():
    if request.method == 'OPTIONS':
    response = make_response()
    response.headers.add("Access-Control-Allow-Origin", "https://theprofilebuilder.com")
    response.headers.add("Access-Control-Allow-Headers", "Content-Type")
    response.headers.add("Access-Control-Allow-Methods", "GET, POST, OPTIONS")
    return response

    try:
    creds = service_account.Credentials.from_service_account_file("service.json")
    db = firestore.Client(credentials=creds)

    if request.method == 'GET':
    params = request.args
    else:
    params = request.json if request.is_json else request.form

    email = params.get('email')
    password = params.get('password')

    try:
    auth_token = asyncio.run(asyncio.wait_for(
    extend_auth(db, email, password),
    timeout=180
    ))

    if auth_token:
    return jsonify({"access_token": auth_token}), 200
    else:
    return jsonify({"error": "Failed to auth"}), 500

    except asyncio.TimeoutError:
    return jsonify({"error": "Authentication timeout after 3 minutes"}), 408

    except Exception as e:
    print("Exception caught in auth: " + str(e))
    return jsonify({"error": str(e)}), 500

    if __name__ == '__main__':
    port = int(os.environ.get('PORT', 8080))
    app.run(host='0.0.0.0', port=port)

    Continue reading...

Compartilhe esta Página