zoukankan      html  css  js  c++  java
  • sys:1: RuntimeWarning: coroutine 'Launcher.killChrome' was never awaited


    def
    ret_loop(): loop = events.new_event_loop() try: events.set_event_loop(loop) # loop.set_debug(debug) return loop.run_until_complete(get_browser()) # except Exception as e: finally: try: _cancel_all_tasks(loop) loop.run_until_complete(loop.shutdown_asyncgens()) finally: events.set_event_loop(None) loop.close() # print(e) # print('adfafdadsf') if __name__=='__main__': # asyncio.run(get_browser()) # asyncio.get_event_loop().run_until_complete(get_browser()) ret_loop()

    我自己写的这个ret_loop方法其实是照抄的

    asyncio.run
    __all__ = 'run',
    
    from . import coroutines
    from . import events
    from . import tasks
    
    
    def run(main, *, debug=False):
        """Execute the coroutine and return the result.
    
        This function runs the passed coroutine, taking care of
        managing the asyncio event loop and finalizing asynchronous
        generators.
    
        This function cannot be called when another asyncio event loop is
        running in the same thread.
    
        If debug is True, the event loop will be run in debug mode.
    
        This function always creates a new event loop and closes it at the end.
        It should be used as a main entry point for asyncio programs, and should
        ideally only be called once.
    
        Example:
    
            async def main():
                await asyncio.sleep(1)
                print('hello')
    
            asyncio.run(main())
        """
        if events._get_running_loop() is not None:
            raise RuntimeError(
                "asyncio.run() cannot be called from a running event loop")
    
        if not coroutines.iscoroutine(main):
            raise ValueError("a coroutine was expected, got {!r}".format(main))
    
        loop = events.new_event_loop()
        try:
            events.set_event_loop(loop)
            loop.set_debug(debug)
            return loop.run_until_complete(main)
        finally:
            try:
                _cancel_all_tasks(loop)
                loop.run_until_complete(loop.shutdown_asyncgens())
            finally:
                events.set_event_loop(None)
                loop.close()

    发现报错的是最后一句话,完整的错误信息如下:

    Error in atexit._run_exitfuncs:
    Traceback (most recent call last):
      File "C:UsersAdministratorAppDataLocalProgramsPythonPython38libsite-packagespyppeteerlauncher.py", line 174, in _close_process
        self._loop.run_until_complete(self.killChrome())
      File "C:UsersAdministratorAppDataLocalProgramsPythonPython38libasyncioase_events.py", line 591, in run_until_complete
        self._check_closed()
      File "C:UsersAdministratorAppDataLocalProgramsPythonPython38libasyncioase_events.py", line 508, in _check_closed
        raise RuntimeError('Event loop is closed')
    RuntimeError: Event loop is closed
    sys:1: RuntimeWarning: coroutine 'Launcher.killChrome' was never awaited
    RuntimeWarning: Enable tracemalloc to get the object allocation traceback

    那这个

    'Launcher.killChrome'为什么失败呢?
    找到这个方法:
    #!/usr/bin/env python3
    # -*- coding: utf-8 -*-
    
    """Chromium process launcher module."""
    
    import asyncio
    import atexit
    import json
    from urllib.request import urlopen
    from urllib.error import URLError
    import logging
    import os
    import os.path
    from pathlib import Path
    import shutil
    import signal
    import subprocess
    import sys
    import tempfile
    import time
    from typing import Any, Dict, List, TYPE_CHECKING
    
    from pyppeteer import __pyppeteer_home__
    from pyppeteer.browser import Browser
    from pyppeteer.connection import Connection
    from pyppeteer.errors import BrowserError
    from pyppeteer.helper import addEventListener, debugError, removeEventListeners
    from pyppeteer.target import Target
    from pyppeteer.util import check_chromium, chromium_executable
    from pyppeteer.util import download_chromium, merge_dict, get_free_port
    
    if TYPE_CHECKING:
        from typing import Optional  # noqa: F401
    
    logger = logging.getLogger(__name__)
    
    pyppeteer_home = Path(__pyppeteer_home__)
    CHROME_PROFILE_PATH = pyppeteer_home / '.dev_profile'
    
    DEFAULT_ARGS = [
        '--disable-background-networking',
        '--disable-background-timer-throttling',
        '--disable-breakpad',
        '--disable-browser-side-navigation',
        '--disable-client-side-phishing-detection',
        '--disable-default-apps',
        '--disable-dev-shm-usage',
        '--disable-extensions',
        '--disable-features=site-per-process',
        '--disable-hang-monitor',
        '--disable-popup-blocking',
        '--disable-prompt-on-repost',
        '--disable-sync',
        '--disable-translate',
        '--metrics-recording-only',
        '--no-first-run',
        '--safebrowsing-disable-auto-update',
    ]
    
    AUTOMATION_ARGS = [
        '--enable-automation',
        '--password-store=basic',
        '--use-mock-keychain',
    ]
    
    
    class Launcher(object):
        """Chrome process launcher class."""
    
        def __init__(self, options: Dict[str, Any] = None,  # noqa: C901
                     **kwargs: Any) -> None:
            """Make new launcher."""
            self.options = merge_dict(options, kwargs)
            self.port = get_free_port()
            self.url = f'http://127.0.0.1:{self.port}'
            self.chrome_args: List[str] = []
            self._loop = self.options.get('loop', asyncio.get_event_loop())
    
            logLevel = self.options.get('logLevel')
            if logLevel:
                logging.getLogger('pyppeteer').setLevel(logLevel)
    
            if not self.options.get('ignoreDefaultArgs', False):
                self.chrome_args.extend(DEFAULT_ARGS)
                self.chrome_args.append(
                    f'--remote-debugging-port={self.port}',
                )
    
            self.chromeClosed = True
            if self.options.get('appMode', False):
                self.options['headless'] = False
            elif not self.options.get('ignoreDefaultArgs', False):
                self.chrome_args.extend(AUTOMATION_ARGS)
    
            self._tmp_user_data_dir: Optional[str] = None
            self._parse_args()
    
            if self.options.get('devtools'):
                self.chrome_args.append('--auto-open-devtools-for-tabs')
                self.options['headless'] = False
    
            if 'headless' not in self.options or self.options.get('headless'):
                self.chrome_args.extend([
                    '--headless',
                    '--disable-gpu',
                    '--hide-scrollbars',
                    '--mute-audio',
                ])
    
            def _is_default_url() -> bool:
                for arg in self.options['args']:
                    if not arg.startswith('-'):
                        return False
                return True
    
            if (not self.options.get('ignoreDefaultArgs') and
                    isinstance(self.options.get('args'), list) and
                    _is_default_url()):
                self.chrome_args.append('about:blank')
    
            if 'executablePath' in self.options:
                self.exec = self.options['executablePath']
            else:
                if not check_chromium():
                    download_chromium()
                self.exec = str(chromium_executable())
    
            self.cmd = [self.exec] + self.chrome_args
    
        def _parse_args(self) -> None:
            if (not isinstance(self.options.get('args'), list) or
                    not any(opt for opt in self.options['args']
                            if opt.startswith('--user-data-dir'))):
                if 'userDataDir' not in self.options:
                    if not CHROME_PROFILE_PATH.exists():
                        CHROME_PROFILE_PATH.mkdir(parents=True)
                    self._tmp_user_data_dir = tempfile.mkdtemp(
                        dir=str(CHROME_PROFILE_PATH))
                self.chrome_args.append('--user-data-dir={}'.format(
                    self.options.get('userDataDir', self._tmp_user_data_dir)))
            if isinstance(self.options.get('args'), list):
                self.chrome_args.extend(self.options['args'])
    
        def _cleanup_tmp_user_data_dir(self) -> None:
            for retry in range(100):
                if self._tmp_user_data_dir and os.path.exists(
                        self._tmp_user_data_dir):
                    shutil.rmtree(self._tmp_user_data_dir, ignore_errors=True)
                    if os.path.exists(self._tmp_user_data_dir):
                        time.sleep(0.01)
                else:
                    break
            else:
                raise IOError('Unable to remove Temporary User Data')
    
        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
    
    

    注意看下这个方法:

        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

    于是乎,找到了bug之源!!!!!~

    就是他们

            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)

    程序结束时候注册一个事件,就是上面那个函数,会使用当前的loop来close掉浏览器

    可是这个run方法,已经在程序退出之前就finally里面close掉了loop

    于是乎,GG思密达,我也是强迫症,看不得红色!!!!虽然并没有什么影响!!!!

    就!是!不!能!报!红!!!!

    解决方法当然很简单:

    直接

     asyncio.get_event_loop().run_until_complete(get_browser())

    不用你run就行了

    当然还有一种,关闭那个程序退出时候自动杀掉进程的方法,然而,我并不想这么做,为什么?,我!就!不!

    def ret_loop():
    loop = events.new_event_loop()
    try:
    events.set_event_loop(loop)
    # loop.set_debug(debug)
    return loop.run_until_complete(get_browser())
    # except Exception as e:
    finally:
    try:
    _cancel_all_tasks(loop)
    loop.run_until_complete(loop.shutdown_asyncgens())
    finally:
    events.set_event_loop(None)
    loop.close()
    # print(e)
    # print('adfafdadsf')

    if __name__=='__main__':
    # asyncio.run(get_browser())
    # asyncio.get_event_loop().run_until_complete(get_browser())
    ret_loop()
  • 相关阅读:
    为函数的参数指定类型
    装饰器函数导致的原函数的元数据被替代--保存元数据
    ssm单项目整合
    security权限控制
    springAOP学习笔记
    springIOC学习笔记
    springDataJpa学习笔记
    springmvc学习笔记
    原生mybaits学习笔记
    java反射和注解
  • 原文地址:https://www.cnblogs.com/DDBD/p/12942920.html
Copyright © 2011-2022 走看看