<div align="center">
# GraiaX Playwright
_适用于 Graia Project 的 Playwright 管理器_
[![Code style: black](https://img.shields.io/badge/code%20style-black-000000.svg)](https://github.com/psf/black)
[![Imports: isort](https://img.shields.io/badge/%20imports-isort-%231674b1?style=flat&labelColor=ef8336)](https://pycqa.github.io/isort/)
[![License](https://img.shields.io/github/license/GraiaCommunity/graiax-playwright)](https://github.com/GraiaCommunity/graiax-playwright/blob/master/LICENSE)
[![pdm-managed](https://img.shields.io/badge/pdm-managed-blueviolet)](https://pdm.fming.dev)
[![PyPI](https://img.shields.io/pypi/v/graiax-playwright)](https://img.shields.io/pypi/v/graiax-playwright)
</div>
Graiax Playwright 使用 [launart](https://github.com/GraiaProject/launart) 作为启动管理器,
适用于 [Ariadne](https://github.com/GraiaProject/Ariadne) 及 [Avilla](https://github.com/GraiaProject/Avilla)。
通过 GraiaX Playwright 你可以轻松地在 Ariadne / Avilla 启动的时候同时启动一个
Playwright,并在其退出的时候自动关闭 Playwright。
> 需要注意的是,Playwright 将会在运行期间保持后台常驻,
> 但由于并未开启任何页面,其内存占用量不是非常大(但也是可观的)。
## 安装
`pdm add graiax-playwright` 或 `poetry add graiax-playwright`。
> 我们强烈建议使用包管理器或虚拟环境
## 开始使用
以下教程以配合 Launart 使用为例。
### 机器人入口文件
```python
from creart import create
from launart import Launart
from graia.ariadne.app import Ariadne
from graiax.playwright import PlaywrightService
launart = create(Launart)
launart.add_component(PlaywrightService("chromium")) # 默认值为 chromium
launart.add_component(PlaywrightService("chromium", user_data_dir="./browser_data")) # 与上一行二选一,该方式使用 Persistent Context
...
launart.launch_blocking()
```
### 配合 Graia Saya 使用
```python
from creart import create
from launart import Launart
from graia.ariadne.util.saya import listen
from graiax.playwright import PlaywrightService
@listen(...)
async def function(app: Ariadne):
launart = create(Launart)
pw_service = launart.get_component(PlaywrightService)
async with pw_service.page( # 此 API 启用了自动上下文管理
viewport={"width": 800, "height": 10},
device_scale_factor=1.5,
) as page:
await page.set_content("Hello World!")
img = await page.screenshot(type="jpeg", quality=80, full_page=True, scale="device")
...
```
### 高级用法之一
上面配合 Saya 使用的例子展示了创建一个页面的例子,但该页面默认与其他页面互相**隔离**(例如 cookie
等),假如我们需要一个与其他页面**隔离**的新页面,那么我们可以使用
`page(use_global_context=False)` 在创建页面时使用一个新的上下文,如下所示:
> [!NOTE]
> 该种用法中的新上下文,仍受到 Playwright 启动参数的影响
>
> 如果你传入了例如 `viewport` 之类的只有新创建上下文或者新页面才支持的参数时,则会忽略
> `use_global_context` 参数。此时若 `without_new_context`
> 为 `True`(默认行为),则将会直接使用浏览器实例创建新页面。
> 反之则会先创建新上下文再用新的上下文创建新页面,但是结束时新的页面和上下文都会被关闭。
>
> 更多信息详见:<https://playwright.dev/python/docs/browser-contexts>
```python
@listen(...)
async def function(app: Ariadne):
launart = create(Launart)
pw_service = launart.get_component(PlaywrightService)
async with pw_service.page(use_global_context=False) as page: # 此 API 启用了自动上下文管理
await page.set_content("Hello World!")
img = await page.screenshot(type="jpeg", quality=80, full_page=True, scale="device")
...
```
### 高级用法之二
上面配合 Saya 使用的例子展示了为**单个页面**设置 viewport 的功能,自 GraiaX Playwright `v0.3.1`
版本起,可以在创建 PlaywrightService 时为全局的 Browser Context 指定 viewport,然后在截图时使用全局
Browser Context 截图,如下所示:
**机器人入口文件:**
```python
launart.add_service(PlaywrightService("chromium"))
```
**Saya 模块中:**
```python
from graiax.playwright import PlaywrightService
@listen(...)
async def function(app: Ariadne):
launart = create(Launart)
pw_service = manager.get_component(PlaywrightService)
async with pw_service.context(...) as context: # 此 API 启用了自动上下文管理
page = context.new_page()
try:
await page.set_content("Hello World!")
img = await page.screenshot(type="jpeg", quality=80, full_page=True, scale='device')
finally:
page.stop()
...
```
### 高级用法之三
通过依赖注入来获取 `PlaywrightService`,前面的代码中获取 `PlaywrightService` 都需要通过 Launart
的 `get_component()` 方法,你也可以通过自定义一个 BCC 的 `Dispatcher` 来实现依赖注入。
编写一个 `Dispatcher`:
```python
from graia.broadcast.entities.dispatcher import BaseDispatcher
from graia.broadcast.interfaces.dispatcher import DispatcherInterface
class CustomDispatcher(BaseDispatcher):
@classmethod
async def catch(cls, interface: DispatcherInterface):
with contextlib.suppress(TypeError):
if generic_isinstance(interface.event, Service):
manager = Launart.current()
return manager.get_component(interface.annotation)
```
在启动 Launart 之前获取一个 BCC 实例并对其应用这个 `Dispatcher`:
```python
from creart import it
from graia.broadcast import Broadcast
bcc = it(Broadcast)
bcc.finale_dispatchers.append(RedbotDispatcher)
...
launart.launch_blocking() # 或者是 avilla.launch()
```
之后用起来就很简单了,你可以对比一下有什么不同:
```python
from graiax.playwright import PlaywrightService
@listen(...)
async def function(app: Ariadne, pw_service: PlaywrightService):
async with pw_service.page(...) as page:
...
```
## 许可证
本项目使用 [`MIT`](./LICENSE) 许可证进行许可。
Raw data
{
"_id": null,
"home_page": null,
"name": "graiax-playwright",
"maintainer": null,
"docs_url": null,
"requires_python": ">=3.10",
"maintainer_email": null,
"keywords": "graia, graiax, launart, playwright",
"author": null,
"author_email": "BlueGlassBlock <blueglassblock@outlook.com>, I Love Study <1450069615@qq.com>, Redlnn <w731347477@gmail.com>",
"download_url": "https://files.pythonhosted.org/packages/8d/ac/b66c8212699019a384c75857c6e7aee06c8cdeaf68c3e8bf96a9c7ffe9c6/graiax_playwright-0.4.4.tar.gz",
"platform": null,
"description": "<div align=\"center\">\n\n# GraiaX Playwright\n\n_\u9002\u7528\u4e8e Graia Project \u7684 Playwright \u7ba1\u7406\u5668_\n\n[![Code style: black](https://img.shields.io/badge/code%20style-black-000000.svg)](https://github.com/psf/black)\n[![Imports: isort](https://img.shields.io/badge/%20imports-isort-%231674b1?style=flat&labelColor=ef8336)](https://pycqa.github.io/isort/)\n[![License](https://img.shields.io/github/license/GraiaCommunity/graiax-playwright)](https://github.com/GraiaCommunity/graiax-playwright/blob/master/LICENSE)\n[![pdm-managed](https://img.shields.io/badge/pdm-managed-blueviolet)](https://pdm.fming.dev)\n[![PyPI](https://img.shields.io/pypi/v/graiax-playwright)](https://img.shields.io/pypi/v/graiax-playwright)\n\n</div>\n\nGraiax Playwright \u4f7f\u7528 [launart](https://github.com/GraiaProject/launart) \u4f5c\u4e3a\u542f\u52a8\u7ba1\u7406\u5668\uff0c\n\u9002\u7528\u4e8e [Ariadne](https://github.com/GraiaProject/Ariadne) \u53ca [Avilla](https://github.com/GraiaProject/Avilla)\u3002\n\n\u901a\u8fc7 GraiaX Playwright \u4f60\u53ef\u4ee5\u8f7b\u677e\u5730\u5728 Ariadne / Avilla \u542f\u52a8\u7684\u65f6\u5019\u540c\u65f6\u542f\u52a8\u4e00\u4e2a\nPlaywright\uff0c\u5e76\u5728\u5176\u9000\u51fa\u7684\u65f6\u5019\u81ea\u52a8\u5173\u95ed Playwright\u3002\n\n> \u9700\u8981\u6ce8\u610f\u7684\u662f\uff0cPlaywright \u5c06\u4f1a\u5728\u8fd0\u884c\u671f\u95f4\u4fdd\u6301\u540e\u53f0\u5e38\u9a7b\uff0c \n> \u4f46\u7531\u4e8e\u5e76\u672a\u5f00\u542f\u4efb\u4f55\u9875\u9762\uff0c\u5176\u5185\u5b58\u5360\u7528\u91cf\u4e0d\u662f\u975e\u5e38\u5927\uff08\u4f46\u4e5f\u662f\u53ef\u89c2\u7684\uff09\u3002\n\n## \u5b89\u88c5\n\n`pdm add graiax-playwright` \u6216 `poetry add graiax-playwright`\u3002\n\n> \u6211\u4eec\u5f3a\u70c8\u5efa\u8bae\u4f7f\u7528\u5305\u7ba1\u7406\u5668\u6216\u865a\u62df\u73af\u5883\n\n## \u5f00\u59cb\u4f7f\u7528\n\n\u4ee5\u4e0b\u6559\u7a0b\u4ee5\u914d\u5408 Launart \u4f7f\u7528\u4e3a\u4f8b\u3002\n\n### \u673a\u5668\u4eba\u5165\u53e3\u6587\u4ef6\n\n```python\nfrom creart import create\nfrom launart import Launart\nfrom graia.ariadne.app import Ariadne\nfrom graiax.playwright import PlaywrightService\n\nlaunart = create(Launart)\nlaunart.add_component(PlaywrightService(\"chromium\")) # \u9ed8\u8ba4\u503c\u4e3a chromium\nlaunart.add_component(PlaywrightService(\"chromium\"\uff0c user_data_dir=\"./browser_data\")) # \u4e0e\u4e0a\u4e00\u884c\u4e8c\u9009\u4e00\uff0c\u8be5\u65b9\u5f0f\u4f7f\u7528 Persistent Context\n...\n\nlaunart.launch_blocking()\n```\n\n### \u914d\u5408 Graia Saya \u4f7f\u7528\n\n```python\nfrom creart import create\nfrom launart import Launart\nfrom graia.ariadne.util.saya import listen\nfrom graiax.playwright import PlaywrightService\n\n\n@listen(...)\nasync def function(app: Ariadne):\n launart = create(Launart)\n pw_service = launart.get_component(PlaywrightService)\n\n async with pw_service.page( # \u6b64 API \u542f\u7528\u4e86\u81ea\u52a8\u4e0a\u4e0b\u6587\u7ba1\u7406\n viewport={\"width\": 800, \"height\": 10},\n device_scale_factor=1.5,\n ) as page:\n await page.set_content(\"Hello World!\")\n img = await page.screenshot(type=\"jpeg\", quality=80, full_page=True, scale=\"device\")\n ...\n```\n\n### \u9ad8\u7ea7\u7528\u6cd5\u4e4b\u4e00\n\n\u4e0a\u9762\u914d\u5408 Saya \u4f7f\u7528\u7684\u4f8b\u5b50\u5c55\u793a\u4e86\u521b\u5efa\u4e00\u4e2a\u9875\u9762\u7684\u4f8b\u5b50\uff0c\u4f46\u8be5\u9875\u9762\u9ed8\u8ba4\u4e0e\u5176\u4ed6\u9875\u9762\u4e92\u76f8**\u9694\u79bb**\uff08\u4f8b\u5982 cookie\n\u7b49\uff09\uff0c\u5047\u5982\u6211\u4eec\u9700\u8981\u4e00\u4e2a\u4e0e\u5176\u4ed6\u9875\u9762**\u9694\u79bb**\u7684\u65b0\u9875\u9762\uff0c\u90a3\u4e48\u6211\u4eec\u53ef\u4ee5\u4f7f\u7528\n`page(use_global_context=False)` \u5728\u521b\u5efa\u9875\u9762\u65f6\u4f7f\u7528\u4e00\u4e2a\u65b0\u7684\u4e0a\u4e0b\u6587\uff0c\u5982\u4e0b\u6240\u793a\uff1a\n\n> [!NOTE] \n> \u8be5\u79cd\u7528\u6cd5\u4e2d\u7684\u65b0\u4e0a\u4e0b\u6587\uff0c\u4ecd\u53d7\u5230 Playwright \u542f\u52a8\u53c2\u6570\u7684\u5f71\u54cd\n>\n> \u5982\u679c\u4f60\u4f20\u5165\u4e86\u4f8b\u5982 `viewport` \u4e4b\u7c7b\u7684\u53ea\u6709\u65b0\u521b\u5efa\u4e0a\u4e0b\u6587\u6216\u8005\u65b0\u9875\u9762\u624d\u652f\u6301\u7684\u53c2\u6570\u65f6\uff0c\u5219\u4f1a\u5ffd\u7565\n> `use_global_context` \u53c2\u6570\u3002\u6b64\u65f6\u82e5 `without_new_context`\n> \u4e3a `True`\uff08\u9ed8\u8ba4\u884c\u4e3a\uff09\uff0c\u5219\u5c06\u4f1a\u76f4\u63a5\u4f7f\u7528\u6d4f\u89c8\u5668\u5b9e\u4f8b\u521b\u5efa\u65b0\u9875\u9762\u3002\n> \u53cd\u4e4b\u5219\u4f1a\u5148\u521b\u5efa\u65b0\u4e0a\u4e0b\u6587\u518d\u7528\u65b0\u7684\u4e0a\u4e0b\u6587\u521b\u5efa\u65b0\u9875\u9762\uff0c\u4f46\u662f\u7ed3\u675f\u65f6\u65b0\u7684\u9875\u9762\u548c\u4e0a\u4e0b\u6587\u90fd\u4f1a\u88ab\u5173\u95ed\u3002\n>\n> \u66f4\u591a\u4fe1\u606f\u8be6\u89c1\uff1a<https://playwright.dev/python/docs/browser-contexts>\n\n```python\n@listen(...)\nasync def function(app: Ariadne):\n launart = create(Launart)\n pw_service = launart.get_component(PlaywrightService)\n async with pw_service.page(use_global_context=False) as page: # \u6b64 API \u542f\u7528\u4e86\u81ea\u52a8\u4e0a\u4e0b\u6587\u7ba1\u7406\n await page.set_content(\"Hello World!\")\n img = await page.screenshot(type=\"jpeg\", quality=80, full_page=True, scale=\"device\")\n ...\n```\n\n### \u9ad8\u7ea7\u7528\u6cd5\u4e4b\u4e8c\n\n\u4e0a\u9762\u914d\u5408 Saya \u4f7f\u7528\u7684\u4f8b\u5b50\u5c55\u793a\u4e86\u4e3a**\u5355\u4e2a\u9875\u9762**\u8bbe\u7f6e viewport \u7684\u529f\u80fd\uff0c\u81ea GraiaX Playwright `v0.3.1`\n\u7248\u672c\u8d77\uff0c\u53ef\u4ee5\u5728\u521b\u5efa PlaywrightService \u65f6\u4e3a\u5168\u5c40\u7684 Browser Context \u6307\u5b9a viewport\uff0c\u7136\u540e\u5728\u622a\u56fe\u65f6\u4f7f\u7528\u5168\u5c40\nBrowser Context \u622a\u56fe\uff0c\u5982\u4e0b\u6240\u793a\uff1a\n\n**\u673a\u5668\u4eba\u5165\u53e3\u6587\u4ef6\uff1a**\n\n```python\nlaunart.add_service(PlaywrightService(\"chromium\"))\n```\n\n**Saya \u6a21\u5757\u4e2d\uff1a**\n\n```python\nfrom graiax.playwright import PlaywrightService\n\n\n@listen(...)\nasync def function(app: Ariadne):\n launart = create(Launart)\n pw_service = manager.get_component(PlaywrightService)\n async with pw_service.context(...) as context: # \u6b64 API \u542f\u7528\u4e86\u81ea\u52a8\u4e0a\u4e0b\u6587\u7ba1\u7406\n page = context.new_page()\n try:\n await page.set_content(\"Hello World!\")\n img = await page.screenshot(type=\"jpeg\", quality=80, full_page=True, scale='device')\n finally:\n page.stop()\n ...\n```\n\n### \u9ad8\u7ea7\u7528\u6cd5\u4e4b\u4e09\n\n\u901a\u8fc7\u4f9d\u8d56\u6ce8\u5165\u6765\u83b7\u53d6 `PlaywrightService`\uff0c\u524d\u9762\u7684\u4ee3\u7801\u4e2d\u83b7\u53d6 `PlaywrightService` \u90fd\u9700\u8981\u901a\u8fc7 Launart\n\u7684 `get_component()` \u65b9\u6cd5\uff0c\u4f60\u4e5f\u53ef\u4ee5\u901a\u8fc7\u81ea\u5b9a\u4e49\u4e00\u4e2a BCC \u7684 `Dispatcher` \u6765\u5b9e\u73b0\u4f9d\u8d56\u6ce8\u5165\u3002\n\n\u7f16\u5199\u4e00\u4e2a `Dispatcher`\uff1a\n\n```python\nfrom graia.broadcast.entities.dispatcher import BaseDispatcher\nfrom graia.broadcast.interfaces.dispatcher import DispatcherInterface\n\nclass CustomDispatcher(BaseDispatcher):\n @classmethod\n async def catch(cls, interface: DispatcherInterface):\n with contextlib.suppress(TypeError):\n if generic_isinstance(interface.event, Service):\n manager = Launart.current()\n return manager.get_component(interface.annotation)\n```\n\n\u5728\u542f\u52a8 Launart \u4e4b\u524d\u83b7\u53d6\u4e00\u4e2a BCC \u5b9e\u4f8b\u5e76\u5bf9\u5176\u5e94\u7528\u8fd9\u4e2a `Dispatcher`\uff1a\n\n```python\nfrom creart import it\nfrom graia.broadcast import Broadcast\n\nbcc = it(Broadcast)\nbcc.finale_dispatchers.append(RedbotDispatcher)\n\n...\n\nlaunart.launch_blocking() # \u6216\u8005\u662f avilla.launch()\n```\n\n\u4e4b\u540e\u7528\u8d77\u6765\u5c31\u5f88\u7b80\u5355\u4e86\uff0c\u4f60\u53ef\u4ee5\u5bf9\u6bd4\u4e00\u4e0b\u6709\u4ec0\u4e48\u4e0d\u540c\uff1a\n\n```python\nfrom graiax.playwright import PlaywrightService\n\n@listen(...)\nasync def function(app: Ariadne, pw_service: PlaywrightService):\n async with pw_service.page(...) as page:\n ...\n```\n\n## \u8bb8\u53ef\u8bc1\n\n\u672c\u9879\u76ee\u4f7f\u7528 [`MIT`](./LICENSE) \u8bb8\u53ef\u8bc1\u8fdb\u884c\u8bb8\u53ef\u3002\n",
"bugtrack_url": null,
"license": "MIT",
"summary": "\u9002\u7528\u4e8e Graia \u7684 Playwright \u7ba1\u7406\u5668",
"version": "0.4.4",
"project_urls": {
"Repository": "https://github.com/GraiaCommunity/graiax-playwright"
},
"split_keywords": [
"graia",
" graiax",
" launart",
" playwright"
],
"urls": [
{
"comment_text": "",
"digests": {
"blake2b_256": "66fa9c82bce498afe925c079eba500ad64b35af583cda87f683cb9ee4f69b02d",
"md5": "34e848072efaa7ae77ea1235aed4fa62",
"sha256": "79edd7933a541549c01675ab9939f22063be9b590c1529efedf1a18915fc07ef"
},
"downloads": -1,
"filename": "graiax_playwright-0.4.4-py3-none-any.whl",
"has_sig": false,
"md5_digest": "34e848072efaa7ae77ea1235aed4fa62",
"packagetype": "bdist_wheel",
"python_version": "py3",
"requires_python": ">=3.10",
"size": 16140,
"upload_time": "2024-08-18T14:30:26",
"upload_time_iso_8601": "2024-08-18T14:30:26.097080Z",
"url": "https://files.pythonhosted.org/packages/66/fa/9c82bce498afe925c079eba500ad64b35af583cda87f683cb9ee4f69b02d/graiax_playwright-0.4.4-py3-none-any.whl",
"yanked": false,
"yanked_reason": null
},
{
"comment_text": "",
"digests": {
"blake2b_256": "8dacb66c8212699019a384c75857c6e7aee06c8cdeaf68c3e8bf96a9c7ffe9c6",
"md5": "cc43d5af282fe3d1ac085ccf97a51976",
"sha256": "f3fefe4b566ae880a49e7fa4584865279d03b6d93cfccfdf28efca60b4d62044"
},
"downloads": -1,
"filename": "graiax_playwright-0.4.4.tar.gz",
"has_sig": false,
"md5_digest": "cc43d5af282fe3d1ac085ccf97a51976",
"packagetype": "sdist",
"python_version": "source",
"requires_python": ">=3.10",
"size": 14495,
"upload_time": "2024-08-18T14:30:27",
"upload_time_iso_8601": "2024-08-18T14:30:27.440184Z",
"url": "https://files.pythonhosted.org/packages/8d/ac/b66c8212699019a384c75857c6e7aee06c8cdeaf68c3e8bf96a9c7ffe9c6/graiax_playwright-0.4.4.tar.gz",
"yanked": false,
"yanked_reason": null
}
],
"upload_time": "2024-08-18 14:30:27",
"github": true,
"gitlab": false,
"bitbucket": false,
"codeberg": false,
"github_user": "GraiaCommunity",
"github_project": "graiax-playwright",
"travis_ci": false,
"coveralls": false,
"github_actions": true,
"lcname": "graiax-playwright"
}