python-recentx


Namepython-recentx JSON
Version 1.4.5 PyPI version JSON
download
home_pagehttps://github.com/HMaker/python-recentx
SummaryPython type wrappers for Chrome DevTools Protocol (CDP)
upload_time2024-04-24 09:30:22
maintainerNone
docs_urlNone
authorMark E. Haase
requires_python<4.0,>=3.8
licenseMIT
keywords
VCS
bugtrack_url
requirements No requirements were recorded.
Travis-CI No Travis.
coveralls test coverage No coveralls.
            # Python CDP
#### Currently supports CDP [r1179426][2] (Chrome 117).

Python CDP Generator (shortened to PyCDP) is a library that provides
Python wrappers for the types, commands, and events specified in the [Chrome
DevTools Protocol][1].  

The Chrome DevTools Protocol provides for remote control of a web browser by
sending JSON messages over a WebSocket. That JSON format is described by a
machine-readable specification. This specification is used to automatically
generate the classes and methods found in this library.

## Installation
You can install this library as a dependency on your project with:
```
pip install git+https://github.com/HMaker/python-recentx.git@latest
```
Change the git tag `@latest` if you need another version. To install for development, clone this
repository, install [Poetry][5] package manager and run `poetry install` to install dependencies.

## Usage
If all you want is automate Chrome right now, PyCDP includes a low-level client for asyncio and twisted:
```python
import asyncio
from pycdp import cdp
from pycdp.browser import ChromeLauncher
from pycdp.asyncio import connect_cdp

async def main():
    chrome = ChromeLauncher(
        binary='/usr/bin/google-chrome', # linux path
        args=['--remote-debugging-port=9222', '--incognito']
    )
    # ChromeLauncher.launch() is blocking, run it on a background thread
    await asyncio.get_running_loop().run_in_executor(None, chrome.launch)
    conn = await connect_cdp('http://localhost:9222')
    target_id = await conn.execute(cdp.target.create_target('about:blank'))
    target_session = await conn.connect_session(target_id)
    await target_session.execute(cdp.page.enable())
    # you may use "async for target_session.listen()" to listen multiple events, here we listen just a single event.
    with target_session.safe_wait_for(cdp.page.DomContentEventFired) as navigation:
        await target_session.execute(cdp.page.navigate('https://chromedevtools.github.io/devtools-protocol/'))
        await navigation
    dom = await target_session.execute(cdp.dom.get_document())
    node = await target_session.execute(cdp.dom.query_selector(dom.node_id, 'p'))
    js_node = await target_session.execute(cdp.dom.resolve_node(node))
    print((await target_session.execute(cdp.runtime.call_function_on('function() {return this.innerText;}', js_node.object_id, return_by_value=True)))[0].value)
    await target_session.execute(cdp.page.close())
    await conn.close()
    await asyncio.get_running_loop().run_in_executor(None, chrome.kill)

asyncio.run(main())
```
the twisted client requires [twisted][6] and [autobahn][7] packages:
```python
from twisted.python.log import err
from twisted.internet import reactor, defer, threads
from pycdp import cdp
from pycdp.browser import ChromeLauncher
from pycdp.twisted import connect_cdp

async def main():
    chrome = ChromeLauncher(
        binary='C:\Program Files\Google\Chrome\Application\chrome.exe', # windows path
        args=['--remote-debugging-port=9222', '--incognito']
    )
    await threads.deferToThread(chrome.launch)
    conn = await connect_cdp('http://localhost:9222', reactor)
    target_id = await conn.execute(cdp.target.create_target('about:blank'))
    target_session = await conn.connect_session(target_id)
    await target_session.execute(cdp.page.enable())
    await target_session.execute(cdp.page.navigate('https://chromedevtools.github.io/devtools-protocol/'))
    async with target_session.wait_for(cdp.page.DomContentEventFired):
        dom = await target_session.execute(cdp.dom.get_document())
        node = await target_session.execute(cdp.dom.query_selector(dom.node_id, 'p'))
        js_node = await target_session.execute(cdp.dom.resolve_node(node))
        print((await target_session.execute(cdp.runtime.call_function_on('function() {return this.innerText;}', js_node.object_id, return_by_value=True)))[0].value)
    await target_session.execute(cdp.page.close())
    await conn.close()
    await threads.deferToThread(chrome.kill)

def main_error(failure):
    err(failure)
    reactor.stop()

d = defer.ensureDeferred(main())
d.addErrback(main_error)
d.addCallback(lambda *args: reactor.stop())
reactor.run()
```

You also can use just the built-in CDP type wrappers with `import pycdp.cdp` on your own client implementation. If you want to try a different CDP version you can build new type wrappers with `cdpgen` command:
```
usage: cdpgen <arguments>

Generate Python types for the Chrome Devtools Protocol (CDP) specification.

optional arguments:
  -h, --help            show this help message and exit
  --browser-protocol BROWSER_PROTOCOL
                        JSON file for the browser protocol
  --js-protocol JS_PROTOCOL
                        JSON file for the javascript protocol
  --output OUTPUT       output path for the generated Python modules

JSON files for the CDP spec can be found at https://github.com/ChromeDevTools/devtools-protocol/tree/master/json
```
Example:
```sh
cdpgen --browser-protocol browser_protocol.json --js-protocol js_protocol.json --output /tmp/cdp
```
You can then include the `/tmp/cdp` package in your project and import it like the builtin CDP types.  

### Updating built-in CDP wrappers
The `update-cdp.sh` script generates the builtin CDP wrappers, the `pycdp.cdp` package, by automatically fetching CDP protocol specifications from the [ChromeDevTools][8] repostitory.

**To generate types for the latest version:**
```shell
./update-cdp.sh
```
**To generate types for a specific version, you must provide full commit hash:**
```shell
./update-cdp.sh 4dd6c67776f43f75bc9b19f09618c151621c6ed9
```
P.S. Don't forget to make it executable by running `chmod +x update-cdp.sh`

## Implementation of a CDP client
The `pycdp.cdp` package follows same structure of CDP domains, each domain is a Python module and each command a function in that module.

Each function is a generator with a single yield which is a Python dict, on the CDP wire format,
containing the message that should be sent to the browser, on resumption the generator receives the message from browser:
```python
import cdp

# Get all CDP targets
command = cdp.target.get_targets() # this is a generator
raw_cdp_request = next(command) # receive the yield
raw_cdp_response = send_cdp_request(raw_cdp_request) # you implement send_cdp_request, raw_cdp_request is the JSON object that should be sent to browser
try:
    command.send(raw_cdp_response) # send the response to the generator where raw_cdp_response is the JSON object received from browser, it will raise StopIteration
    raise RuntimeError("the generator didnt exit!") # this shouldnt happen
except StopIteration as result:
    response = result.value # the parsed response to Target.get_targets() command
print(response)
```
For implementation details check out the [docs][3].

<br>
<hr>
PyCDP is licensed under the MIT License.
<hr>

[1]: https://chromedevtools.github.io/devtools-protocol/
[2]: https://github.com/ChromeDevTools/devtools-protocol/tree/39e36261937bf39dced789dd7ff19df6933d56d8
[3]: docs/getting_started.rst
[4]: https://github.com/hyperiongray/trio-chrome-devtools-protocol
[5]: https://python-poetry.org/docs/
[6]: https://pypi.org/project/Twisted/
[7]: https://pypi.org/project/autobahn/
[8]: https://github.com/ChromeDevTools/devtools-protocol


            

Raw data

            {
    "_id": null,
    "home_page": "https://github.com/HMaker/python-recentx",
    "name": "python-recentx",
    "maintainer": null,
    "docs_url": null,
    "requires_python": "<4.0,>=3.8",
    "maintainer_email": null,
    "keywords": null,
    "author": "Mark E. Haase",
    "author_email": "mehaase@gmail.com",
    "download_url": "https://files.pythonhosted.org/packages/85/ad/1b2792d26465e40149f7dede703804d5db22bc450bc94f5984c52c225207/python_recentx-1.4.5.tar.gz",
    "platform": null,
    "description": "# Python CDP\n#### Currently supports CDP [r1179426][2] (Chrome 117).\n\nPython CDP Generator (shortened to PyCDP) is a library that provides\nPython wrappers for the types, commands, and events specified in the [Chrome\nDevTools Protocol][1].  \n\nThe Chrome DevTools Protocol provides for remote control of a web browser by\nsending JSON messages over a WebSocket. That JSON format is described by a\nmachine-readable specification. This specification is used to automatically\ngenerate the classes and methods found in this library.\n\n## Installation\nYou can install this library as a dependency on your project with:\n```\npip install git+https://github.com/HMaker/python-recentx.git@latest\n```\nChange the git tag `@latest` if you need another version. To install for development, clone this\nrepository, install [Poetry][5] package manager and run `poetry install` to install dependencies.\n\n## Usage\nIf all you want is automate Chrome right now, PyCDP includes a low-level client for asyncio and twisted:\n```python\nimport asyncio\nfrom pycdp import cdp\nfrom pycdp.browser import ChromeLauncher\nfrom pycdp.asyncio import connect_cdp\n\nasync def main():\n    chrome = ChromeLauncher(\n        binary='/usr/bin/google-chrome', # linux path\n        args=['--remote-debugging-port=9222', '--incognito']\n    )\n    # ChromeLauncher.launch() is blocking, run it on a background thread\n    await asyncio.get_running_loop().run_in_executor(None, chrome.launch)\n    conn = await connect_cdp('http://localhost:9222')\n    target_id = await conn.execute(cdp.target.create_target('about:blank'))\n    target_session = await conn.connect_session(target_id)\n    await target_session.execute(cdp.page.enable())\n    # you may use \"async for target_session.listen()\" to listen multiple events, here we listen just a single event.\n    with target_session.safe_wait_for(cdp.page.DomContentEventFired) as navigation:\n        await target_session.execute(cdp.page.navigate('https://chromedevtools.github.io/devtools-protocol/'))\n        await navigation\n    dom = await target_session.execute(cdp.dom.get_document())\n    node = await target_session.execute(cdp.dom.query_selector(dom.node_id, 'p'))\n    js_node = await target_session.execute(cdp.dom.resolve_node(node))\n    print((await target_session.execute(cdp.runtime.call_function_on('function() {return this.innerText;}', js_node.object_id, return_by_value=True)))[0].value)\n    await target_session.execute(cdp.page.close())\n    await conn.close()\n    await asyncio.get_running_loop().run_in_executor(None, chrome.kill)\n\nasyncio.run(main())\n```\nthe twisted client requires [twisted][6] and [autobahn][7] packages:\n```python\nfrom twisted.python.log import err\nfrom twisted.internet import reactor, defer, threads\nfrom pycdp import cdp\nfrom pycdp.browser import ChromeLauncher\nfrom pycdp.twisted import connect_cdp\n\nasync def main():\n    chrome = ChromeLauncher(\n        binary='C:\\Program Files\\Google\\Chrome\\Application\\chrome.exe', # windows path\n        args=['--remote-debugging-port=9222', '--incognito']\n    )\n    await threads.deferToThread(chrome.launch)\n    conn = await connect_cdp('http://localhost:9222', reactor)\n    target_id = await conn.execute(cdp.target.create_target('about:blank'))\n    target_session = await conn.connect_session(target_id)\n    await target_session.execute(cdp.page.enable())\n    await target_session.execute(cdp.page.navigate('https://chromedevtools.github.io/devtools-protocol/'))\n    async with target_session.wait_for(cdp.page.DomContentEventFired):\n        dom = await target_session.execute(cdp.dom.get_document())\n        node = await target_session.execute(cdp.dom.query_selector(dom.node_id, 'p'))\n        js_node = await target_session.execute(cdp.dom.resolve_node(node))\n        print((await target_session.execute(cdp.runtime.call_function_on('function() {return this.innerText;}', js_node.object_id, return_by_value=True)))[0].value)\n    await target_session.execute(cdp.page.close())\n    await conn.close()\n    await threads.deferToThread(chrome.kill)\n\ndef main_error(failure):\n    err(failure)\n    reactor.stop()\n\nd = defer.ensureDeferred(main())\nd.addErrback(main_error)\nd.addCallback(lambda *args: reactor.stop())\nreactor.run()\n```\n\nYou also can use just the built-in CDP type wrappers with `import pycdp.cdp` on your own client implementation. If you want to try a different CDP version you can build new type wrappers with `cdpgen` command:\n```\nusage: cdpgen <arguments>\n\nGenerate Python types for the Chrome Devtools Protocol (CDP) specification.\n\noptional arguments:\n  -h, --help            show this help message and exit\n  --browser-protocol BROWSER_PROTOCOL\n                        JSON file for the browser protocol\n  --js-protocol JS_PROTOCOL\n                        JSON file for the javascript protocol\n  --output OUTPUT       output path for the generated Python modules\n\nJSON files for the CDP spec can be found at https://github.com/ChromeDevTools/devtools-protocol/tree/master/json\n```\nExample:\n```sh\ncdpgen --browser-protocol browser_protocol.json --js-protocol js_protocol.json --output /tmp/cdp\n```\nYou can then include the `/tmp/cdp` package in your project and import it like the builtin CDP types.  \n\n### Updating built-in CDP wrappers\nThe `update-cdp.sh` script generates the builtin CDP wrappers, the `pycdp.cdp` package, by automatically fetching CDP protocol specifications from the [ChromeDevTools][8] repostitory.\n\n**To generate types for the latest version:**\n```shell\n./update-cdp.sh\n```\n**To generate types for a specific version, you must provide full commit hash:**\n```shell\n./update-cdp.sh 4dd6c67776f43f75bc9b19f09618c151621c6ed9\n```\nP.S. Don't forget to make it executable by running `chmod +x update-cdp.sh`\n\n## Implementation of a CDP client\nThe `pycdp.cdp` package follows same structure of CDP domains, each domain is a Python module and each command a function in that module.\n\nEach function is a generator with a single yield which is a Python dict, on the CDP wire format,\ncontaining the message that should be sent to the browser, on resumption the generator receives the message from browser:\n```python\nimport cdp\n\n# Get all CDP targets\ncommand = cdp.target.get_targets() # this is a generator\nraw_cdp_request = next(command) # receive the yield\nraw_cdp_response = send_cdp_request(raw_cdp_request) # you implement send_cdp_request, raw_cdp_request is the JSON object that should be sent to browser\ntry:\n    command.send(raw_cdp_response) # send the response to the generator where raw_cdp_response is the JSON object received from browser, it will raise StopIteration\n    raise RuntimeError(\"the generator didnt exit!\") # this shouldnt happen\nexcept StopIteration as result:\n    response = result.value # the parsed response to Target.get_targets() command\nprint(response)\n```\nFor implementation details check out the [docs][3].\n\n<br>\n<hr>\nPyCDP is licensed under the MIT License.\n<hr>\n\n[1]: https://chromedevtools.github.io/devtools-protocol/\n[2]: https://github.com/ChromeDevTools/devtools-protocol/tree/39e36261937bf39dced789dd7ff19df6933d56d8\n[3]: docs/getting_started.rst\n[4]: https://github.com/hyperiongray/trio-chrome-devtools-protocol\n[5]: https://python-poetry.org/docs/\n[6]: https://pypi.org/project/Twisted/\n[7]: https://pypi.org/project/autobahn/\n[8]: https://github.com/ChromeDevTools/devtools-protocol\n\n",
    "bugtrack_url": null,
    "license": "MIT",
    "summary": "Python type wrappers for Chrome DevTools Protocol (CDP)",
    "version": "1.4.5",
    "project_urls": {
        "Homepage": "https://github.com/HMaker/python-recentx"
    },
    "split_keywords": [],
    "urls": [
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "85ad1b2792d26465e40149f7dede703804d5db22bc450bc94f5984c52c225207",
                "md5": "b01d07cff23e5045e3ef82250e18143d",
                "sha256": "dd18e42c2287f00fce960ccb2eade39333e86611b43b233d9b2c9e187fd3b962"
            },
            "downloads": -1,
            "filename": "python_recentx-1.4.5.tar.gz",
            "has_sig": false,
            "md5_digest": "b01d07cff23e5045e3ef82250e18143d",
            "packagetype": "sdist",
            "python_version": "source",
            "requires_python": "<4.0,>=3.8",
            "size": 355413,
            "upload_time": "2024-04-24T09:30:22",
            "upload_time_iso_8601": "2024-04-24T09:30:22.227541Z",
            "url": "https://files.pythonhosted.org/packages/85/ad/1b2792d26465e40149f7dede703804d5db22bc450bc94f5984c52c225207/python_recentx-1.4.5.tar.gz",
            "yanked": false,
            "yanked_reason": null
        }
    ],
    "upload_time": "2024-04-24 09:30:22",
    "github": true,
    "gitlab": false,
    "bitbucket": false,
    "codeberg": false,
    "github_user": "HMaker",
    "github_project": "python-recentx",
    "github_not_found": true,
    "lcname": "python-recentx"
}
        
Elapsed time: 0.23276s