Пример #1
0
async def connect(options: dict = None, **kwargs: Any) -> Browser:
    """Connect to the existing chrome.

    ``browserWSEndpoint`` option is necessary to connect to the chrome. The
    format is ``ws://${host}:${port}/devtools/browser/<id>``. This value can
    get by :attr:`~pyppeteer.browser.Browser.wsEndpoint`.

    Available options are:

    * ``browserWSEndpoint`` (str): A browser websocket endpoint to connect to.
      (**required**)
    * ``ignoreHTTPSErrors`` (bool): Whether to ignore HTTPS errors. Defaults to
      ``False``.
    * ``slowMo`` (int|float): Slow down pyppeteer's by the specified amount of
      milliseconds.
    * ``logLevel`` (int|str): Log level to print logs. Defaults to same as the
      root logger.
    * ``loop`` (asyncio.AbstractEventLoop): Event loop (**experimental**).
    """
    options = merge_dict(options, kwargs)
    logLevel = options.get('logLevel')
    if logLevel:
        logging.getLogger('pyppeteer').setLevel(logLevel)

    browserWSEndpoint = options.get('browserWSEndpoint')
    if not browserWSEndpoint:
        raise BrowserError('Need `browserWSEndpoint` option.')
    connectionDelay = options.get('slowMo', 0)
    connection = Connection(browserWSEndpoint,
                            options.get('loop', asyncio.get_event_loop()),
                            connectionDelay)
    return await Browser.create(connection, options, None,
                                lambda: connection.send('Browser.close'))
Пример #2
0
async def connect(options: dict = None, **kwargs: Any) -> Browser:
    """Connect to the existing chrome.
    ``browserWSEndpoint`` or ``browserURL`` option is necessary to connect to
    the chrome. The format of ``browserWSEndpoint`` is
    ``ws://${host}:${port}/devtools/browser/<id>`` and format of ``browserURL``
    is ``http://127.0.0.1:9222```.
    The value of ``browserWSEndpoint`` can get by :attr:`~pyppeteer.browser.Browser.wsEndpoint`.
    Available options are:
    * ``browserWSEndpoint`` (str): A browser websocket endpoint to connect to.
    * ``browserURL`` (str): A browser URL to connect to.
    * ``ignoreHTTPSErrors`` (bool): Whether to ignore HTTPS errors. Defaults to
      ``False``.
    * ``defaultViewport`` (dict): Set a consistent viewport for each page.
      Defaults to an 800x600 viewport. ``None`` disables default viewport.
      * ``width`` (int): page width in pixels.
      * ``height`` (int): page height in pixels.
      * ``deviceScaleFactor`` (int|float): Specify device scale factor (can be
        thought as dpr). Defaults to ``1``.
      * ``isMobile`` (bool): Whether the ``meta viewport`` tag is taken into
        account. Defaults to ``False``.
      * ``hasTouch`` (bool): Specify if viewport supports touch events.
        Defaults to ``False``.
      * ``isLandscape`` (bool): Specify if viewport is in landscape mode.
        Defaults to ``False``.
    * ``slowMo`` (int|float): Slow down pyppeteer's by the specified amount of
      milliseconds.
    * ``logLevel`` (int|str): Log level to print logs. Defaults to same as the
      root logger.
    * ``loop`` (asyncio.AbstractEventLoop): Event loop (**experimental**).
    """
    options = merge_dict(options, kwargs)
    logLevel = options.get('logLevel')
    if logLevel:
        logging.getLogger('pyppeteer').setLevel(logLevel)

    browserWSEndpoint = options.get('browserWSEndpoint')
    if not browserWSEndpoint:
        browserURL = options.get('browserURL')
        if not browserURL:
            raise BrowserError(
                'Need `browserWSEndpoint` or `browserURL` option.')
        browserWSEndpoint = get_ws_endpoint(browserURL)
    connectionDelay = options.get('slowMo', 0)
    connection = Connection(browserWSEndpoint,
                            options.get('loop', asyncio.get_event_loop()),
                            connectionDelay)
    browserContextIds = (await
                         connection.send('Target.getBrowserContexts')).get(
                             'browserContextIds', [])
    ignoreHTTPSErrors = bool(options.get('ignoreHTTPSErrors', False))
    defaultViewport = options.get('defaultViewport', {
        'width': 800,
        'height': 600
    })
    return await Browser.create(connection, browserContextIds,
                                ignoreHTTPSErrors, defaultViewport, None,
                                lambda: connection.send('Browser.close'))
Пример #3
0
async def connect(options: dict = None, **kwargs: Any) -> Browser:
    "Connect to the existing chrome.\n\n    ``browserWSEndpoint`` option is necessary to connect to the chrome. The\n    format is ``ws://${host}:${port}/devtools/browser/<id>``. This value can\n    get by :attr:`~pyppeteer.browser.Browser.wsEndpoint`.\n\n    Available options are:\n\n    * ``browserWSEndpoint`` (str): A browser websocket endpoint to connect to.\n      (**required**)\n    * ``ignoreHTTPSErrors`` (bool): Whether to ignore HTTPS errors. Defaults to\n      ``False``.\n    * ``slowMo`` (int|float): Slow down pyppeteer's by the specified amount of\n      milliseconds.\n    "
    options = merge_dict(options, kwargs)
    browserWSEndpoint = options.get('browserWSEndpoint')
    if (not browserWSEndpoint):
        raise BrowserError('Need `browserWSEndpoint` option.')
    connection = Connection(browserWSEndpoint)
    return (await Browser.create(connection, options, None,
                                 (lambda: connection.send('Browser.close'))))
Пример #4
0
    async def launch(self) -> Browser:
        """Start chrome process and return `Browser` object."""
        env = self.options.get('env')
        self.chromeClosed = False
        self.connection: Optional[Connection] = None
        self.proc = subprocess.Popen(
            self.cmd,
            stdout=subprocess.DEVNULL,
            stderr=subprocess.DEVNULL,
            env=env,
        )

        def _close_process(*args: Any, **kwargs: Any) -> None:
            if not self.chromeClosed:
                asyncio.get_event_loop().run_until_complete(self.killChrome())

        # dont forget to close browser process
        atexit.register(_close_process)
        if self.options.get('handleSIGINT', True):
            signal.signal(signal.SIGINT, _close_process)
        if self.options.get('handleSIGTERM', True):
            signal.signal(signal.SIGTERM, _close_process)
        if self.options.get('handleSIGHUP', True):
            signal.signal(signal.SIGHUP, _close_process)

        connectionDelay = self.options.get('slowMo', 0)
        self.browserWSEndpoint = self._get_ws_endpoint()
        logger.info(f'Browser listening on: {self.browserWSEndpoint}')
        self.connection = Connection(self.browserWSEndpoint, connectionDelay)
        return await Browser.create(self.connection, self.options, self.proc,
                                    self.killChrome)
Пример #5
0
    async def launch(self):
        env = self.options.get("env")
        self.proc = await asyncio.subprocess.create_subprocess_exec(
            *self.cmd,
            stdout=asyncio.subprocess.DEVNULL,
            stderr=asyncio.subprocess.DEVNULL,
            env=env,
        )
        self.chromeClosed = False
        self.connection = None

        def _close_process(*args, **kwargs):
            if not self.chromeClosed:
                asyncio.ensure_future(self.killChrome())

        # dont forget to close browser process
        atexit.register(_close_process)
        if self.options.get("handleSIGINT", True):
            signal.signal(signal.SIGINT, _close_process)
        if self.options.get("handleSIGTERM", True):
            signal.signal(signal.SIGTERM, _close_process)
        if not sys.platform.startswith("win"):
            # SIGHUP is not defined on windows
            if self.options.get("handleSIGHUP", True):
                signal.signal(signal.SIGHUP, _close_process)

        connectionDelay = self.options.get("slowMo", 0.1)
        self.browserWSEndpoint = self._get_ws_endpoint()
        self.connection = Connection(self.browserWSEndpoint, connectionDelay)
        return await Browser.create(self.connection, self.options, self.proc,
                                    self.killChrome)
Пример #6
0
    async def launch(self) -> Browser:
        'Start chrome process and return `Browser` object.'
        env = self.options.get('env')
        self.chromeClosed = False
        self.connection = None
        self.proc = subprocess.Popen(self.cmd,
                                     stdout=subprocess.DEVNULL,
                                     stderr=subprocess.DEVNULL,
                                     env=env)

        def _close_process(*args: Any, **kwargs: Any) -> None:
            if (not self.chromeClosed):
                asyncio.get_event_loop().run_until_complete(self.killChrome())

        atexit.register(_close_process)
        if self.options.get('handleSIGINT', True):
            signal.signal(signal.SIGINT, _close_process)
        if self.options.get('handleSIGTERM', True):
            signal.signal(signal.SIGTERM, _close_process)
        if (not sys.platform.startswith('win')):
            if self.options.get('handleSIGHUP', True):
                signal.signal(signal.SIGHUP, _close_process)
        connectionDelay = self.options.get('slowMo', 0)
        self.browserWSEndpoint = self._get_ws_endpoint()
        logger.info(''.join(
            ['Browser listening on: ', '{}'.format(self.browserWSEndpoint)]))
        self.connection = Connection(self.browserWSEndpoint, connectionDelay)
        return (await Browser.create(self.connection, self.options, self.proc,
                                     self.killChrome))
Пример #7
0
 def launch(self) -> Browser:
     """Start chromium process."""
     self.proc = subprocess.Popen(
         self.cmd,
         stdout=subprocess.PIPE,
         stderr=subprocess.STDOUT,
     )
     atexit.register(self.killChrome)
     import time
     for _ in range(100):
         # wait for DevTools port to open for at least 10sec
         # setting timeout timer is bettter
         time.sleep(0.1)
         if self.proc.poll() is not None:
             raise BrowserError('Unexpectedly chrome process closed with '
                                f'return code: {self.proc.returncode}')
         msg = self.proc.stdout.readline().decode()
         if not msg:
             continue
         m = re.match(r'DevTools listening on (ws://.*)$', msg)
         if m is not None:
             break
     else:
         # This block called only when `for`-loop does not `break`
         raise BrowserError('Failed to connect DevTools port.')
     logger.debug(m.group(0))
     connectionDelay = self.options.get('slowMo', 0)
     connection = Connection(m.group(1).strip(), connectionDelay)
     return Browser(connection, self.options.get('ignoreHTTPSErrors',
                                                 False), self.killChrome)
Пример #8
0
async def connect(options: dict = None, **kwargs: Any) -> Browser:
    """Connect to the existing chrome.

    ``browserWSEndpoint`` option is necessary to connect to the chrome. The
    format is ``ws://${host}:${port}/devtools/browser/<id>``. This value can
    get by :attr:`~pyppeteer.browser.Browser.wsEndpoint`.

    Available options are:

    * ``browserWSEndpoint`` (str): A browser websocket endpoint to connect to.
      (**required**)
    * ``ignoreHTTPSErrors`` (bool): Whether to ignore HTTPS errors. Defaults to
      ``False``.
    * ``slowMo`` (int|float): Slow down pyppeteer's by the specified amount of
      milliseconds.
    """
    options = merge_dict(options, kwargs)
    browserWSEndpoint = options.get('browserWSEndpoint')
    if not browserWSEndpoint:
        raise BrowserError('Need `browserWSEndpoint` option.')
    connection = Connection(browserWSEndpoint)
    return await Browser.create(
        connection, options, None, lambda: connection.send('Browser.close'))
Пример #9
0
async def connect(options: dict = None, **kwargs: Any) -> Browser:
    """Connect to the existing chrome.

    ``browserWSEndpoint`` option is necessary to connect to the chrome. The
    format is ``ws://${host}:${port}/devtools/browser/<id>``. This value can
    get by :attr:`~pyppeteer.browser.Browser.wsEndpoint`.

    Available options are:

    * ``browserWSEndpoint`` (str): A browser websocket endpoint to connect to.
      (**required**)
    * ``ignoreHTTPSErrors`` (bool): Whether to ignore HTTPS errors. Defaults to
      ``False``.
    * ``slowMo`` (int|float): Slow down pyppeteer's by the specified amount of
      milliseconds.
    * ``logLevel`` (int|str): Log level to print logs. Defaults to same as the
      root logger.
    * ``loop`` (asyncio.AbstractEventLoop): Event loop (**experimental**).
    """
    options = merge_dict(options, kwargs)
    logLevel = options.get('logLevel')
    if logLevel:
        logging.getLogger('pyppeteer').setLevel(logLevel)

    browserWSEndpoint = options.get('browserWSEndpoint')
    if not browserWSEndpoint:
        raise BrowserError('Need `browserWSEndpoint` option.')
    connectionDelay = options.get('slowMo', 0)
    connection = Connection(browserWSEndpoint,
                            options.get('loop', asyncio.get_event_loop()),
                            connectionDelay)
    browserContextIds = (await connection.send('Target.getBrowserContexts')
                         ).get('browserContextIds', [])
    ignoreHTTPSErrors = bool(options.get('ignoreHTTPSErrors', False))
    return await Browser.create(
        connection, browserContextIds, ignoreHTTPSErrors, True, None,
        lambda: connection.send('Browser.close'))
Пример #10
0
 async def launch(self):
     env = self.options.get("env")
     self.proc = await asyncio.subprocess.create_subprocess_exec(
         *self.cmd,
         stdout=asyncio.subprocess.DEVNULL,
         stderr=asyncio.subprocess.DEVNULL,
         env=env,
     )
     self.chromeClosed = False
     self.connection = None
     # Signal handlers for exits used to be here
     connectionDelay = self.options.get("slowMo", 0.1)
     self.browserWSEndpoint = self._get_ws_endpoint()
     self.connection = Connection(self.browserWSEndpoint, connectionDelay)
     return await Browser.create(self.connection, self.options, self.proc,
                                 self.killChrome)
Пример #11
0
    async def launch(self) -> Browser:  # noqa: C901
        """Start chrome process and return `Browser` object."""
        self.chromeClosed = False
        self.connection: Optional[Connection] = None

        options = dict()
        options['env'] = self.env
        if not self.dumpio:
            # discard stdout, it's never read in any case.
            options['stdout'] = subprocess.DEVNULL
            options['stderr'] = subprocess.STDOUT

        self.proc = subprocess.Popen(  # type: ignore
            self.cmd,
            **options,
        )

        def _close_process(*args: Any, **kwargs: Any) -> None:
            if not self.chromeClosed:
                self._loop.run_until_complete(self.killChrome())

        # don't forget to close browser process
        if self.autoClose:
            atexit.register(_close_process)
        if self.handleSIGINT:
            signal.signal(signal.SIGINT, _close_process)
        if self.handleSIGTERM:
            signal.signal(signal.SIGTERM, _close_process)
        if not sys.platform.startswith('win'):
            # SIGHUP is not defined on windows
            if self.handleSIGHUP:
                signal.signal(signal.SIGHUP, _close_process)

        connectionDelay = self.slowMo
        self.browserWSEndpoint = get_ws_endpoint(self.url)
        logger.info(f'Browser listening on: {self.browserWSEndpoint}')
        self.connection = Connection(
            self.browserWSEndpoint,
            self._loop,
            connectionDelay,
        )
        browser = await Browser.create(self.connection, [],
                                       self.ignoreHTTPSErrors,
                                       self.defaultViewport, self.proc,
                                       self.killChrome)
        await self.ensureInitialPage(browser)
        return browser
Пример #12
0
    async def launch(self) -> Browser:  # noqa: C901
        """Start chrome process and return `Browser` object."""
        self.chromeClosed = False
        self.connection: Optional[Connection] = None

        options = dict()
        options['env'] = self.options.get('env')
        if not self.options.get('dumpio'):
            options['stdout'] = subprocess.PIPE
            options['stderr'] = subprocess.STDOUT

        self.proc = subprocess.Popen(  # type: ignore
            self.cmd,
            **options,
        )

        def _close_process(*args: Any, **kwargs: Any) -> None:
            if not self.chromeClosed:
                self._loop.run_until_complete(self.killChrome())

        # don't forget to close browser process
        if self.options.get('autoClose', True):
            atexit.register(_close_process)
        if self.options.get('handleSIGINT', True):
            signal.signal(signal.SIGINT, _close_process)
        if self.options.get('handleSIGTERM', True):
            signal.signal(signal.SIGTERM, _close_process)
        if not sys.platform.startswith('win'):
            # SIGHUP is not defined on windows
            if self.options.get('handleSIGHUP', True):
                signal.signal(signal.SIGHUP, _close_process)

        connectionDelay = self.options.get('slowMo', 0)
        self.browserWSEndpoint = self._get_ws_endpoint()
        logger.info(f'Browser listening on: {self.browserWSEndpoint}')
        self.connection = Connection(self.browserWSEndpoint, self._loop,
                                     connectionDelay)
        ignoreHTTPSErrors = bool(self.options.get('ignoreHTTPSErrors', False))
        setDefaultViewport = not self.options.get('appMode', False)
        browser = await Browser.create(self.connection, [], ignoreHTTPSErrors,
                                       setDefaultViewport, self.proc,
                                       self.killChrome)
        await self.ensureInitialPage(browser)
        return browser
Пример #13
0
    async def launch(self) -> Browser:
        """Start chrome process and return `Browser` object."""
        env = self.options.get('env', {})
        self.chromeClosed = False
        self.connection: Optional[Connection] = None
        self.proc = subprocess.Popen(
            self.cmd,
            stdout=subprocess.PIPE,
            stderr=subprocess.STDOUT,
            env=env,
        )

        def _close_process() -> None:
            if not self.chromeClosed:
                asyncio.get_event_loop().run_until_complete(self.killChrome())

        # dont forget to close browser process
        atexit.register(_close_process)

        import time
        for _ in range(100):
            # wait for DevTools port to open for at least 10sec
            # setting timeout timer is bettter
            time.sleep(0.1)
            if self.proc.poll() is not None:
                self._cleanup_tmp_user_data_dir()
                raise BrowserError('Unexpectedly chrome process closed with '
                                   f'return code: {self.proc.returncode}')
            msg = self.proc.stdout.readline().decode()
            if not msg:
                continue
            m = re.match(r'DevTools listening on (ws://.*)$', msg)
            if m is not None:
                break
        else:
            # This block called only when `for`-loop does not `break`
            raise BrowserError('Failed to connect DevTools port.')
        logger.debug(m.group(0))
        connectionDelay = self.options.get('slowMo', 0)
        self.browserWSEndpoint = m.group(1).strip()
        self.connection = Connection(self.browserWSEndpoint, connectionDelay)
        return await Browser.create(self.connection, self.options,
                                    self.killChrome)
Пример #14
0
 async def launch_chrome(self):
     self.chromeClosed = False
     self.connection = None
     self.proc = subprocess.Popen(
         self._launch_cmd(), stdout=subprocess.PIPE, stderr=subprocess.STDOUT
     )
     # Signal handlers for exits used to be here
     connectionDelay = self.slowMo
     self.browserWSEndpoint = launcher.get_ws_endpoint(self.url)
     self.connection = Connection(
         self.browserWSEndpoint, self._loop, connectionDelay
     )
     return await Browser.create(
         connection=self.connection,
         contextIds=[],
         ignoreHTTPSErrors=self.ignoreHTTPSErrors,
         defaultViewport=self.defaultViewport,
         process=self.proc,
         closeCallBack=self.killChrome,
     )
Пример #15
0
    async def launch(self):
        self.chromeClosed = False
        self.connection = None

        options = dict()
        options['env'] = self.env
        if not self.dumpio:
            options['stdout'] = asyncio.subprocess.PIPE
            options['stderr'] = asyncio.subprocess.STDOUT

        self.proc = await asyncio.subprocess.create_subprocess_exec(
            *self.cmd, **options)
        # Signal handlers for exits used to be here
        connectionDelay = self.slowMo
        self.browserWSEndpoint = await self._get_ws_endpoint()
        self.connection = Connection(self.browserWSEndpoint, self._loop,
                                     connectionDelay)

        browser = await Browser.create(
            self.connection, [], self.ignoreHTTPSErrors, self.defaultViewport,
            self.proc, self.killChrome)
        await self.ensureInitialPage(browser)
        return browser
Пример #16
0
 def launch(self) -> Browser:
     """Start chromium process."""
     self.proc = subprocess.Popen(
         self.cmd,
         stdout=subprocess.PIPE,
         stderr=subprocess.STDOUT,
     )
     atexit.register(self.killChrome)
     import time
     while True:
         time.sleep(0.1)
         msg = self.proc.stdout.readline().decode()
         if not msg:
             continue
         m = re.match(r'DevTools listening on (ws://.*)$', msg)
         if m is not None:
             break
     logger.debug(m.group(0))
     self.url = m.group(1).strip()
     connectionDelay = self.options.get('slowMo', 0)
     connection = Connection(self.url, connectionDelay)
     return Browser(connection, self.options.get('ignoreHTTPSErrors',
                                                 False), self.killChrome)
Пример #17
0
    async def launch(self) -> Browser:  # noqa: C901
        """Start chrome process and return `Browser` object."""
        self.chromeClosed = False
        self.connection: Optional[Connection] = None

        options = {}
        options['env'] = self.options.get('env')
        if not self.options.get('dumpio'):
            options['stdout'] = subprocess.DEVNULL
            options['stderr'] = subprocess.DEVNULL

        self.proc = subprocess.Popen(  # type: ignore
            self.cmd,
            **options,
        )

        def _close_process(*args: Any, **kwargs: Any) -> None:
            if not self.chromeClosed:
                asyncio.get_event_loop().run_until_complete(self.killChrome())

        # dont forget to close browser process
        atexit.register(_close_process)
        if self.options.get('handleSIGINT', True):
            signal.signal(signal.SIGINT, _close_process)
        if self.options.get('handleSIGTERM', True):
            signal.signal(signal.SIGTERM, _close_process)
        if not sys.platform.startswith('win'):
            # SIGHUP is not defined on windows
            if self.options.get('handleSIGHUP', True):
                signal.signal(signal.SIGHUP, _close_process)

        connectionDelay = self.options.get('slowMo', 0)
        self.browserWSEndpoint = self._get_ws_endpoint()
        logger.info(f'Browser listening on: {self.browserWSEndpoint}')
        self.connection = Connection(self.browserWSEndpoint, connectionDelay)
        return await Browser.create(self.connection, self.options, self.proc,
                                    self.killChrome)
Пример #18
0
    async def launch(self) -> Browser:
        'Start chrome process and return `Browser` object.'
        self.chromeClosed = False
        self.connection = None
        options = dict()
        options['env'] = self.options.get('env')
        if (not self.options.get('dumpio')):
            options['stdout'] = subprocess.PIPE
            options['stderr'] = subprocess.STDOUT
        self.proc = subprocess.Popen(self.cmd, **options)

        def _close_process(*args: Any, **kwargs: Any) -> None:
            if (not self.chromeClosed):
                self._loop.run_until_complete(self.killChrome())

        if self.options.get('autoClose', True):
            atexit.register(_close_process)
        if self.options.get('handleSIGINT', True):
            signal.signal(signal.SIGINT, _close_process)
        if self.options.get('handleSIGTERM', True):
            signal.signal(signal.SIGTERM, _close_process)
        if (not sys.platform.startswith('win')):
            if self.options.get('handleSIGHUP', True):
                signal.signal(signal.SIGHUP, _close_process)
        connectionDelay = self.options.get('slowMo', 0)
        self.browserWSEndpoint = self._get_ws_endpoint()
        logger.info(''.join(
            ['Browser listening on: ', '{}'.format(self.browserWSEndpoint)]))
        self.connection = Connection(self.browserWSEndpoint, self._loop,
                                     connectionDelay)
        ignoreHTTPSErrors = bool(self.options.get('ignoreHTTPSErrors', False))
        setDefaultViewport = (not self.options.get('appMode', False))
        browser = (await Browser.create(self.connection, [], ignoreHTTPSErrors,
                                        setDefaultViewport, self.proc,
                                        self.killChrome))
        (await self.ensureInitialPage(browser))
        return browser
Пример #19
0
    async def to_pdf():
        if app.config.get('CHROME_URL'):
            version_url = urljoin(app.config['CHROME_URL'], 'json/version')
            data = requests.get(version_url).json()
            con = Connection(data['webSocketDebuggerUrl'])
            browser = await Browser.create(con)

        else:
            chrome_dir = 'var/pyppeteer'
            if not os.path.exists(chrome_dir):
                os.mkdir(chrome_dir)

            tmp_chrome_dir = tempfile.mkdtemp(dir=chrome_dir)
            browser = await launch(executablePath='google-chrome',
                                   userDataDir=tmp_chrome_dir)

        page = await browser.newPage()

        async def request_intercepted(request):
            app.logger.debug('Intercepted URL: %s', request.url)
            if request.url == url:
                await request.respond({'body': html})
            else:
                await request.continue_()

        page.on('request', request_intercepted)
        await page.setRequestInterception(True)

        await page.goto(url)
        pdf = await page.pdf(format='A4')
        await browser.close()

        if not app.config.get('CHROME_URL'):
            shutil.rmtree(tmp_chrome_dir)

        return pdf