Пример #1
0
    def __init__(self, connection: Connection, options: Dict = None,
                 process: Optional[Popen] = None,
                 closeCallback: Callable[[], Awaitable[None]] = None,
                 **kwargs: Any) -> None:
        super().__init__()
        options = merge_dict(options, kwargs)
        self._ignoreHTTPSErrors = bool(options.get('ignoreHTTPSErrors', False))
        self._appMode = bool(options.get('appMode', False))
        self._process = process
        self._screenshotTaskQueue: List = []
        self._connection = connection

        def _dummy_callback() -> Awaitable[None]:
            fut = asyncio.get_event_loop().create_future()
            fut.set_result(None)
            return fut

        if closeCallback:
            self._closeCallback = closeCallback
        else:
            self._closeCallback = _dummy_callback
        self._targets: Dict[str, Target] = dict()
        self._connection.setClosedCallback(
            lambda: self.emit(Browser.Events.Disconnected)
        )
        self._connection.on('Target.targetCreated', self._targetCreated)
        self._connection.on('Target.targetDestroyed', self._targetDestroyed)
        self._connection.on('Target.targetInfoChanged', self._targetInfoChanged)  # noqa: E501
Пример #2
0
    async def press(self, key: str, options: Dict = None, **kwargs: Any
                    ) -> None:
        """Press ``key``.

        If ``key`` is a single character and no modifier keys besides
        ``Shift`` are being held down, a ``keypress``/``input`` event will also
        generated. The ``text`` option can be specified to force an input event
        to be generated.

        :arg str key: Name of key to press, such as ``ArrowLeft``.

        This method accepts the following options:

        * ``text`` (str): If specified, generates an input event with this
          text.
        * ``delay`` (int|float): Time to wait between ``keydown`` and
          ``keyup``. Defaults to 0.

        .. note::
            Modifier keys DO effect :meth:`press`. Holding down ``Shift`` will
            type the text in upper case.
        """
        options = merge_dict(options, kwargs)

        await self.down(key, options)
        if 'delay' in options:
            await asyncio.sleep(options['delay'] / 1000)
        await self.up(key)
Пример #3
0
    async def start(self, options: dict = None, **kwargs: Any) -> None:
        """Start tracing.

        Only one trace can be active at a time per browser.

        This method accepts the following options:

        * ``path`` (str): A path to write the trace file to.
        * ``screenshots`` (bool): Capture screenshots in the trace.
        * ``categories`` (List[str]): Specify custom categories to use instead
          of default.
        """
        options = merge_dict(options, kwargs)
        defaultCategories = [
            '-*', 'devtools.timeline', 'v8.execute',
            'disabled-by-default-devtools.timeline',
            'disabled-by-default-devtools.timeline.frame', 'toplevel',
            'blink.console', 'blink.user_timing', 'latencyInfo',
            'disabled-by-default-devtools.timeline.stack',
            'disabled-by-default-v8.cpu_profiler',
            'disabled-by-default-v8.cpu_profiler.hires',
        ]
        categoriesArray = options.get('categories', defaultCategories)

        if 'screenshots' in options:
            categoriesArray.append('disabled-by-default-devtools.screenshot')

        self._path = options.get('path', '')
        self._recording = True
        await self._client.send('Tracing.start', {
            'transferMode': 'ReturnAsStream',
            'categories': ','.join(categoriesArray),
        })
Пример #4
0
    async def click(self, selector: str, options: dict = None, **kwargs: Any
                    ) -> None:
        """Click element which matches ``selector``.

        This method fetches an element with ``selector``, scrolls it into view
        if needed, and then uses :attr:`mouse` to click in the center of the
        element. If there's no element matching ``selector``, the method raises
        ``PageError``.

        Available options are:

        * ``button`` (str): ``left``, ``right``, or ``middle``, defaults to
          ``left``.
        * ``clickCount`` (int): defaults to 1.
        * ``delay`` (int|float): Time to wait between ``mousedown`` and
          ``mouseup`` in milliseconds. defaults to 0.

        .. note:: If this method triggers a navigation event and there's a
            separate :meth:`waitForNavigation`, you may end up with a race
            condition that yields unexpected results. The correct pattern for
            click and wait for navigation is the following::

                await asyncio.wait([
                    page.waitForNavigation(waitOptions),
                    page.click(selector, clickOptions),
                ])
        """
        options = merge_dict(options, kwargs)
        handle = await self.J(selector)
        if not handle:
            raise PageError('No node found for selector: ' + selector)
        await handle.click(options)
        await handle.dispose()
Пример #5
0
    async def type(self, text: str, options: Dict = None, **kwargs: Any
                   ) -> None:
        """Type characters into a focused element.

        This method sends ``keydown``, ``keypress``/``input``, and ``keyup``
        event for each character in the ``text``.

        To press a special key, like ``Control`` or ``ArrowDown``, use
        :meth:`press` method.

        :arg str text: Text to type into a focused element.
        :arg dict options: Options can have ``delay`` (int|float) field, which
          specifies time to wait between key presses in milliseconds. Defaults
          to 0.

        .. note::
            Modifier keys DO NOT effect :meth:`type`. Holding down ``shift``
            will not type the text in upper case.
        """
        options = merge_dict(options, kwargs)
        delay = options.get('delay', 0)
        for char in text:
            if char in keyDefinitions:
                await self.press(char, {'delay': delay})
            else:
                await self.sendCharacter(char)
            if delay:
                await asyncio.sleep(delay / 1000)
Пример #6
0
    def __init__(self, frameManager: FrameManager, frame: Frame, timeout: int,
                 options: Dict = None, **kwargs: Any) -> None:
        """Make new navigator watcher."""
        options = merge_dict(options, kwargs)
        self._validate_options(options)
        self._frameManeger = frameManager
        self._frame = frame
        self._initialLoaderId = frame._loaderId
        self._timeout = timeout
        self._eventListeners = [
            helper.addEventListener(
                self._frameManeger,
                FrameManager.Events.LifecycleEvent,
                self._checkLifecycleComplete,
            ),
            helper.addEventListener(
                self._frameManeger,
                FrameManager.Events.FrameDetached,
                self._checkLifecycleComplete,
            ),
        ]
        loop = asyncio.get_event_loop()
        self._lifecycleCompletePromise = loop.create_future()

        self._navigationPromise = asyncio.ensure_future(asyncio.wait([
            self._lifecycleCompletePromise,
            self._createTimeoutPromise(),
        ], return_when=concurrent.futures.FIRST_COMPLETED))
        self._navigationPromise.add_done_callback(
            lambda fut: self._cleanup())
Пример #7
0
    async def waitForNavigation(self, options: dict = None, **kwargs: Any
                                ) -> Optional[Response]:
        """Wait for navigation.

        Available options are same as :meth:`goto` method.
        """
        options = merge_dict(options, kwargs)
        mainFrame = self._frameManager.mainFrame
        if mainFrame is None:
            raise PageError('No main frame.')
        timeout = options.get('timeout', self._defaultNavigationTimeout)
        watcher = NavigatorWatcher(self._frameManager, mainFrame, timeout,
                                   options)
        responses: Dict[str, Response] = dict()
        listener = helper.addEventListener(
            self._networkManager,
            NetworkManager.Events.Response,
            lambda response: responses.__setitem__(response.url, response)
        )
        result = await watcher.navigationPromise()
        helper.removeEventListeners([listener])
        error = result[0].pop().exception()
        if error:
            raise error

        response = responses.get(self.url, None)
        return response
Пример #8
0
 async def emulate(self, options: dict = None, **kwargs: Any) -> None:
     """Emulate viewport and user agent."""
     options = merge_dict(options, kwargs)
     # TODO: if options does not have viewport or userAgent,
     # skip its setting.
     await self.setViewport(options.get('viewport', {}))
     await self.setUserAgent(options.get('userAgent', ''))
Пример #9
0
    def waitFor(self, selectorOrFunctionOrTimeout: Union[str, int, float],
                options: dict = None, *args: Any, **kwargs: Any
                ) -> Union[Awaitable, 'WaitTask']:
        """Wait until `selectorOrFunctionOrTimeout`.

        Details see :meth:`pyppeteer.page.Page.waitFor`.
        """
        options = merge_dict(options, kwargs)
        if isinstance(selectorOrFunctionOrTimeout, (int, float)):
            fut: Awaitable[None] = self._client._loop.create_task(
                asyncio.sleep(selectorOrFunctionOrTimeout / 1000))
            return fut
        if not isinstance(selectorOrFunctionOrTimeout, str):
            fut = self._client._loop.create_future()
            fut.set_exception(TypeError(
                'Unsupported target type: ' +
                str(type(selectorOrFunctionOrTimeout))
            ))
            return fut

        if args or helper.is_jsfunc(selectorOrFunctionOrTimeout):
            return self.waitForFunction(
                selectorOrFunctionOrTimeout, options, *args)
        if selectorOrFunctionOrTimeout.startswith('//'):
            return self.waitForXPath(selectorOrFunctionOrTimeout, options)
        return self.waitForSelector(selectorOrFunctionOrTimeout, options)
Пример #10
0
    def waitForSelector(self, selector: str, options: dict = None,
                        **kwargs: Any) -> 'WaitTask':
        """Wait until element which matches ``selector`` appears on page.

        Details see :meth:`pyppeteer.page.Page.waitForSelector`.
        """
        options = merge_dict(options, kwargs)
        waitForVisible = bool(options.get('visible'))
        waitForHidden = bool(options.get('hidden'))
        predicate = '''
(selector, waitForVisible, waitForHidden) => {
    const node = document.querySelector(selector);
    if (!node)
        return waitForHidden;
    if (!waitForVisible && !waitForHidden)
        return node;
    const style = window.getComputedStyle(node);
    const isVisible = style && style.visibility !== 'hidden' && hasVisibleBoundingBox();
    const success = (waitForVisible === isVisible || waitForHidden === !isVisible)
    return success ? node : null

    function hasVisibleBoundingBox() {
        const rect = node.getBoundingClientRect();
        return !!(rect.top || rect.bottom || rect.width || rect.height);
    }
}
        '''  # noqa: E501
        return self.waitForFunction(
            predicate, options, selector, waitForVisible, waitForHidden)
Пример #11
0
    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
Пример #12
0
    def waitForXPath(self, xpath: str, options: dict = None,
                     **kwargs: Any) -> 'WaitTask':
        """Wait until element which matches ``xpath`` appears on page.

        Details see :meth:`pyppeteer.page.Page.waitForXPath`.
        """
        options = merge_dict(options, kwargs)
        return self._waitForSelectorOrXPath(xpath, True, options)
Пример #13
0
    async def goForward(self, options: dict = None, **kwargs: Any
                        ) -> Optional[Response]:
        """Navigate to the next page in history.

        Available options are same as :meth:`goto` method.
        """
        options = merge_dict(options, kwargs)
        return await self._go(+1, options)
Пример #14
0
    async def type(self, text: str, options: Dict = None, **kwargs: Any
                   ) -> None:
        """Focus the element and then type text.

        Details see :meth:`pyppeteer.input.Keyboard.type` method.
        """
        options = merge_dict(options, kwargs)
        await self.focus()
        await self._page.keyboard.type(text, options)
Пример #15
0
 async def create(connection: Connection, options: dict = None,
                  process: Optional[Popen] = None,
                  closeCallback: Callable[[], Awaitable[None]] = None,
                  **kwargs: Any) -> 'Browser':
     """Create browser object."""
     options = merge_dict(options, kwargs)
     browser = Browser(connection, options, process, closeCallback)
     await connection.send('Target.setDiscoverTargets', {'discover': True})
     return browser
Пример #16
0
    async def screenshot(self, options: Dict = None, **kwargs: Any) -> bytes:
        """Take a screenshot of this element.

        If the element is detached from DOM, this method raises an
        ``ElementHandleError``.

        Available options are same as :meth:`pyppeteer.page.Page.screenshot`.
        """
        options = merge_dict(options, kwargs)

        needsViewportReset = False
        boundingBox = await self.boundingBox()
        if not boundingBox:
            raise ElementHandleError(
                'Node is either not visible or not an HTMLElement')

        original_viewport = copy.deepcopy(self._page.viewport)

        if (boundingBox['width'] > original_viewport['width'] or
                boundingBox['height'] > original_viewport['height']):
            newViewport = {
                'width': max(
                    original_viewport['width'],
                    math.ceil(boundingBox['width'])
                ),
                'height': max(
                    original_viewport['height'],
                    math.ceil(boundingBox['height'])
                ),
            }
            new_viewport = copy.deepcopy(original_viewport)
            new_viewport.update(newViewport)
            await self._page.setViewport(new_viewport)
            needsViewportReset = True

        await self._scrollIntoViewIfNeeded()
        boundingBox = await self.boundingBox()
        if not boundingBox:
            raise ElementHandleError(
                'Node is either not visible or not an HTMLElement')

        _obj = await self._client.send('Page.getLayoutMetrics')
        pageX = _obj['layoutViewport']['pageX']
        pageY = _obj['layoutViewport']['pageY']

        clip = {}
        clip.update(boundingBox)
        clip['x'] = clip['x'] + pageX
        clip['y'] = clip['y'] + pageY
        opt = {'clip': clip}
        opt.update(options)
        imageData = await self._page.screenshot(opt)

        if needsViewportReset:
            await self._page.setViewport(original_viewport)

        return imageData
Пример #17
0
    def waitForFunction(self, pageFunction: str, options: dict = None,
                        *args: Any, **kwargs: Any) -> 'WaitTask':
        """Wait until the function completes.

        Details see :meth:`pyppeteer.page.Page.waitForFunction`.
        """
        options = merge_dict(options, kwargs)
        timeout = options.get('timeout',  30000)  # msec
        polling = options.get('polling', 'raf')
        return WaitTask(self, pageFunction, polling, timeout, *args)
Пример #18
0
    async def startCSSCoverage(self, options: Dict = None, **kwargs: Any
                               ) -> None:
        """Start CSS coverage measurement.

        Available options are:

        * ``resetOnNavigation`` (bool): Whether to reset coverage on every
          navigation. Defaults to ``True``.
        """
        options = merge_dict(options, kwargs)
        await self._cssCoverage.start(options)
Пример #19
0
    async def reload(self, options: dict = None, **kwargs: Any
                     ) -> Optional[Response]:
        """Reload this page.

        Available options are same as :meth:`goto` method.
        """
        options = merge_dict(options, kwargs)
        response = (await asyncio.gather(
            self.waitForNavigation(options),
            self._client.send('Page.reload'),
        ))[0]
        return response
Пример #20
0
    async def click(self, selector: str, options: dict = None, **kwargs: Any
                    ) -> None:
        """Click element which matches ``selector``.

        Details see :meth:`pyppeteer.page.Page.click`.
        """
        options = merge_dict(options, kwargs)
        handle = await self.J(selector)
        if not handle:
            raise PageError('No node found for selector: ' + selector)
        await handle.click(options)
        await handle.dispose()
Пример #21
0
    async def type(self, selector: str, text: str, options: dict = None,
                   **kwargs: Any) -> None:
        """Type ``text`` on the element which matches ``selector``.

        Details see :meth:`pyppeteer.page.Page.type`.
        """
        options = merge_dict(options, kwargs)
        handle = await self.querySelector(selector)
        if handle is None:
            raise PageError('Cannot find {} on this page'.format(selector))
        await handle.type(text, options)
        await handle.dispose()
Пример #22
0
    async def goto(self, url: str, options: dict = None, **kwargs: Any
                   ) -> Optional[Response]:
        """Go to the ``url``.

        :arg string url: URL to navigate page to. The url should include
            scheme, e.g. ``https://``.

        Available options are:

        * ``timeout`` (int): Maximum navigation time in milliseconds, defaults
          to 30 seconds, pass ``0`` to desable timeout. The default value can
          be changed by using the :meth:`setDefaultNavigationTimeout` method.
        * ``waitUntil`` (str|List[str]): When to consider navigation succeeded,
          defaults to ``load``. Given a list of event strings, navigation is
          considered to be successful after all events have been fired. Events
          can be either:

          * ``load``: when ``load`` event is fired.
          * ``documentloaded``: when the ``DOMContentLoaded`` event is fired.
          * ``networkidle0``: when there are no more than 0 network connections
            for at least 500 ms.
          * ``networkidle2``: when there are no more than 2 network connections
            for at least 500 ms.
        """
        options = merge_dict(options, kwargs)
        referrer = self._networkManager.extraHTTPHeaders().get('referer', '')
        requests: Dict[str, Request] = dict()
        eventListeners = [helper.addEventListener(
            self._networkManager, NetworkManager.Events.Request,
            lambda request: requests.__setitem__(request.url, request)
        )]

        mainFrame = self._frameManager.mainFrame
        if mainFrame is None:
            raise PageError('No main frame.')
        timeout = options.get('timeout', self._defaultNavigationTimeout)
        watcher = NavigatorWatcher(self._frameManager, mainFrame, timeout,
                                   options)

        result = await self._navigate(url, referrer)
        if result is not None:
            raise PageError(result)
        result = await watcher.navigationPromise()
        watcher.cancel()
        helper.removeEventListeners(eventListeners)
        error = result[0].pop().exception()  # type: ignore
        if error:
            raise error

        request = requests.get(mainFrame.url)
        return request.response if request else None
Пример #23
0
    async def addStyleTag(self, options: Dict = None, **kwargs: str
                          ) -> ElementHandle:
        """Add style or link tag to this page.

        One of ``url``, ``path`` or ``content`` option is necessary.
            * ``url`` (string): URL of the link tag to add.
            * ``path`` (string): Path to the local CSS file to add.
            * ``content`` (string): CSS string to add.

        :return ElementHandle: :class:`~pyppeteer.element_handle.ElementHandle`
                               of added tag.
        """
        frame = self.mainFrame
        if not frame:
            raise PageError('no main frame.')
        options = merge_dict(options, kwargs)
        return await frame.addStyleTag(options)
Пример #24
0
    async def down(self, key: str, options: dict = None, **kwargs: Any
                   ) -> None:
        """Dispatch a ``keydown`` event with ``key``.

        If ``key`` is a single character and no modifier keys besides ``Shift``
        are being held down, and a ``keypress``/``input`` event will also
        generated. The ``text`` option can be specified to force an ``input``
        event to be generated.

        If ``key`` is a modifier key, like ``Shift``, ``Meta``, or ``Alt``,
        subsequent key presses will be sent with that modifier active. To
        release the modifier key, use :meth:`up` method.

        :arg str key: Name of key to press, such as ``ArrowLeft``.
        :arg dict options: Option can have ``text`` field, and if this option
            specified, generate an input event with this text.

        .. note::
            Modifier keys DO influence :meth:`down`. Holding down ``shift``
            will type the text in upper case.
        """
        options = merge_dict(options, kwargs)

        description = self._keyDescriptionForString(key)
        autoRepeat = description['code'] in self._pressedKeys
        self._pressedKeys.add(description['code'])
        self._modifiers |= self._modifierBit(description['key'])

        text = options.get('text')
        if text is None:
            text = description['text']

        await self._client.send('Input.dispatchKeyEvent', {
            'type': 'keyDown' if text else 'rawKeyDown',
            'modifiers': self._modifiers,
            'windowsVirtualKeyCode': description['keyCode'],
            'code': description['code'],
            'key': description['key'],
            'text': text,
            'unmodifiedText': text,
            'autoRepeat': autoRepeat,
            'location': description['location'],
            'isKeypad': description['location'] == 3,
        })
Пример #25
0
    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] = []

        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',
            ])

        if 'executablePath' in self.options:
            self.exec = self.options['executablePath']
        else:
            if not check_chromium():
                download_chromium()
            self.exec = str(chromium_excutable())

        self.cmd = [self.exec] + self.chrome_args
Пример #26
0
 async def screenshot(self, options: Dict = None, **kwargs: Any) -> bytes:
     'Take a screenshot of this element.\n\n        If the element is detached from DOM, this method raises an\n        ``ElementHandleError``.\n\n        Available options are same as :meth:`pyppeteer.page.Page.screenshot`.\n        '
     options = merge_dict(options, kwargs)
     needsViewportReset = False
     boundingBox = (await self.boundingBox())
     if (not boundingBox):
         raise ElementHandleError(
             'Node is either not visible or not an HTMLElement')
     original_viewport = copy.deepcopy(self._page.viewport)
     if ((boundingBox['width'] > original_viewport['width'])
             or (boundingBox['height'] > original_viewport['height'])):
         newViewport = {
             'width':
             max(original_viewport['width'],
                 math.ceil(boundingBox['width'])),
             'height':
             max(original_viewport['height'],
                 math.ceil(boundingBox['height'])),
         }
         new_viewport = copy.deepcopy(original_viewport)
         new_viewport.update(newViewport)
         (await self._page.setViewport(new_viewport))
         needsViewportReset = True
     (await self._scrollIntoViewIfNeeded())
     boundingBox = (await self.boundingBox())
     if (not boundingBox):
         raise ElementHandleError(
             'Node is either not visible or not an HTMLElement')
     _obj = (await self._client.send('Page.getLayoutMetrics'))
     pageX = _obj['layoutViewport']['pageX']
     pageY = _obj['layoutViewport']['pageY']
     clip = {}
     clip.update(boundingBox)
     clip['x'] = (clip['x'] + pageX)
     clip['y'] = (clip['y'] + pageY)
     opt = {
         'clip': clip,
     }
     opt.update(options)
     imageData = (await self._page.screenshot(opt))
     if needsViewportReset:
         (await self._page.setViewport(original_viewport))
     return imageData
Пример #27
0
    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] = []

        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',
            ])

        if 'executablePath' in self.options:
            self.exec = self.options['executablePath']
        else:
            if not check_chromium():
                download_chromium()
            self.exec = str(chromium_excutable())

        self.cmd = [self.exec] + self.chrome_args
Пример #28
0
    async def up(self, options: dict = None, **kwargs: Any) -> None:
        """Release pressed button (dispatches ``mouseup`` event).

        This method accepts the following options:

        * ``button`` (str): ``left``, ``right``, or ``middle``, defaults to
          ``left``.
        * ``clickCount`` (int): defaults to 1.
        """
        options = merge_dict(options, kwargs)
        self._button = 'none'
        await self._client.send('Input.dispatchMouseEvent', {
            'type': 'mouseReleased',
            'button': options.get('button', 'left'),
            'x': self._x,
            'y': self._y,
            'modifiers': self._keyboard._modifiers,
            'clickCount': options.get('clickCount') or 1,
        })
Пример #29
0
    async def down(self,
                   key: str,
                   options: dict = None,
                   **kwargs: Any) -> None:
        """Dispatches a ``keydown`` event with ``key``.

        If ``key`` is a single character and no modifier keys besides ``shift``
        are being held down, and a ``keyparess``/``input`` event will also
        generated. The ``text`` option can be specified to force an ``input``
        event to be generated.

        If ``key`` is a modifier key, like ``Shift``, ``Meta``, or ``Alt``,
        subsequent key presses will be sent with that modifier active. To
        release the modifier key, use :meth:`up` method.

        :arg str key: Name of key to press, such as ``ArrowLeft``.
        :arg dict options: Option can have ``text`` field, and if this option
            spedified, generate an input event with this text.
        """
        options = merge_dict(options, kwargs)

        description = self._keyDescriptionForString(key)
        autoRepeat = description['key'] in self._pressedKeys
        self._pressedKeys.add(description['code'])
        self._modifiers |= self._modifierBit(description['key'])

        text = options.get('text')
        if text is None:
            text = description['text']

        await self._client.send(
            'Input.dispatchKeyEvent', {
                'type': 'keyDown' if text else 'rawKeyDown',
                'modifiers': self._modifiers,
                'windowsVirtualKeyCode': description['keyCode'],
                'code': description['code'],
                'key': description['key'],
                'text': text,
                'unmodifiedText': text,
                'autoRepeat': autoRepeat,
                'location': description['location'],
                'isKeypad': description['location'] == 3,
            })
Пример #30
0
    async def up(self, options: dict = None, **kwargs: Any) -> None:
        """Release pressed button (dispatches ``mouseup`` event).

        This method accepts the following options:

        * ``button`` (str): ``left``, ``right``, or ``middle``, defaults to
          ``left``.
        * ``clickCount`` (int): defaults to 1.
        """
        options = merge_dict(options, kwargs)
        self._button = 'none'
        await self._client.send('Input.dispatchMouseEvent', {
            'type': 'mouseReleased',
            'button': options.get('button', 'left'),
            'x': self._x,
            'y': self._y,
            'modifiers': self._keyboard._modifiers,
            'clickCount': options.get('clickCount') or 1,
        })
Пример #31
0
    def __init__(
        self,
        pageurl,
        sitekey,
        proxy=None,
        proxy_auth=None,
        options={},
        **kwargs,
    ):
        self.options = merge_dict(options, kwargs)
        self.url = pageurl
        self.sitekey = sitekey
        self.proxy = proxy
        self.proxy_auth = proxy_auth

        self.headless = settings["headless"]
        self.cookies = []
        self.proc_id = self.proc_count
        type(self).proc_count += 1
Пример #32
0
    async def click(self, options: dict = None, **kwargs: Any) -> None:
        """Click the center of this element.

        If needed, this method scrolls element into view. If the element is
        detached from DOM, the method raises ``ElementHandleError``.

        ``options`` can contain the following fields:

        * ``button`` (str): ``left``, ``right``, of ``middle``, defaults to
          ``left``.
        * ``clickCount`` (int): Defaults to 1.
        * ``delay`` (int|float): Time to wait between ``mousedown`` and
          ``mouseup`` in milliseconds. Defaults to 0.
        """
        options = merge_dict(options, kwargs)
        obj = await self._visibleCenter()
        x = obj.get('x', 0)
        y = obj.get('y', 0)
        await self._page.mouse.click(x, y, options)
Пример #33
0
    async def screenshot(self, options: dict = None, **kwargs: Any) -> bytes:
        """Take a screen shot.

        The following options are available:

        * ``path`` (str): The file path to save the image to. The screenshot
          type will be inferred from the file extension.
        * ``type`` (str): Specify screenshot type, can be either ``jpeg`` or
          ``png``. Defaults to ``png``.
        * ``quality`` (int): The quality of the image, between 0-100. Not
          applicable to ``png`` image.
        * ``fullPage`` (bool): When true, take a screenshot of the full
          scrollable page. Defaults to ``False``.
        * ``clip`` (dict): An object which specifies clipping region of the
          page. This option should have the following fields:

          * ``x`` (int): x-coordinate of top-left corner of clip area.
          * ``y`` (int): y-coordinate of top-left corner of clip area.
          * ``width`` (int): width of clipping area.
          * ``height`` (int): height of clipping area.

        * ``omitBackground`` (bool): Hide default white background and allow
          capturing screenshot with transparency.
        """
        options = merge_dict(options, kwargs)
        screenshotType = None
        if 'type' in options:
            screenshotType = options['type']
            if screenshotType not in ['png', 'jpeg']:
                raise ValueError(f'Unknown type value: {screenshotType}')
        elif 'path' in options:
            mimeType, _ = mimetypes.guess_type(options['path'])
            if mimeType == 'image/png':
                screenshotType = 'png'
            elif mimeType == 'image/jpeg':
                screenshotType = 'jpeg'
            else:
                raise ValueError('Unsupported screenshot '
                                 f'mime type: {mimeType}')
        if not screenshotType:
            screenshotType = 'png'
        return await self._screenshotTask(screenshotType, options)
Пример #34
0
    def _waitForSelectorOrXPath(self, selectorOrXPath: str, isXPath: bool,
                                options: dict = None, **kwargs: Any
                                ) -> 'WaitTask':
        options = merge_dict(options, kwargs)
        timeout = options.get('timeout', 30000)
        waitForVisible = bool(options.get('visible'))
        waitForHidden = bool(options.get('hidden'))
        polling = 'raf' if waitForHidden or waitForVisible else 'mutation'
        predicate = '''
(selectorOrXPath, isXPath, waitForVisible, waitForHidden) => {
    const node = isXPath
        ? document.evaluate(selectorOrXPath, document, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null).singleNodeValue
        : document.querySelector(selectorOrXPath);
    if (!node)
        return waitForHidden;
    if (!waitForVisible && !waitForHidden)
        return node;
    const element = /** @type {Element} */ (node.nodeType === Node.TEXT_NODE ? node.parentElement : node);

    const style = window.getComputedStyle(element);
    const isVisible = style && style.visibility !== 'hidden' && hasVisibleBoundingBox();
    const success = (waitForVisible === isVisible || waitForHidden === !isVisible)
    return success ? node : null

    function hasVisibleBoundingBox() {
        const rect = element.getBoundingClientRect();
        return !!(rect.top || rect.bottom || rect.width || rect.height);
    }
}
        '''  # noqa: E501
        return WaitTask(
            self,
            predicate,
            f'{"XPath" if isXPath else "selector"} "{selectorOrXPath}"',
            polling,
            timeout,
            self._client._loop,
            selectorOrXPath,
            isXPath,
            waitForVisible,
            waitForHidden,
        )
Пример #35
0
    async def screenshot(self, options: dict = None, **kwargs: Any) -> bytes:
        """Take a screen shot.

        The following options are available:

        * ``path`` (str): The file path to save the image to. The screenshot
          type will be inferred from the file extension.
        * ``type`` (str): Specify screenshot type, can be either ``jpeg`` or
          ``png``. Defaults to ``png``.
        * ``quality`` (int): The quality of the image, between 0-100. Not
          applicable to ``png`` image.
        * ``fullPage`` (bool): When true, take a screenshot of the full
          scrollable page. Defaults to ``False``.
        * ``clip`` (dict): An object which specifies clipping region of the
          page. This option should have the following fields:

          * ``x`` (int): x-coordinate of top-left corner of clip area.
          * ``y`` (int): y-coordinate of top-left corner of clip area.
          * ``width`` (int): width of clipping area.
          * ``height`` (int): height of clipping area.

        * ``omitBackground`` (bool): Hide default white background and allow
          capturing screenshot with transparency.
        """
        options = merge_dict(options, kwargs)
        screenshotType = None
        if 'type' in options:
            screenshotType = options['type']
            if screenshotType not in ['png', 'jpeg']:
                raise ValueError(f'Unknown type value: {screenshotType}')
        elif 'path' in options:
            mimeType, _ = mimetypes.guess_type(options['path'])
            if mimeType == 'image/png':
                screenshotType = 'png'
            elif mimeType == 'image/jpeg':
                screenshotType = 'jpeg'
            else:
                raise ValueError('Unsupported screenshot '
                                 f'mime type: {mimeType}')
        if not screenshotType:
            screenshotType = 'png'
        return await self._screenshotTask(screenshotType, options)
Пример #36
0
    async def click(self, x: float, y: float, options: dict = None,
                    **kwargs: Any) -> None:
        """Click button at (``x``, ``y``).

        Shortcut to :meth:`move`, :meth:`down`, and :meth:`up`.

        This method accepts the following options:

        * ``button`` (str): ``left``, ``right``, or ``middle``, defaults to
          ``left``.
        * ``clickCount`` (int): defaults to 1.
        * ``delay`` (int|float): Time to wait between ``mousedown`` and
          ``mouseup`` in milliseconds. Defaults to 0.
        """
        options = merge_dict(options, kwargs)
        await self.move(x, y)
        await self.down(options)
        if options and options.get('delay'):
            await asyncio.sleep(options.get('delay', 0) / 1000)
        await self.up(options)
Пример #37
0
    async def press(self, key: str, options: Dict = None, **kwargs: Any
                    ) -> None:
        """Press ``key`` onto the element.

        This method focuses the element, and then uses
        :meth:`pyppeteer.input.keyboard.down` and
        :meth:`pyppeteer.input.keyboard.up`.

        :arg str key: Name of key to press, such as ``ArrowLeft``.

        This method accepts the following options:

        * ``text`` (str): If specified, generates an input event with this
          text.
        * ``delay`` (int|float): Time to wait between ``keydown`` and
          ``keyup``. Defaults to 0.
        """
        options = merge_dict(options, kwargs)
        await self.focus()
        await self._page.keyboard.press(key, options)
Пример #38
0
    async def startJSCoverage(self, options: Dict = None, **kwargs: Any
                              ) -> None:
        """Start JS coverage measurement.

        Available options are:

        * ``resetOnNavigation`` (bool): Whether to reset coverage on every
          navigation. Defaults to ``True``.
        * ``reportAnonymousScript`` (bool): Whether anonymous script generated
          by the page should be reported. Defaults to ``False``.

        .. note::
            Anonymous scripts are ones that don't have an associated url. These
            are scripts that are dynamically created on the page using ``eval``
            of ``new Function``. If ``reportAnonymousScript`` is set to
            ``True``, anonymous scripts will have
            ``__pyppeteer_evaluation_script__`` as their url.
        """
        options = merge_dict(options, kwargs)
        await self._jsCoverage.start(options)
Пример #39
0
    async def click(self, options: dict = None, **kwargs: Any) -> None:
        """Click the center of this element.

        If needed, this method scrolls element into view. If the element is
        detached from DOM, the method raises ``ElementHandleError``.

        ``options`` can contain the following fields:

        * ``button`` (str): ``left``, ``right``, of ``middle``, defaults to
          ``left``.
        * ``clickCount`` (int): Defaults to 1.
        * ``delay`` (int|float): Time to wait between ``mousedown`` and
          ``mouseup`` in milliseconds. Defaults to 0.
        """
        options = merge_dict(options, kwargs)
        await self._scrollIntoViewIfNeeded()
        obj = await self._clickablePoint()
        x = obj.get('x', 0)
        y = obj.get('y', 0)
        await self._page.mouse.click(x, y, options)
Пример #40
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    * ``logLevel`` (int|str): Log level to print logs. Defaults to same as the\n      root logger.\n    * ``loop`` (asyncio.AbstractEventLoop): Event loop (**experimental**).\n    "
    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'))))
Пример #41
0
def defaultArgs(options: Dict = None,
                **kwargs: Any) -> List[str]:  # noqa: C901,E501
    """Get the default flags the chromium will be launched with.

    ``options`` or keyword arguments are set of configurable options to set on
    the browser. Can have the following fields:

    * ``headless`` (bool): Whether to run browser in headless mode. Defaults to
      ``True`` unless the ``devtools`` option is ``True``.
    * ``args`` (List[str]): Additional arguments to pass to the browser
      instance. The list of chromium flags can be found
      `here <http://peter.sh/experiments/chromium-command-line-switches/>`__.
    * ``userDataDir`` (str): Path to a User Data Directory.
    * ``devtools`` (bool): Whether to auto-open DevTools panel for each tab. If
      this option is ``True``, the ``headless`` option will be set ``False``.
    """
    options = merge_dict(options, kwargs)
    devtools = options.get('devtools', False)
    headless = options.get('headless', not devtools)
    args = options.get('args', list())
    userDataDir = options.get('userDataDir')
    chromeArguments = copy(DEFAULT_ARGS)

    if userDataDir:
        chromeArguments.append(f'--user-data-dir={userDataDir}')
    if devtools:
        chromeArguments.append('--auto-open-devtools-for-tabs')
    if headless:
        chromeArguments.extend((
            '--headless',
            '--hide-scrollbars',
            '--mute-audio',
        ))
        if current_platform().startswith('win'):
            chromeArguments.append('--disable-gpu')

    if all(map(lambda arg: arg.startswith('-'), args)):  # type: ignore
        chromeArguments.append('about:blank')
    chromeArguments.extend(args)

    return chromeArguments
Пример #42
0
    def __init__(self,
                 frameManager: FrameManager,
                 frame: Frame,
                 timeout: int,
                 options: Dict = None,
                 **kwargs: Any) -> None:
        """Make new navigator watcher."""
        options = merge_dict(options, kwargs)
        self._validate_options(options)
        self._frameManager = frameManager
        self._frame = frame
        self._initialLoaderId = frame._loaderId
        self._timeout = timeout
        self._hasSameDocumentNavigation = False
        self._eventListeners = [
            helper.addEventListener(
                self._frameManager,
                FrameManager.Events.LifecycleEvent,
                self._checkLifecycleComplete,
            ),
            helper.addEventListener(
                self._frameManager,
                FrameManager.Events.FrameNavigatedWithinDocument,
                self._navigatedWithinDocument,
            ),
            helper.addEventListener(
                self._frameManager,
                FrameManager.Events.FrameDetached,
                self._checkLifecycleComplete,
            ),
        ]
        self._loop = self._frameManager._client._loop
        self._lifecycleCompletePromise = self._loop.create_future()

        self._navigationPromise = self._loop.create_task(
            asyncio.wait([
                self._lifecycleCompletePromise,
                self._createTimeoutPromise(),
            ],
                         return_when=concurrent.futures.FIRST_COMPLETED))
        self._navigationPromise.add_done_callback(lambda fut: self._cleanup())
Пример #43
0
 def waitFor(self,
             selectorOrFunctionOrTimeout: Union[(str, int, float)],
             options: dict = None,
             *args: Any,
             **kwargs: Any) -> Union[(Awaitable, 'WaitTask')]:
     'Wait until `selectorOrFunctionOrTimeout`.\n\n        Details see :meth:`pyppeteer.page.Page.waitFor`.\n        '
     options = merge_dict(options, kwargs)
     if isinstance(selectorOrFunctionOrTimeout, (int, float)):
         fut = asyncio.ensure_future(
             asyncio.sleep((selectorOrFunctionOrTimeout / 1000)))
         return fut
     if (not isinstance(selectorOrFunctionOrTimeout, str)):
         fut = asyncio.get_event_loop().create_future()
         fut.set_exception(
             TypeError(('Unsupported target type: ' +
                        str(type(selectorOrFunctionOrTimeout)))))
         return fut
     if (args or helper.is_jsfunc(selectorOrFunctionOrTimeout)):
         return self.waitForFunction(selectorOrFunctionOrTimeout, options,
                                     *args)
     return self.waitForSelector(selectorOrFunctionOrTimeout, options)
Пример #44
0
    async def waitForNavigation(self,
                                options: dict = None,
                                **kwargs: Any) -> Optional[Response]:
        """Wait for navigation completes."""
        options = merge_dict(options, kwargs)
        mainFrame = self._frameManager.mainFrame
        if mainFrame is None:
            raise PageError('No main frame.')
        watcher = NavigatorWatcher(self._frameManager, mainFrame, options)
        responses: Dict[str, Response] = dict()
        listener = helper.addEventListener(
            self._networkManager, NetworkManager.Events.Response,
            lambda response: responses.__setitem__(response.url, response))
        result = await watcher.navigationPromise()
        helper.removeEventListeners([listener])
        error = result[0].pop().exception()
        if error:
            raise error

        response = responses.get(self.url, None)
        return response
Пример #45
0
 async def start(self, options: Dict = None, **kwargs: Any) -> None:
     """Start coverage measurement."""
     options = merge_dict(options, kwargs)
     if self._enabled:
         raise PageError('CSSCoverage is already enabled.')
     self._resetOnNavigation = (True if 'resetOnNavigation' not in options
                                else bool(options['resetOnNavigation']))
     self._enabled = True
     self._stylesheetURLs.clear()
     self._stylesheetSources.clear()
     self._eventListeners = [
         helper.addEventListener(
             self._client, 'CSS.styleSheetAdded', lambda e: self._client.
             _loop.create_task(self._onStyleSheet(e))),
         helper.addEventListener(self._client,
                                 'Runtime.executionContextsCleared',
                                 self._onExecutionContextsCleared),
     ]
     await self._client.send('DOM.enable')
     await self._client.send('CSS.enable')
     await self._client.send('CSS.startRuleUsageTracking')
Пример #46
0
    async def start(self, options: dict = None, **kwargs: Any) -> None:
        """Start tracing.

        Only one trace can be active at a time per browser.

        This method accepts the following options:

        * ``path`` (str): A path to write the trace file to.
        * ``screenshots`` (bool): Capture screenshots in the trace.
        * ``categories`` (List[str]): Specify custom categories to use instead
          of default.
        """
        options = merge_dict(options, kwargs)
        defaultCategories = [
            '-*',
            'devtools.timeline',
            'v8.execute',
            'disabled-by-default-devtools.timeline',
            'disabled-by-default-devtools.timeline.frame',
            'toplevel',
            'blink.console',
            'blink.user_timing',
            'latencyInfo',
            'disabled-by-default-devtools.timeline.stack',
            'disabled-by-default-v8.cpu_profiler',
            'disabled-by-default-v8.cpu_profiler.hires',
        ]
        categoriesArray = options.get('categories', defaultCategories)

        if 'screenshots' in options:
            categoriesArray.append('disabled-by-default-devtools.screenshot')

        self._path = options.get('path', '')
        self._recording = True
        await self._client.send(
            'Tracing.start', {
                'transferMode': 'ReturnAsStream',
                'categories': ','.join(categoriesArray),
            })
Пример #47
0
    def __init__(self,
                 pageurl,
                 loop=None,
                 proxy=None,
                 proxy_auth=None,
                 options=None,
                 lang='en-US',
                 chromePath=None,
                 **kwargs):
        self.url = pageurl
        self.loop = loop or util.get_event_loop()
        self.proxy = proxy
        self.proxy_auth = proxy_auth
        self.options = merge_dict({} if options is None else options, kwargs)
        self.chromePath = chromePath

        super(Solver, self).__init__(loop=loop,
                                     proxy=proxy,
                                     proxy_auth=proxy_auth,
                                     language=lang,
                                     options=options,
                                     chromePath=chromePath)
Пример #48
0
    async def press(self,
                    key: str,
                    options: Dict = None,
                    **kwargs: Any) -> None:
        """Press ``key`` onto the element.

        This method focuses the element, and then uses
        :meth:`pyppeteer.input.keyboard.down` and
        :meth:`pyppeteer.input.keyboard.up`.

        :arg str key: Name of key to press, such as ``ArrowLeft``.

        This method accepts the following options:

        * ``text`` (str): If specified, generates an input event with this
          text.
        * ``delay`` (int|float): Time to wait between ``keydown`` and
          ``keyup``. Defaults to 0.
        """
        options = merge_dict(options, kwargs)
        await self.focus()
        await self._page.keyboard.press(key, options)
Пример #49
0
    def _waitForSelectorOrXPath(self, selectorOrXPath: str, isXPath: bool,
                                options: dict = None, **kwargs: Any
                                ) -> 'WaitTask':
        options = merge_dict(options, kwargs)
        timeout = options.get('timeout', 30000)
        waitForVisible = bool(options.get('visible'))
        waitForHidden = bool(options.get('hidden'))
        polling = 'raf' if waitForHidden or waitForVisible else 'mutation'
        predicate = '''
(selectorOrXPath, isXPath, waitForVisible, waitForHidden) => {
    const node = isXPath
        ? document.evaluate(selectorOrXPath, document, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null).singleNodeValue
        : document.querySelector(selectorOrXPath);
    if (!node)
        return waitForHidden;
    if (!waitForVisible && !waitForHidden)
        return node;
    const element = /** @type {Element} */ (node.nodeType === Node.TEXT_NODE ? node.parentElement : node);

    const style = window.getComputedStyle(element);
    const isVisible = style && style.visibility !== 'hidden' && hasVisibleBoundingBox();
    const success = (waitForVisible === isVisible || waitForHidden === !isVisible)
    return success ? node : null

    function hasVisibleBoundingBox() {
        const rect = element.getBoundingClientRect();
        return !!(rect.top || rect.bottom || rect.width || rect.height);
    }
}
        '''  # noqa: E501
        return self.waitForFunction(
            predicate,
            {'timeout': timeout, 'polling': polling},
            selectorOrXPath,
            isXPath,
            waitForVisible,
            waitForHidden,
        )
Пример #50
0
 async def start(self, options: Dict = None, **kwargs: Any) -> None:
     'Start coverage measurement.'
     options = merge_dict(options, kwargs)
     if self._enabled:
         raise PageError('JSCoverage is always enabled.')
     self._resetOnNavigation = (True if (
         'resetOnNavigation' not in options) else bool(options['resetOnNavigation']))
     self._reportAnonymousScript = bool(
         options.get('reportAnonymousScript'))
     self._enabled = True
     self._scriptURLs.clear()
     self._scriptSources.clear()
     self._eventListeners = [helper.addEventListener(self._client, 'Debugger.scriptParsed', (lambda e: self._client._loop.create_task(
         self._onScriptParsed(e)))), helper.addEventListener(self._client, 'Runtime.executionContextsCleared', self._onExecutionContextsCleared)]
     (await self._client.send('Profiler.enable'))
     (await self._client.send('Profiler.startPreciseCoverage', {
         'callCount': False,
         'detailed': True,
     }))
     (await self._client.send('Debugger.enable'))
     (await self._client.send('Debugger.setSkipAllPauses', {
         'skip': True,
     }))
Пример #51
0
    async def screenshot(self, options: Dict = None, **kwargs: Any) -> bytes:
        """Take a screenshot of this element.

        If the element is detached from DOM, this method raises an
        ``ElementHandleError``.

        Available options are same as :meth:`pyppeteer.page.Page.screenshot`.
        """
        options = merge_dict(options, kwargs)
        await self._scrollIntoViewIfNeeded()
        _obj = await self._client.send('Page.getLayoutMetrics')
        pageX = _obj['layoutViewport']['pageX']
        pageY = _obj['layoutViewport']['pageY']

        clip = await self.boundingBox()
        if not clip:
            raise ElementHandleError('Node is not visible.')

        clip['x'] = clip['x'] + pageX
        clip['y'] = clip['y'] + pageY
        opt = {'clip': clip}
        opt.update(options)
        return await self._page.screenshot(opt)
Пример #52
0
    async def move(self, x: float, y: float, options: dict = None,
                   **kwargs: Any) -> None:
        """Move mouse cursor (dispatches a ``mousemove`` event).

        Options can accepts ``steps`` (int) field. If this ``steps`` option
        specified, Sends intermediate ``mousemove`` events. Defaults to 1.
        """
        options = merge_dict(options, kwargs)
        fromX = self._x
        fromY = self._y
        self._x = x
        self._y = y
        steps = options.get('steps', 1)
        for i in range(1, steps + 1):
            x = round(fromX + (self._x - fromX) * (i / steps))
            y = round(fromY + (self._y - fromY) * (i / steps))
            await self._client.send('Input.dispatchMouseEvent', {
                'type': 'mouseMoved',
                'button': self._button,
                'x': x,
                'y': y,
                'modifiers': self._keyboard._modifiers,
            })
Пример #53
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'))
Пример #54
0
    def __init__(
            self,
            options,  # noqa: C901
            **kwargs) -> 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 = [f'--remote-debugging-port={self.port}']
        self._loop = self.options.get('loop', asyncio.get_event_loop())

        logLevel = self.options.get('logLevel')
        if logLevel:
            logging.getLogger('pyppeteer').setLevel(logLevel)
        self.chromeClosed = True
        if self.options.get('appMode', False):
            self.options['headless'] = False
        self._tmp_user_data_dir = 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',
            ])
        if 'executablePath' in self.options:
            self.exec = self.options['executablePath']
        else:
            if not check_chromium():
                download_chromium()
            self.exec = str(chromium_excutable())
        self.cmd = [self.exec] + self.chrome_args
Пример #55
0
    def __init__(self, connection: Connection, options: Dict=None, process: Optional[Popen]=None, closeCallback: Callable[([], Awaitable[None])]=None, **kwargs: Any) -> None:
        super().__init__()
        options = merge_dict(options, kwargs)
        self._ignoreHTTPSErrors = bool(options.get('ignoreHTTPSErrors', False))
        self._appMode = bool(options.get('appMode', False))
        self._process = process
        self._screenshotTaskQueue = []
        self._connection = connection

        def _dummy_callback() -> Awaitable[None]:
            fut = asyncio.get_event_loop().create_future()
            fut.set_result(None)
            return fut
        if closeCallback:
            self._closeCallback = closeCallback
        else:
            self._closeCallback = _dummy_callback
        self._targets = dict()
        self._connection.setClosedCallback(
            (lambda: self.emit(Browser.Events.Disconnected)))
        self._connection.on('Target.targetCreated', self._targetCreated)
        self._connection.on('Target.targetDestroyed', self._targetDestroyed)
        self._connection.on('Target.targetInfoChanged',
                            self._targetInfoChanged)
Пример #56
0
    async def waitForTarget(self, predicate, options=None, **kwargs):
        options = merge_dict(options, kwargs)
        timeout = options.get("timeout", 30000)
        with contextlib.suppress(StopIteration):
            return next(filter(lambda u: u == predicate, self.targets()))
        resolve = self._connection._loop.create_future()

        def check(target):
            if predicate(target):
                resolve.set_result(target)

        self.on(Browser.Events.TargetCreated, check)
        self.on(Browser.Events.TargetChanged, check)
        try:
            if timeout:
                return await asyncio.wait_for(resolve, timeout=timeout)
            return await resolve
        except asyncio.TimeoutError:
            raise TimeoutError(
                "waiting for target target: "
                f"timeout {timeout * 1000}ms exceeded") from None
        finally:
            self.remove_listener(Browser.Events.TargetCreated, check)
            self.remove_listener(Browser.Events.TargetChanged, check)
Пример #57
0
    async def press(self, key: str, options: Dict = None, **kwargs: Any
                    ) -> None:
        """Press ``key``.

        If ``key`` is a single character and no modifier keys besides
        ``Shift`` are being held down, a ``keypress``/``input`` event will also
        generated. The ``text`` option can be specified to force an input event
        to be generated.

        :arg str key: Name of key to press, such as ``ArrowLeft``.

        This method accepts the following options:

        * ``text`` (str): If specified, generates an input event with this
          text.
        * ``delay`` (int|float): Time to wait between ``keydown`` and
          ``keyup``. Defaults to 0.
        """
        options = merge_dict(options, kwargs)

        await self.down(key, options)
        if options and options.get('delay'):
            await asyncio.sleep(options['delay'] / 1000)
        await self.up(key)
Пример #58
0
    def __init__(
            self,
            options: Dict[str, Any] = None,  # noqa: C901
            **kwargs: Any) -> None:
        """Make new launcher."""
        options = merge_dict(options, kwargs)

        self.port = get_free_port()
        self.url = f'http://127.0.0.1:{self.port}'
        self._loop = options.get('loop', asyncio.get_event_loop())
        self.chromeClosed = True

        ignoreDefaultArgs = options.get('ignoreDefaultArgs', False)
        args: List[str] = options.get('args', list())
        self.dumpio = options.get('dumpio', False)
        executablePath = options.get('executablePath')
        self.env = options.get('env')
        self.handleSIGINT = options.get('handleSIGINT', True)
        self.handleSIGTERM = options.get('handleSIGTERM', True)
        self.handleSIGHUP = options.get('handleSIGHUP', True)
        self.ignoreHTTPSErrors = options.get('ignoreHTTPSErrors', False)
        self.defaultViewport = options.get('defaultViewport', {
            'width': 800,
            'height': 600
        })  # noqa: E501
        self.slowMo = options.get('slowMo', 0)
        self.timeout = options.get('timeout', 30000)
        self.autoClose = options.get('autoClose', True)

        logLevel = options.get('logLevel')
        if logLevel:
            logging.getLogger('pyppeteer').setLevel(logLevel)

        self.chromeArguments: List[str] = list()
        if not ignoreDefaultArgs:
            self.chromeArguments.extend(defaultArgs(options))
        elif isinstance(ignoreDefaultArgs, list):
            self.chromeArguments.extend(
                filter(
                    lambda arg: arg not in ignoreDefaultArgs,
                    defaultArgs(options),
                ))
        else:
            self.chromeArguments.extend(args)

        self.temporaryUserDataDir: Optional[str] = None

        if not any(arg for arg in self.chromeArguments
                   if arg.startswith('--remote-debugging-')):
            self.chromeArguments.append(f'--remote-debugging-port={self.port}')

        if not any(arg for arg in self.chromeArguments
                   if arg.startswith('--user-data-dir')):
            if not CHROME_PROFILE_PATH.exists():
                CHROME_PROFILE_PATH.mkdir(parents=True)
            self.temporaryUserDataDir = tempfile.mkdtemp(
                dir=str(CHROME_PROFILE_PATH))  # noqa: E501
            self.chromeArguments.append(
                f'--user-data-dir={self.temporaryUserDataDir}')  # noqa: E501

        self.chromeExecutable = executablePath
        if not self.chromeExecutable:
            if not check_chromium():
                download_chromium()
            self.chromeExecutable = str(chromium_executable())

        self.cmd = [self.chromeExecutable] + self.chromeArguments
Пример #59
0
 async def startCSSCoverage(self, options: Dict = None, **kwargs: Any) -> None:
     'Start CSS coverage measurement.\n\n        Available options are:\n\n        * ``resetOnNavigation`` (bool): Whether to reset coverage on every\n          navigation. Defaults to ``True``.\n        '
     options = merge_dict(options, kwargs)
     (await self._cssCoverage.start(options))
Пример #60
0
    async def pdf(self, options: dict = None, **kwargs: Any) -> bytes:
        """Generate a pdf of the page.

        Options:

        * ``path`` (str): The file path to save the PDF.
        * ``scale`` (float): Scale of the webpage rendering, defaults to ``1``.
        * ``displayHeaderFooter`` (bool): Display header and footer.
          Defaults to ``False``.
        * ``headerTemplate`` (str): HTML template for the print header. Should
          be valid HTML markup with following classes.

          * ``data``: formatted print date
          * ``title``: document title
          * ``url``: document location
          * ``pageNumber``: current page number
          * ``totalPages``: total pages in the document

        * ``footerTemplate`` (str): HTML template for the print footer. Should
          use the same template as ``headerTemplate``.
        * ``printBackground`` (bool): Print background graphics. Defaults to
          ``False``.
        * ``landscape`` (bool): Paper orientation. Defaults to ``False``.
        * ``pageRanges`` (string): Paper ranges to print, e.g., '1-5,8,11-13'.
          Defaults to empty string, which means all pages.
        * ``foramt`` (str): Paper format. If set, takes prioprity over
          ``width`` or ``height``. Defaults to ``Letter``.
        * ``width`` (str): Paper width, accepts values labeled with units.
        * ``height`` (str): Paper height, accepts values labeled with units.
        * ``margin`` (dict): Paper margins, defaults to ``None``.

          * ``top`` (str): Top margin, accepts values labeled with units.
          * ``right`` (str): Right margin, accepts values labeled with units.
          * ``bottom`` (str): Bottom margin, accepts values labeled with units.
          * ``left`` (str): Left margin, accepts values labeled with units.

        :return bytes: Return generated PDF ``bytes`` object.
        """
        options = merge_dict(options, kwargs)
        scale = options.get('scale', 1)
        displayHeaderFooter = bool(options.get('displayHeaderFooter'))
        headerTemplate = options.get('headerTemplate', '')
        footerTemplate = options.get('footerTemplate', '')
        printBackground = bool(options.get('printBackground'))
        landscape = bool(options.get('landscape'))
        pageRanges = options.get('pageRanges', '')

        paperWidth = 8.5
        paperHeight = 11.0
        if 'format' in options:
            fmt = Page.PaperFormats.get(options['format'].lower())
            if not fmt:
                raise ValueError('Unknown paper format: ' + options['format'])
            paperWidth = fmt['width']
            paperHeight = fmt['height']
        else:
            paperWidth = convertPrintParameterToInches(
                options.get('width')) or paperWidth  # noqa: E501
            paperHeight = convertPrintParameterToInches(
                options.get('height')) or paperHeight  # noqa: E501

        marginOptions = options.get('margin', {})
        marginTop = convertPrintParameterToInches(
            marginOptions.get('top')) or 0  # noqa: E501
        marginLeft = convertPrintParameterToInches(
            marginOptions.get('left')) or 0  # noqa: E501
        marginBottom = convertPrintParameterToInches(
            marginOptions.get('bottom')) or 0  # noqa: E501
        marginRight = convertPrintParameterToInches(
            marginOptions.get('right')) or 0  # noqa: E501

        result = await self._client.send(
            'Page.printToPDF',
            dict(landscape=landscape,
                 displayHeaderFooter=displayHeaderFooter,
                 headerTemplate=headerTemplate,
                 footerTemplate=footerTemplate,
                 printBackground=printBackground,
                 scale=scale,
                 paperWidth=paperWidth,
                 paperHeight=paperHeight,
                 marginTop=marginTop,
                 marginBottom=marginBottom,
                 marginLeft=marginLeft,
                 marginRight=marginRight,
                 pageRanges=pageRanges))
        buffer = base64.b64decode(result.get('data', b''))
        if 'path' in options:
            with open(options['path'], 'wb') as f:
                f.write(buffer)
        return buffer