Search code examples
pythonflaskpython-asynciopyppeteer

RuntimeError: Event loop is closed. Pyppeteer


I am trying to write a program that handles HTTP requests and takes a screenshot of the links in the query parameters. I want to make it so that the browser stays open and requests create tabs in order to save RAM. The problem is that the first request is handled as it should be: the program returns a screenshot. But the second request fails. "RuntimeError: Event loop is closed".

#main.py

from flask import Flask, Response, request
from schedule_gen import capture_screenshot


app = Flask(__name__)

@app.route('/schedule', methods=['GET'])
async def schedule():
    # Processing query parameters.
    url = request.args.get('url')
    can_cache = request.args.get('canCache', False)

    if url is None:
        return "No url"

    screenshot = await capture_screenshot(url)
    return Response(screenshot, mimetype='image/png')



if __name__ == '__main__':
    app.run(debug=True, port=8800, host='0.0.0.0')

#schedule_gen

from pyppeteer import launch

browser = None


async def get_browser():
    global browser
    if browser is None:
        browser = await launch(
            options={'args': ['--no-sandbox']},
            handleSIGINT=False,
            handleSIGTERM=False,
            handleSIGHUP=False
        )
    return browser


async def capture_screenshot(url):
    b = await get_browser()
    page = await b.newPage()

    # Set the viewport height to match the entire page
    await page.setViewport({'width': 1920, 'height': 0})

    await page.goto(url)

    screenshot = await page.screenshot({'fullPage': True})

    await page.close()
    return screenshot

I tried all sorts of options, but none of them worked.


Solution

  • You are mixing Flask synchronous request handling with asynchronous functions but Flask dont allow that, you can use Quart to solve this. First install it pip install quart then in main.py modify it like this:

    from quart import Quart, Response, request
    from schedule_gen import capture_screenshot
    
    app = Quart(__name__)
    
    @app.route('/schedule', methods=['GET'])
    async def schedule():
        # Processing query parameters.
        url = request.args.get('url')
        can_cache = request.args.get('canCache', False)
    
        if url is None:
            return "No url"
    
        screenshot = await capture_screenshot(url)
        return Response(screenshot, mimetype='image/png')
    
    if __name__ == '__main__':
        app.run(debug=True, port=8800, host='0.0.0.0')