Exemplo n.º 1
0
    def waitFor(self,
                selectorOrFunctionOrTimeout: Union[str, int, float],
                options: dict = None,
                *args: Any,
                **kwargs: Any) -> Awaitable:
        """Wait for function, timeout, or element which matches on page.

        This method behaves differently with respect to the first argument:

        * If ``selectorOrFunctionOrTimeout`` is number (int or float), then it
          is treated as a timeout in milliseconds and this returns future which
          will be done after the timeout.
        * If ``selectorOrFunctionOrTimeout`` is a string of JavaScript
          function, this method is a shortcut to :meth:`waitForFunction`.
        * If ``selectorOrFunctionOrTimeout`` is a selector string, this method
          is a shortcut to :meth:`waitForSelector`.

        Pyppeteer tries to automatically detect function or selector, but
        sometimes miss-detects. If not work as you expected, use
        :meth:`waitForFunction` or :meth:`waitForSelector` dilectly.
        """
        frame = self.mainFrame
        if not frame:
            raise PageError('no main frame.')
        return frame.waitFor(selectorOrFunctionOrTimeout, options, *args,
                             **kwargs)
Exemplo n.º 2
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._enabled = True
     self._scriptURLs.clear()
     self._scriptSources.clear()
     self._eventListeners = [
         helper.addEventListener(
             self._client, 'Debugger.scriptParsed',
             (lambda e: asyncio.ensure_future(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,
     }))
Exemplo n.º 3
0
 async def stop(self) -> List:
     'Stop coverage measurement and return results.'
     if (not self._enabled):
         raise PageError('CSSCoverage is not enabled.')
     self._enabled = False
     result = (await self._client.send('CSS.stopRuleUsageTracking'))
     (await self._client.send('CSS.disable'))
     (await self._client.send('DOM.disable'))
     helper.removeEventListeners(self._eventListeners)
     styleSheetIdToCoverage = {}
     for entry in result['ruleUsage']:
         ranges = styleSheetIdToCoverage.get(entry['styleSheetId'])
         if (not ranges):
             ranges = []
             styleSheetIdToCoverage[entry['styleSheetId']] = ranges
         ranges.append({
             'startOffset': entry['startOffset'],
             'endOffset': entry['endOffset'],
             'count': (1 if entry['used'] else 0),
         })
     coverage = []
     for styleSheetId in self._stylesheetURLs:
         url = self._stylesheetURLs.get(styleSheetId)
         text = self._stylesheetSources.get(styleSheetId)
         ranges = convertToDisjointRanges(
             styleSheetIdToCoverage.get(styleSheetId, []))
         coverage.append({
             'url': url,
             'ranges': ranges,
             'text': text,
         })
     return coverage
Exemplo n.º 4
0
 async def addStyleTag(self, options: Dict) -> ElementHandle:
     'Add style tag to this frame.\n\n        Details see :meth:`pyppeteer.page.Page.addStyleTag`.\n        '
     context = (await self.executionContext())
     if (context is None):
         raise ElementHandleError('ExecutionContext is None.')
     addStyleUrl = "\n        async function (url) {\n            const link = document.createElement('link');\n            link.rel = 'stylesheet';\n            link.href = url;\n            document.head.appendChild(link);\n            await new Promise((res, rej) => {\n                link.onload = res;\n                link.onerror = rej;\n            });\n            return link;\n        }"
     addStyleContent = "\n        function (content) {\n            const style = document.createElement('style');\n            style.type = 'text/css';\n            style.appendChild(document.createTextNode(content));\n            document.head.appendChild(style);\n            return style;\n        }"
     if isinstance(options.get('url'), str):
         url = options['url']
         try:
             return (await context.evaluateHandle(addStyleUrl,
                                                  url)).asElement()
         except ElementHandleError as e:
             raise PageError(''.join(
                 ['Loading style from ', '{}'.format(url),
                  ' failed'])) from e
     if isinstance(options.get('path'), str):
         with open(options['path']) as f:
             contents = f.read()
         contents = (
             contents +
             '/*# sourceURL={}*/'.format(options['path'].replace('\n', '')))
         return (await context.evaluateHandle(addStyleContent,
                                              contents)).asElement()
     if isinstance(options.get('content'), str):
         return (await
                 context.evaluateHandle(addStyleContent,
                                        options['content'])).asElement()
     raise ValueError(
         'Provide an object with a `url`, `path` or `content` property')
Exemplo n.º 5
0
 async def stop(self) -> List:
     'Stop coverage measurement and return results.'
     if (not self._enabled):
         raise PageError('JSCoverage is not enabled.')
     self._enabled = False
     result = (await self._client.send('Profiler.takePreciseCoverage'))
     (await self._client.send('Profiler.stopPreciseCoverage'))
     (await self._client.send('Profiler.disable'))
     (await self._client.send('Debugger.disable'))
     helper.removeEventListeners(self._eventListeners)
     coverage = []
     for entry in result.get('result', []):
         url = self._scriptURLs.get(entry.get('scriptId'))
         text = self._scriptSources.get(entry.get('scriptId'))
         if ((text is None) or (url is None)):
             continue
         flattenRanges = []
         for func in entry.get('functions', []):
             flattenRanges.extend(func.get('ranges', []))
         ranges = convertToDisjointRanges(flattenRanges)
         coverage.append({
             'url': url,
             'ranges': ranges,
             'text': text,
         })
     return coverage
Exemplo n.º 6
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'))  # noqa: E501
     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 asyncio.gather(
         self._client.send('Profiler.enable'),
         self._client.send('Profiler.startPreciseCoverage', {
             'callCount': False,
             'detailed': True
         }), self._client.send('Debugger.enable'),
         self._client.send('Debugger.setSkipAllPauses', {'skip': True}))
Exemplo n.º 7
0
 async def addScriptTag(self, options: Dict) -> ElementHandle:
     'Add script tag to this frame.\n\n        Details see :meth:`pyppeteer.page.Page.addScriptTag`.\n        '
     context = (await self.executionContext())
     if (context is None):
         raise ElementHandleError('ExecutionContext is None.')
     addScriptUrl = "\n        async function addScriptUrl(url) {\n            const script = document.createElement('script');\n            script.src = url;\n            document.head.appendChild(script);\n            await new Promise((res, rej) => {\n                script.onload = res;\n                script.onerror = rej;\n            });\n            return script;\n        }"
     addScriptContent = "\n        function addScriptContent(content) {\n            const script = document.createElement('script');\n            script.type = 'text/javascript';\n            script.text = content;\n            document.head.appendChild(script);\n            return script;\n        }"
     if isinstance(options.get('url'), str):
         url = options['url']
         try:
             return (await context.evaluateHandle(addScriptUrl,
                                                  url)).asElement()
         except ElementHandleError as e:
             raise PageError(''.join(
                 ['Loading script from ', '{}'.format(url),
                  ' failed'])) from e
     if isinstance(options.get('path'), str):
         with open(options['path']) as f:
             contents = f.read()
         contents = (
             contents +
             '//# sourceURL={}'.format(options['path'].replace('\n', '')))
         return (await context.evaluateHandle(addScriptContent,
                                              contents)).asElement()
     if isinstance(options.get('content'), str):
         return (await
                 context.evaluateHandle(addScriptContent,
                                        options['content'])).asElement()
     raise ValueError(
         'Provide an object with a `url`, `path` or `content` property')
Exemplo n.º 8
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
Exemplo n.º 9
0
    async def evaluateHandle(self, pageFunction: str, *args: Any
                             ) -> JSHandle:
        """Execute function on this page.

        Difference between :meth:`~pyppeteer.page.Page.evaluate` and
        :meth:`~pyppeteer.page.Page.evaluateHandle` is that
        ``evaluateHandle`` returns JSHandle object (not value).

        :arg str pageFunction: JavaScript function to be executed.
        """
        if not self.mainFrame:
            raise PageError('no main frame.')
        if not self.mainFrame.executionContext:
            raise PageError('No context.')
        return await self.mainFrame.executionContext.evaluateHandle(
            pageFunction, *args)
Exemplo n.º 10
0
    async def stop(self) -> List:
        """Stop coverage measurement and return results."""
        if not self._enabled:
            raise PageError('JSCoverage is not enabled.')
        self._enabled = False

        result = await self._client.send('Profiler.takePreciseCoverage')
        await self._client.send('Profiler.stopPreciseCoverage')
        await self._client.send('Profiler.disable')
        await self._client.send('Debugger.disable')
        helper.removeEventListeners(self._eventListeners)

        coverage: List = []
        for entry in result.get('result', []):
            url = self._scriptURLs.get(entry.get('scriptId'))
            if not url and self._reportAnonymousScript:
                url = f'debugger://VM{entry.get("scriptId")}'
            text = self._scriptSources.get(entry.get('scriptId'))
            if text is None or url is None:
                continue
            flattenRanges: List = []
            for func in entry.get('functions', []):
                flattenRanges.extend(func.get('ranges', []))
            ranges = convertToDisjointRanges(flattenRanges)
            coverage.append({'url': url, 'ranges': ranges, 'text': text})
        return coverage
Exemplo n.º 11
0
    def waitForFunction(self,
                        pageFunction: str,
                        options: dict = None,
                        *args: str,
                        **kwargs: Any) -> Awaitable:
        """Wait until the function completes and returns a truethy value.

        :arg Any args: Arguments to pass to ``pageFunction``.
        :return: Return awaitable object which resolves when the
                 ``pageFunction`` returns a truethy value. It resolves to a
                 :class:`~pyppeteer.execution_context.JSHandle` of the truethy
                 value.

        This method accepts the following options:

        * ``polling`` (str|number): An interval at which the ``pageFunction``
          is executed, defaults to ``raf``. If ``polling`` is a number, then
          it is treated as an interval in milliseconds at which the function
          would be executed. If ``polling`` is a string, then it can be one of
          the following values:

          * ``raf``: to constantly execute ``pageFunction`` in
            ``requestAnimationFrame`` callback. This is the tightest polling
            mode which is suitable to observe styling changes.
          * ``mutation``: to execute ``pageFunction`` on every DOM mutation.

        * ``timeout`` (int|float): maximum time to wait for in milliseconds.
        """
        frame = self.mainFrame
        if not frame:
            raise PageError('no main frame.')
        return frame.waitForFunction(pageFunction, options, *args, **kwargs)
Exemplo n.º 12
0
    def waitForSelector(self,
                        selector: str,
                        options: dict = None,
                        **kwargs: Any) -> Awaitable:
        """Wait until element which matches ``selector`` appears on page.

        Wait for the ``selector`` to appear in page. If at the moment of
        callingthe method the ``selector`` already exists, the method will
        return immediately. If the selector doesn't appear after the
        ``timeout`` milliseconds of waiting, the function will raise error.

        :arg str selector: A selector of an element to wait for.
        :return: Return awaitable object which resolves when element specified
                 by selector string is added to DOM.

        This method accepts the following options:

        * ``visible`` (bool): Wait for element to be present in DOM and to be
          visible; i.e. to not have ``display: none`` or ``visibility: hidden``
          CSS properties. Defaults to ``False``.
        * ``hidden`` (bool): Wait for eleemnt to not be found in the DOM or to
          be hidden, i.e. have ``display: none`` or ``visibility: hidden`` CSS
          properties. Defaults to ``False``.
        * ``timeout`` (int|float): Maximum time to wait for in milliseconds.
          Defaults to 30000 (30 seconds).
        """
        frame = self.mainFrame
        if not frame:
            raise PageError('no main frame.')
        return frame.waitForSelector(selector, options, **kwargs)
    def _onFrameNavigated(self, framePayload: dict) -> None:
        isMainFrame = not framePayload.get('parentId')
        if isMainFrame:
            frame = self._mainFrame
        else:
            frame = self._frames.get(framePayload.get('id', ''))
        if not (isMainFrame or frame):
            raise PageError('We either navigate top level or have old version '
                            'of the navigated frame')

        # Detach all child frames first.
        if frame:
            for child in frame.childFrames:
                self._removeFramesRecursively(child)

        # Update or create main frame.
        _id = framePayload.get('id', '')
        if isMainFrame:
            if frame:
                # Update frame id to retain frame identity on cross-process navigation.  # noqa: E501
                self._frames.pop(frame._id, None)
                frame._id = _id
            else:
                # Initial main frame navigation.
                frame = Frame(self._client, self._page, None, _id)
            self._frames[_id] = frame
            self._mainFrame = frame

        # Update frame payload.
        frame._navigated(framePayload)  # type: ignore
        self.emit(FrameManager.Events.FrameNavigated, frame)
    async def addStyleTag(self, options: Dict) -> ElementHandle:
        """Add style tag to this frame.

        Details see :meth:`pyppeteer.page.Page.addStyleTag`.
        """
        context = await self.executionContext()
        if context is None:
            raise ElementHandleError('ExecutionContext is None.')

        addStyleUrl = '''
        async function (url) {
            const link = document.createElement('link');
            link.rel = 'stylesheet';
            link.href = url;
            const promise = new Promise((res, rej) => {
                link.onload = res;
                link.onerror = rej;
            });
            document.head.appendChild(link);
            await promise;
            return link;
        }'''

        addStyleContent = '''
        async function (content) {
            const style = document.createElement('style');
            style.type = 'text/css';
            style.appendChild(document.createTextNode(content));
            const promise = new Promise((res, rej) => {
                style.onload = res;
                style.onerror = rej;
            });
            document.head.appendChild(style);
            await promise;
            return style;
        }'''

        if isinstance(options.get('url'), str):
            url = options['url']
            try:
                return (await context.evaluateHandle(  # type: ignore
                    addStyleUrl, url)).asElement()
            except ElementHandleError as e:
                raise PageError(f'Loading style from {url} failed') from e

        if isinstance(options.get('path'), str):
            with open(options['path']) as f:
                contents = f.read()
            contents = contents + '/*# sourceURL={}*/'.format(
                options['path'].replace('\n', ''))
            return (await context.evaluateHandle(  # type: ignore
                addStyleContent, contents)).asElement()

        if isinstance(options.get('content'), str):
            return (await context.evaluateHandle(  # type: ignore
                addStyleContent, options['content'])).asElement()

        raise ValueError(
            'Provide an object with a `url`, `path` or `content` property')
Exemplo n.º 15
0
 async def close(self) -> None:
     """Close connection."""
     conn = self._client._connection
     if conn is None:
         raise PageError('Protocol Error: Connectoin Closed. '
                         'Most likely the page has been closed.')
     await conn.send('Target.closeTarget',
                     {'targetId': self._target._targetId})
Exemplo n.º 16
0
 def _detach(self) -> None:
     for waitTask in self._waitTasks:
         waitTask.terminate(
             PageError('waitForFunction failed: frame got detached.'))
     self._detached = True
     if self._parentFrame:
         self._parentFrame._childFrames.remove(self)
     self._parentFrame = None
Exemplo n.º 17
0
 async def _document(self) -> ElementHandle:
     if not self._documentPromise:
         context = await self.executionContext()
         if context is None:
             raise PageError('No context exists.')
         self._documentPromise = (
             await context.evaluateHandle('document')).asElement()
     return self._documentPromise
Exemplo n.º 18
0
    async def evaluateHandle(self, pageFunction: str, *args: Any) -> JSHandle:
        """Execute fucntion on this frame.

        Details see :meth:`pyppeteer.page.Page.evaluateHandle`.
        """
        context = await self.executionContext()
        if context is None:
            raise PageError('this frame has no context.')
        return await context.evaluateHandle(pageFunction, *args)
Exemplo n.º 19
0
 def waitForSelector(self,
                     selector: str,
                     options: dict = None,
                     **kwargs: Any) -> Awaitable:
     """Wait until element which matches selector appears on page."""
     frame = self.mainFrame
     if not frame:
         raise PageError('no main frame.')
     return frame.waitForSelector(selector, options, **kwargs)
Exemplo n.º 20
0
    async def injectFile(self, filePath: str) -> str:
        """[Deprecated] Inject file to this page.

        This method is deprecated. Use :meth:`addScriptTag` instead.
        """
        frame = self.mainFrame
        if not frame:
            raise PageError('no main frame.')
        return await frame.injectFile(filePath)
Exemplo n.º 21
0
 async def addStyleTag(self, options: Dict = None, **kwargs: str) -> str:
     """Add script tag to this page."""
     frame = self.mainFrame
     if not frame:
         raise PageError('no main frame.')
     if options is None:
         options = {}
     options.update(kwargs)
     return await frame.addStyleTag(options)
Exemplo n.º 22
0
 async def click(self, selector: str, options: dict = None, **kwargs: Any
                 ) -> None:
     """Click element which matches `selector`."""
     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()
Exemplo n.º 23
0
    async def select(self, selector: str, *values: str) -> List[str]:
        """Select options and return selected values.

        If no element matched the ``selector``, raise ``ElementHandleError``.
        """
        frame = self.mainFrame
        if not frame:
            raise PageError('no main frame.')
        return await frame.select(selector, *values)
Exemplo n.º 24
0
    async def rerun(self) -> None:  # noqa: C901
        """Start polling."""
        runCount = self._runCount = self._runCount + 1
        success: Optional[JSHandle] = None
        error = None

        try:
            context = await self._frame.executionContext()
            if context is None:
                raise PageError('No execution context.')
            success = await context.evaluateHandle(
                waitForPredicatePageFunction,
                self._predicateBody,
                self._polling,
                self._timeout,
                *self._args,
            )
        except Exception as e:
            error = e

        if self.promise.done():
            return

        if self._terminated or runCount != self._runCount:
            if success:
                await success.dispose()
            return

        # Add try/except referring to puppeteer.
        try:
            if not error and success and (await self._frame.evaluate(
                    's => !s', success)):
                await success.dispose()
                return
        except NetworkError:
            if success is not None:
                await success.dispose()
            return

        # page is navigated and context is destroyed.
        # Try again in the new execution context.
        if (isinstance(error, NetworkError)
                and 'Execution context was destroyed' in error.args[0]):
            return

        # Try again in the new execution context.
        if (isinstance(error, NetworkError)
                and 'Cannot find context with specified id' in error.args[0]):
            return

        if error:
            self.promise.set_exception(error)
        else:
            self.promise.set_result(success)

        self._cleanup()
Exemplo n.º 25
0
    async def tap(self, selector: str) -> None:
        """Tap the element which matches the ``selector``.

        Details see :meth:`pyppeteer.page.Page.tap`.
        """
        handle = await self.J(selector)
        if not handle:
            raise PageError('No node found for selector: ' + selector)
        await handle.tap()
        await handle.dispose()
Exemplo n.º 26
0
    async def hover(self, selector: str) -> None:
        """Mouse hover the element which matches ``selector``.

        Details see :meth:`pyppeteer.page.Page.hover`.
        """
        handle = await self.J(selector)
        if not handle:
            raise PageError('No node found for selector: ' + selector)
        await handle.hover()
        await handle.dispose()
Exemplo n.º 27
0
    async def focus(self, selector: str) -> None:
        """Fucus element which matches ``selector``.

        Details see :meth:`pyppeteer.page.Page.focus`.
        """
        handle = await self.J(selector)
        if not handle:
            raise PageError('No node found for selector: ' + selector)
        await self.evaluate('element => element.focus()', handle)
        await handle.dispose()
Exemplo n.º 28
0
 def waitForFunction(self,
                     pageFunction: str,
                     options: dict = None,
                     *args: str,
                     **kwargs: Any) -> Awaitable:
     """Wait for function."""
     frame = self.mainFrame
     if not frame:
         raise PageError('no main frame.')
     return frame.waitForFunction(pageFunction, options, *args, **kwargs)
Exemplo n.º 29
0
    async def focus(self, selector: str) -> None:
        """Focus the element which matches ``selector``.

        If no element matched the ``selector``, raise ``PageError``.
        """
        handle = await self.J(selector)
        if not handle:
            raise PageError('No node found for selector: ' + selector)
        await self.evaluate('element => element.focus()', handle)
        await handle.dispose()
Exemplo n.º 30
0
    async def tap(self, selector: str) -> None:
        """Tap the element which matches the ``selector``.

        :arg str selector: A selector to search element to touch.
        """
        handle = await self.J(selector)
        if not handle:
            raise PageError('No node found for selector: ' + selector)
        await handle.tap()
        await handle.dispose()