{"id":13585724,"url":"https://github.com/chazkii/chromewhip","last_synced_at":"2025-07-15T19:46:19.675Z","repository":{"id":40740320,"uuid":"97796389","full_name":"chazkii/chromewhip","owner":"chazkii","description":"Scriptable Google Chrome™ as a HTTP service + asyncio driver","archived":false,"fork":false,"pushed_at":"2023-08-29T20:30:19.000Z","size":1973,"stargazers_count":118,"open_issues_count":17,"forks_count":16,"subscribers_count":9,"default_branch":"master","last_synced_at":"2024-10-30T03:44:26.856Z","etag":null,"topics":["asyncio-driver","chrome-process","devtools-protocol","google-chrome"],"latest_commit_sha":null,"homepage":"","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/chazkii.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE.txt","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null}},"created_at":"2017-07-20T06:01:51.000Z","updated_at":"2024-10-07T11:27:34.000Z","dependencies_parsed_at":"2024-01-07T10:00:17.102Z","dependency_job_id":null,"html_url":"https://github.com/chazkii/chromewhip","commit_stats":{"total_commits":83,"total_committers":3,"mean_commits":"27.666666666666668","dds":"0.048192771084337394","last_synced_commit":"7249f64f96df3c6ca0859a3da06ce7ddcebbfded"},"previous_names":["chuckus/chromewhip"],"tags_count":23,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/chazkii%2Fchromewhip","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/chazkii%2Fchromewhip/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/chazkii%2Fchromewhip/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/chazkii%2Fchromewhip/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/chazkii","download_url":"https://codeload.github.com/chazkii/chromewhip/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248288350,"owners_count":21078903,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["asyncio-driver","chrome-process","devtools-protocol","google-chrome"],"created_at":"2024-08-01T15:05:06.514Z","updated_at":"2025-04-10T20:08:48.857Z","avatar_url":"https://github.com/chazkii.png","language":"Python","funding_links":[],"categories":["Python"],"sub_categories":[],"readme":"# Chromewhip - Google Chrome™ as a web service\n\n[![Build Status](https://travis-ci.org/chuckus/chromewhip.svg?branch=master)](https://travis-ci.org/chuckus/chromewhip)\n[![Docker Hub Status](https://img.shields.io/docker/build/chuckus/chromewhip.svg)](https://img.shields.io/docker/build/chuckus/chromewhip.svg)\n[![PyPi version](https://img.shields.io/pypi/v/chromewhip.svg)](https://img.shields.io/pypi/v/chromewhip.svg)\n\n\n### Chrome browser as an HTTP service with an splash compatible HTTP API\n\nChromewhip is an easily deployable service that runs headless Chrome process \nwrapped with an HTTP API. Inspired by the [`splash`](https://github.com/scrapinghub/splash) \nproject, we aim to provide a drop-in replacement for the `splash` service by adhering to their documented API.\n\nIt is currently in early **alpha** and still being heavily developed. Please use the issue tracker \nto track the progress towards **beta**. For now, the required milestone can be summarised as \n**implementing the entire Splash API**.\n\n## How to use as a service\n\nOne can simply deploy as a Docker container and use the API that is served on port `8080`.\n\n```\ndocker run --init -it --rm --shm-size=1024m -p=127.0.0.1:8080:8080 --cap-add=SYS_ADMIN \\\n  chuckus/chromewhip\n```\n\nRefer to the HTTP API reference at the bottom of the README for what features are available.\n\n## How to use the low-level driver\n\nAs part of the Chromewhip service, a Python 3.6 asyncio compatible driver for Chrome devtools protocol was \ndeveloped and can be leveraged without having to run the HTTP server. The advantages of \nour devtools driver are:\n\n* Typed Python bindings for devtools protocol through templated generation - get autocomplete with your code editor.\n* Can bind events to concurrent commands, which is required for providing a robust HTTP service.\n\n### Prerequisites\n\nBefore executing the code below, please have the following:\n\n* Google Chrome Canary running with flag `--remote-debugging-port=9222`\n\n### Example driver code\n\n```python\nimport asyncio\nimport logging\n\nfrom chromewhip import Chrome\nfrom chromewhip.protocol import browser, page, dom\n\n# see logging from chromewhip\nlogging.basicConfig(level=logging.DEBUG)\n\nHOST = '127.0.0.1'\nPORT = 9222\n\nloop = asyncio.get_event_loop()\nc = Chrome(host=HOST, port=PORT)\n\nloop.run_until_complete(c.connect())\n\n    \n# use the startup tab or create a new one\ntab = c.tabs[0]\ntab = loop.run_until_complete(c.create_tab())\n\nloop.run_until_complete(tab.enable_page_events())\n\ndef sync_cmd(*args, **kwargs):\n    return loop.run_until_complete(tab.send_command(*args, **kwargs))\n    \n# send_command will return once the frameStoppedLoading event is received THAT matches\n# the frameId that it is in the returned command payload.\nresult = sync_cmd(page.Page.navigate(url='http://nzherald.co.nz'), \n                  await_on_event_type=page.FrameStoppedLoadingEvent)\n\n# send_command always returns a dict with keys `ack` and `event`\n# `ack` contains the payload on response of a command\n# `event` contains the payload of the awaited event if `await_on_event_type` is provided\nack = result['ack']['result']\nevent = result['event']\nassert ack['frameId'] == event.frameId\n\nsync_cmd(page.Page.setDeviceMetricsOverride(width=800,\n                                            height=600,\n                                            deviceScaleFactor=0.0,\n                                            mobile=False))\n\n\nresult = sync_cmd(dom.DOM.getDocument())\n\ndom_obj = result['ack']['result']['root']\n\n# Python types are determined by the `types` fields in the JSON reference for the\n# devtools protocol, and `send_command` will convert if possible.\nassert isinstance(dom_obj, dom.Node)\n\nprint(dom_obj.nodeId)\nprint(dom_obj.nodeName)\n\n# close the tab\nloop.run_until_complete(c.close_tab(tab))\n\n# or close the browser via Devtools API\ntab = c.tabs[0]\nsync_cmd(browser.Browser.close())\n```\n\n\n\n## Implemented HTTP API\n\n### /render.html\n\nQuery params:\n\n* url : string : required\n  * The url to render (required)\n\n* js : string : optional\n  Javascript profile name.\n  \n* js_source : string : optional\n   * JavaScript code to be executed in page context\n\n* viewport : string : optional\n  * View width and height (in pixels) of the browser viewport to render the web\n    page. Format is \"\u003cwidth\u003ex\u003cheight\u003e\", e.g. 800x600.  Default value is 1024x768.\n\n    'viewport' parameter is more important for PNG and JPEG rendering; it is supported for\n    all rendering endpoints because javascript code execution can depend on\n    viewport size. \n \n### /render.png\n\nQuery params (including render.html):\n\n* render_all : int : optional\n  * Possible values are `1` and `0`.  When `render_all=1`, extend the\n    viewport to include the whole webpage (possibly very tall) before rendering.\n   \n### Why not just use Selenium?\n* chromewhip uses the devtools protocol instead of the json wire protocol, where the devtools protocol has \ngreater flexibility, especially when it comes to subscribing to granular events from the browser.\n\n## Bug reports and requests\nPlease simply file one using the Github tracker\n\n## Contributing\nPlease :)\n\n### How to regenerate the Python protocol files\n\nIn `scripts`, you can run `regenerate_protocol.sh`, which downloads HEAD of offical devtools specs, regenerates, \nruns some sanity tests and creates a commit with the message of official devtools specs HEAD.\n\nFrom time to time, it will fail, due to desynchronization of the `chromewhip` patch with the json specs, or \nmistakes in the protocol.\n\nUnder `data`, there are `*_patch` files, which follow the [RFC 6902 JSON Patch notation](https://tools.ietf.org/html/rfc6902). \nYou will see that there are some checks to see whether particular items in arrays exist before patching. If you get \na `jsonpatch.JsonPatchTestFailed` exception, it's likely to desynchronization, so check the official spec and adjust \nthe patch json file.\n\n## Implementation\n\nDeveloped to run on Python 3.6, it leverages both `aiohttp` and `asyncio` for the implementation of the \nasynchronous HTTP server that wraps `chrome`.\n\n \n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fchazkii%2Fchromewhip","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fchazkii%2Fchromewhip","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fchazkii%2Fchromewhip/lists"}