page.screenshot
返回: bytes 或 str(文件路径)page.screenshot(path=None, as_bytes=False)页面截图。传 path 保存文件,as_bytes=True 返回 PNG 二进制数据。
参数说明
| 参数 | 说明 |
|---|---|
| path | 可选,保存路径(如 'page.png')。 |
| as_bytes | True 返回 bytes / False 保存文件。 |
常见坑
- 默认截取可视区域,不含滚动外内容。
相关示例
截图功能支持页面级和元素级截图,可保存为文件或返回 bytes 数据。
page.screenshot(path=None, as_bytes=False)页面截图。传 path 保存文件,as_bytes=True 返回 PNG 二进制数据。
| 参数 | 说明 |
|---|---|
| path | 可选,保存路径(如 'page.png')。 |
| as_bytes | True 返回 bytes / False 保存文件。 |
ele.screenshot(path=None, as_bytes=False)元素级截图,只截取指定元素区域。
| 参数 | 说明 |
|---|---|
| path | 可选,保存路径。 |
| as_bytes | True 返回 bytes。 |
from ruyipage import launch
page = launch()
try:
page.get("https://example.com")
# 页面截图保存到文件
page.screenshot(path="page.png")
# 页面截图返回 bytes
img_bytes = page.screenshot(as_bytes=True)
print(f"截图大小: {len(img_bytes)} bytes")
# 元素截图
h1 = page.ele("tag:h1")
h1.screenshot(path="title.png")
finally:
page.quit()覆盖最常用的页面与元素截图输出能力。
源码文件:app/content/ruyipage_examples/06_screenshot.py · 仓库:06_screenshot.py
# =============================
# RuyiPage 示例注释版
# 标题: 截图功能:整页、元素、base64、bytes
# 说明: 覆盖最常用的页面与元素截图输出能力。
# 你会学到:
# 1. 整页截图并保存到文件
# 2. 对单个元素或区域截图
# 3. 滚动到目标后截图
# 4. 获取截图的 base64 和 bytes 数据
# 相关 API: page.screenshot, ele.screenshot, page.scroll.to_see, page.scroll.to_bottom
# =============================
# -*- coding: utf-8 -*-
"""
示例6: 截图功能
测试功能:
- 整页截图
- 元素截图
- 保存为文件
- 获取base64
- 获取bytes
"""
import os
import sys
import io
# 设置控制台输出编码为UTF-8(Windows兼容)
if sys.platform == 'win32':
sys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding='utf-8')
sys.stderr = io.TextIOWrapper(sys.stderr.buffer, encoding='utf-8')
sys.path.insert(0, os.path.join(os.path.dirname(__file__), '..'))
from ruyipage import FirefoxPage, FirefoxOptions
def test_screenshot():
"""测试截图功能"""
print("=" * 60)
print("测试6: 截图功能")
print("=" * 60)
opts = FirefoxOptions()
opts.headless(False)
page = FirefoxPage(opts)
try:
# 加载测试页面
test_page = os.path.join(os.path.dirname(__file__), 'test_pages', 'test_page.html')
test_url = 'file:///' + os.path.abspath(test_page).replace('\\', '/')
page.get(test_url)
page.wait(1)
# 创建输出目录
output_dir = os.path.join(os.path.dirname(__file__), 'output', 'screenshots')
os.makedirs(output_dir, exist_ok=True)
# 1. 整页截图
print("\n1. 整页截图:")
full_path = os.path.join(output_dir, 'full_page.png')
page.screenshot(full_path)
print(f" ✓ 整页截图已保存: {full_path}")
# 2. 元素截图
print("\n2. 元素截图:")
title = page.ele('#main-title')
title_path = os.path.join(output_dir, 'title_element.png')
title.screenshot(title_path)
print(f" ✓ 标题元素截图已保存: {title_path}")
# 3. 表单区域截图
print("\n3. 表单区域截图:")
form_section = page.ele('#form-section')
form_path = os.path.join(output_dir, 'form_section.png')
form_section.screenshot(form_path)
print(f" ✓ 表单区域截图已保存: {form_path}")
# 4. 按钮截图
print("\n4. 按钮截图:")
btn = page.ele('#click-btn')
# 先滚动到按钮位置确保可见
page.scroll.to_see(btn)
page.wait(0.5)
btn_path = os.path.join(output_dir, 'button.png')
try:
btn.screenshot(btn_path)
print(f" ✓ 按钮截图已保存: {btn_path}")
except Exception as e:
print(f" ⚠ 按钮截图跳过(元素尺寸问题): {str(e)[:50]}")
# 5. 获取截图的base64
print("\n5. 获取截图base64:")
base64_data = page.screenshot(as_base64=True)
print(f" ✓ Base64数据长度: {len(base64_data)} 字符")
# 6. 获取截图的bytes
print("\n6. 获取截图bytes:")
bytes_data = page.screenshot(as_bytes=True)
print(f" ✓ Bytes数据长度: {len(bytes_data)} 字节")
# 7. 元素base64截图
print("\n7. 元素base64截图:")
try:
# 使用表单区域元素,它更稳定
form_elem = page.ele('#form-section')
elem_base64 = form_elem.screenshot(as_base64=True)
print(f" ✓ 元素Base64数据长度: {len(elem_base64)} 字符")
except Exception as e:
print(f" ⚠ 元素base64截图跳过(元素尺寸问题): {str(e)[:50]}")
# 8. 滚动后截图
print("\n8. 滚动后截图:")
page.scroll.to_bottom()
page.wait(0.5)
bottom_path = os.path.join(output_dir, 'page_bottom.png')
page.screenshot(bottom_path)
print(f" ✓ 页面底部截图已保存: {bottom_path}")
# 9. 表格截图
print("\n9. 表格截图:")
table = page.ele('#data-table')
table_path = os.path.join(output_dir, 'table.png')
try:
page.scroll.to_see(table)
page.wait(0.5)
table.screenshot(table_path)
print(f" ✓ 表格截图已保存: {table_path}")
except Exception as e:
print(f" ⚠ 表格截图跳过(元素尺寸问题): {str(e)[:50]}")
print("\n" + "=" * 60)
print("✓ 所有截图测试通过!")
print(f"截图保存在: {output_dir}")
print("=" * 60)
except Exception as e:
print(f"\n✗ 测试失败: {e}")
import traceback
traceback.print_exc()
finally:
page.wait(2)
page.quit()
if __name__ == '__main__':
test_screenshot()
把一些散落但重要的能力集中演示,适合做协议能力查漏补缺。
源码文件:app/content/ruyipage_examples/34_remaining_commands.py · 仓库:34_remaining_commands.py
#!/usr/bin/env python
# =============================
# RuyiPage 示例注释版
# 标题: 剩余命令覆盖:截图、历史、继续响应、mock、fail、认证、动作释放
# 说明: 把一些散落但重要的能力集中演示,适合做协议能力查漏补缺。
# 你会学到:
# 1. 截图与保存文件
# 2. 验证历史遍历
# 3. 继续响应和 mock 响应
# 4. 请求失败与认证补充
# 5. 释放动作链状态
# 相关 API: page.screenshot, page.back, page.forward, page.intercept.start_responses, req.continue_response, req.mock, req.fail, req.continue_with_auth
# =============================
# -*- coding: utf-8 -*-
"""示例34: Remaining Commands(严格结果版)"""
import io
import os
import sys
from typing import Dict, List
if sys.platform == "win32":
sys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding="utf-8")
sys.stderr = io.TextIOWrapper(sys.stderr.buffer, encoding="utf-8")
from ruyipage import FirefoxPage, InterceptedRequest
from ruyipage._functions.tools import find_free_port
from test_server import TestServer
def add_result(
results: List[Dict[str, str]], item: str, status: str, note: str
) -> None:
results.append({"item": item, "status": status, "note": note})
def print_results(results: List[Dict[str, str]]) -> None:
print("\n| 项目 | 状态 | 说明 |")
print("| --- | --- | --- |")
for row in results:
print(f"| {row['item']} | {row['status']} | {row['note']} |")
def main() -> None:
print("=" * 70)
print("测试 34: Remaining Commands")
print("=" * 70)
page = FirefoxPage()
server = None
results: List[Dict[str, str]] = []
screenshot_path = os.path.join(os.path.dirname(__file__), "test_screenshot.png")
try:
server = TestServer(port=find_free_port(9430, 9530)).start()
base_url = server.get_url("")[:-1]
# 1. captureScreenshot
page.get(base_url + "/nav/basic")
add_result(results, "页面加载", "成功", f"服务地址: {base_url}")
data_bytes = page.screenshot(as_bytes=True)
if data_bytes and len(data_bytes) > 100:
add_result(
results,
"browsingContext.captureScreenshot viewport",
"成功",
f"截图字节数: {len(data_bytes)}",
)
else:
add_result(
results,
"browsingContext.captureScreenshot viewport",
"失败",
"截图数据过短",
)
saved_path = page.screenshot(path=screenshot_path)
if saved_path and os.path.exists(saved_path):
add_result(results, "screenshot save file", "成功", saved_path)
else:
add_result(results, "screenshot save file", "失败", "未保存截图文件")
# 2. traverseHistory
page.get(base_url + "/nav/basic?a=1")
page.get(base_url + "/nav/basic?a=2")
page.get(base_url + "/nav/basic?a=3")
page.back()
back_url = page.url
page.back()
back2_url = page.url
page.forward()
forward_url = page.url
if (
back_url.endswith("?a=2")
and back2_url.endswith("?a=1")
and forward_url.endswith("?a=2")
):
add_result(
results,
"browsingContext.traverseHistory",
"成功",
f"back={back_url}, back2={back2_url}, forward={forward_url}",
)
else:
add_result(
results,
"browsingContext.traverseHistory",
"失败",
f"back={back_url}, back2={back2_url}, forward={forward_url}",
)
# 3. network.continueResponse
page.intercept.start_responses(
url_patterns=[{"type": "string", "pattern": base_url + "/api/data"}]
)
page.run_js(
f"fetch('{base_url}/api/data').catch(()=>null); return true;", as_expr=False
)
resp_req: InterceptedRequest | None = page.intercept.wait(timeout=5)
if resp_req:
resp_req.continue_response()
add_result(results, "network.continueResponse", "成功", resp_req.url)
else:
add_result(
results,
"network.continueResponse",
"跳过",
"未稳定捕获到 responseStarted 拦截",
)
page.intercept.stop()
# 4. network.provideResponse
page.intercept.start_requests(
url_patterns=[{"type": "string", "pattern": base_url + "/api/mock-source"}]
)
page.run_js(
f"fetch('{base_url}/api/mock-source').catch(()=>null); return true;",
as_expr=False,
)
mock_req: InterceptedRequest | None = page.intercept.wait(timeout=5)
if mock_req:
mock_req.mock(body='{"status":"mocked"}', status_code=200)
add_result(results, "network.provideResponse", "成功", mock_req.url)
else:
add_result(
results,
"network.provideResponse",
"跳过",
"未稳定捕获到 beforeRequestSent 拦截",
)
page.intercept.stop()
# 5. network.failRequest
page.intercept.start_requests(
url_patterns=[{"type": "string", "pattern": base_url + "/api/slow"}]
)
page.run_js(
f"fetch('{base_url}/api/slow').catch(()=>null); return true;", as_expr=False
)
fail_req: InterceptedRequest | None = page.intercept.wait(timeout=5)
if fail_req:
fail_req.fail()
add_result(results, "network.failRequest", "成功", fail_req.url)
else:
add_result(
results,
"network.failRequest",
"跳过",
"未稳定捕获到 beforeRequestSent 拦截",
)
page.intercept.stop()
# 6. network.continueWithAuth
page.events.start(["network.authRequired"], contexts=[page.tab_id])
page.intercept.start(
url_patterns=[{"type": "string", "pattern": base_url + "/api/auth"}],
phases=["authRequired"],
)
try:
page.get(base_url + "/api/auth")
except Exception:
pass
auth_req: InterceptedRequest | None = page.intercept.wait(timeout=5)
auth_event = page.events.wait("network.authRequired", timeout=5)
if auth_req and auth_event:
auth_req.continue_with_auth(
action="provideCredentials",
username="user",
password="pass",
)
add_result(results, "network.continueWithAuth", "成功", auth_req.url)
else:
add_result(
results,
"network.continueWithAuth",
"跳过",
"当前环境未稳定观察到 authRequired",
)
page.intercept.stop()
page.events.stop()
# 7. input.performActions / releaseActions
try:
page.quit()
except Exception:
pass
page = FirefoxPage()
action_page = """
<!DOCTYPE html>
<html>
<head><meta charset='utf-8'><title>Actions Test</title></head>
<body>
<input id='input-box' autofocus />
<button id='btn' onclick="window.btnClicked = true">Click Me</button>
<script>
window.btnClicked = false;
window.lastKey = '';
document.getElementById('input-box').addEventListener('keydown', function(e) {
window.lastKey = e.key;
});
</script>
</body>
</html>
"""
page.get("data:text/html;charset=utf-8," + action_page)
page.actions.move_to(page.ele("#input-box")).click().press("a").perform()
last_key = page.run_js("return window.lastKey")
page.actions.move_to(page.ele("#btn")).click().perform()
btn_clicked = page.run_js("return window.btnClicked")
page.actions.release()
if last_key == "a":
add_result(
results, "input.performActions keyboard", "成功", f"lastKey={last_key}"
)
else:
add_result(
results, "input.performActions keyboard", "失败", f"lastKey={last_key}"
)
if btn_clicked is True:
add_result(
results, "input.performActions pointer", "成功", "按钮点击事件已触发"
)
else:
add_result(
results, "input.performActions pointer", "失败", "按钮点击事件未触发"
)
add_result(results, "input.releaseActions", "成功", "动作状态已释放")
print_results(results)
except Exception as e:
add_result(results, "示例执行", "失败", str(e)[:120])
print_results(results)
raise
finally:
try:
page.intercept.stop()
except Exception:
pass
try:
page.events.stop()
except Exception:
pass
try:
if os.path.exists(screenshot_path):
os.remove(screenshot_path)
except Exception:
pass
try:
if server is not None:
server.stop()
except Exception:
pass
try:
page.quit()
except Exception:
pass
if __name__ == "__main__":
main()