koishijs / koishi-plugin-puppeteer Goto Github PK
View Code? Open in Web Editor NEWBrowser service | 浏览器服务
Home Page: https://puppeteer.koishi.chat
License: MIT License
Browser service | 浏览器服务
Home Page: https://puppeteer.koishi.chat
License: MIT License
Bonjour, I am the author of the FFXIV plugin koishi-plugin-ffxiv-macrodict
, which provides a convenient way to read the description of the ffxiv's game macros (text commands).
Recently I tried to switch the render function from page.SetContent()
and page.screenshot()
to use the <html>
message element provided by puppeteer
plugin. But now it looks like the font-family
-es CSS that I set for various languages are not functional, which makes the resulting character weird, especially in CJK (Chinese, Japanese and Korean characters).
So I guess that is because the html
message not accepting the lang
attributes?
Here's how I utilize the puppeteer plugin for the image generation.
<html lang=lang>
<head>
<style>{css`
/* ... */
[lang="zh"] body {
font-family: 'Microsoft Yahei UI', SimHei, Consolas, 'Courier New', monospace;
}
[lang="ja"] body {
font-family: 'Yu Gothic', 'Yu Gothic UI', 'Meiryo UI', 'Meiryo', 'MS Gothic', Consolas, 'Courier New', monospace;
}
[lang="ko"] body {
font-family: 'Malgun Gothic', 'Apple SD Gothic Neo', 'Nanum Gothic', Consolas, 'Courier New', monospace;
}
`}
</head>
{ /* ... */ }
</html>
在使用 jsx
写 svg
内部的 text
标签会报错
<svg viewBox="0 0 100 100">
<circle
cx="50"
cy="50"
r="50"
fill="none"
stroke="#ccc"
strokeWidth="10"
/>
<circle
cx="50"
cy="50"
r="50"
fill="none"
stroke="#f00"
strokeWidth="10"
strokeDasharray={2 * Math.PI * 50}
strokeDashoffset={2 * Math.PI * 50 * (1 - 0.8)}
transform="rotate(-90, 50, 50)"
/>
<text
x="50"
y="50"
textAnchor="middle"
dominantBaseline="middle"
fontSize="20"
fill="#000"
>
{`${Math.floor(0.8 * 100)}%`}
</text>
</svg>
内置 wait
方法无法完全等待字体每次加载
jsx
和 pptr
打开 html
的方法均无法稳定等待加载
这里 似乎只能加载图片 http
协议的 url
,加载本地图片 file:////root/ks/data/skk.jpg
时会报错
2023-11-20 21:12:05 [W] command help-pro
AggregateError
at request (/root/ks/node_modules/cordis-axios/lib/index.js:153:21)
at http.axios (/root/ks/node_modules/cordis-axios/lib/index.js:182:16)
at _Quester.file (/root/ks/node_modules/cordis-axios/lib/index.js:256:42)
at _Quester.file (/root/ks/node_modules/@satorijs/satori/lib/index.js:55:18)
at ImageElement.initialize (/root/ks/node_modules/koishi-plugin-puppeteer/lib/canvas.js:127:46)
at Proxy.loadImage (/root/ks/node_modules/koishi-plugin-puppeteer/lib/canvas.js:180:21)
at initTheme (/root/ks/node_modules/koishi-plugin-help-pro/lib/render_canvas.js:191:34)
at process.processTicksAndRejections (node:internal/process/task_queues:95:5)
at async render_categroy (/root/ks/node_modules/koishi-plugin-help-pro/lib/render_canvas.js:53:20)
at async renderCategroy (/root/ks/node_modules/koishi-plugin-help-pro/lib/index.js:454:15)
at async _Command.<anonymous> (/root/ks/node_modules/koishi-plugin-help-pro/lib/index.js:160:28)
at async Array.<anonymous> (/root/ks/node_modules/@koishijs/core/lib/index.cjs:1331:14)
at async _Command.execute (/root/ks/node_modules/@koishijs/core/lib/index.cjs:1346:22)
at async /root/ks/node_modules/@koishijs/core/lib/index.cjs:2174:22
at async _Session.withScope (/root/ks/node_modules/@koishijs/core/lib/index.cjs:2076:22)
at async next (/root/ks/node_modules/@koishijs/core/lib/index.cjs:1053:16)
at async next (/root/ks/node_modules/@koishijs/core/lib/index.cjs:1053:16)
at async _Processor._handleMessage (/root/ks/node_modules/@koishijs/core/lib/index.cjs:1064:22)
有些人可能会使用shot功能去访问一些可能封号的网站
可否添加个调用百度智能云的图片审查功能呢
https://ai.baidu.com/solution/censoring?hmsr=aibanner&hmpl=censoring
The chrome
browser that we are using can be installed by the snap
, which is popular in these years and is the default package manager on Ubuntu Desktop. But the namespace mechanisms limits many allowances that causes the failure invoking from the puppeteer
plugin of Koishi.
Therefore, we should clarify the disadvantages of using snap
to install the chrome
with the puppeteer
plugin and suggest some alternatives methods.
Since
puppeteer
supportsconnect
to an existing browser instance rather than launching a new one, also it would ease the configuration for users. It would be great if the puppeteer plugin supported this feature as well.
由于 puppeteer
支持 connect
到一个现有的浏览器实例,而不是启动一个新的,而且这样会方便用户配置。如果 puppeteer 插件也能支持这个功能会很好。
- Add a new config to choose whether to use
Launch
orConnect
for handling a browser instance.- When the user selects
Connect
, show a text input box for entering the existing browser URI.- And then the plugin would connect to it when it started to provide the service.
Launch
或 Connect
。Connect
,显示一个文本输入框使其输入现有的浏览器的 URI。目前 pptr 是没有跟随 Koishi 全局代理的设置:
koishi-plugin-puppeteer/packages/core/src/index.ts
Lines 58 to 61 in a93fcda
希望尊重 Koishi 全局代理设置(
想的一个笨笨方法:
//add proxyAgent
if(ctx.root.config.request.proxyAgent){
this.config.args.push([`--proxy-server=${ctx.root.config.request.proxyAgent}`])
}
this.browser = await puppeteer.launch({
...this.config,
executablePath,
})
安装 github 插件告诉我pptr已安装
紧接着去搜索 pptr 告诉我未安装 点进去又是已安装
插件配置也找不到 pptr
但是通过 yarn 可以发现其实是安装了 pptr 的
删去 node_modules
加以多次重启后解决
显示 pptr 已安装
System:
OS: Linux 5.4 Alpine Linux
CPU: (8) x64 Intel(R) Xeon(R) Gold 6133 CPU @ 2.50GHz
GPU: Tesla V100-SXM2-32GB
RAM: 22286MiB / 39359MiB
Binaries:
Node: 18.13.0
Yarn: 1.22.19
Koishi:
Core: 4.11.2
Console: 5.1.10
此问题为尝试复现 koishijs/koishi-plugin-github#22 时出现的
可以顺便看看吗
edit: 转移 log
插件在渲染 html 内置组件时,如果使用诸如 file:///home/ubuntu/imgs/1.png
这样的本地资源,可以正常加载。但如果在调用 ctx.puppeteer.render
时使用本地资源,则会无法加载。
Puppeteers 打开标签时默认的 URL 为 about:blank
,此时 Chrome 无法加载本地资源(Not allowed to load local resource
)。但渲染内置组件之前,插件会先做以下操作:
await page.goto('file:///' + resolve(__dirname, '../index.html'))
这样标签页的 URL 变成了本地页面,因此之后可以正常加载本地资源了。但是,ctx.puppeteer.render
在渲染前并不会做类似的操作,所以页面并不能正常显示。
能否在 ctx.puppeteer.render
中也加上这个操作?如果不行,这么做会导致什么其他的问题吗?
比如插件商店里面的下棋的插件chess 按理说棋盘是以图片的形式发出来的,但实际上发的字符
直接在插件里面安装puppeteer,并不做任何配置直接启用插件
下棋的插件chess 应该是正确的发送图片(在使用v3koishi时成功过,但后来也忘记怎么操作了,但确实要自己手动的安装chrome的一个模块,
或许可以在写这个插件的是否自动检测,没有的进行安装一个?
在自定义那边,设置了指定文件也失败了
https://commondatastorage.googleapis.com/chromium-browser-snapshots/Linux_x64/982053/chrome-linux.zip
2022-04-27 13:02:14 [W] ndefined;1mapp Error: Failed to launch the browser process!
[0427/130214.085519:FATAL:zygote_host_impl_linux.cc(117)] No usable sandbox! Update your kernel or see https://chromium.googlesource.com/chromium/src/+/main/docs/linux/suid_sandbox_development.md for more information on developing with the SUID sandbox. If you want to live dangerously and need an immediate workaround, you can try using --no-sandbox.
#0 0x5564dbb87b89 base::debug::CollectStackTrace()
koishijs/koishi#1 0x5564dbaec433 base::debug::StackTrace::StackTrace()
koishijs/koishi#2 0x5564dbaff330 logging::LogMessage::~LogMessage()
koishijs/koishi#3 0x5564d9ae499b content::ZygoteHostImpl::Init()
koishijs/koishi#4 0x5564db695372 content::ContentMainRunnerImpl::Initialize()
koishijs/koishi#5 0x5564db693439 content::RunContentProcess()
koishijs/koishi#6 0x5564db69358e content::ContentMain()
koishijs/koishi#7 0x5564db6eed7a headless::(anonymous namespace)::RunContentMain()
koishijs/koishi#8 0x5564db6eea85 headless::HeadlessShellMain()
koishijs/koishi#9 0x5564d81523e8 ChromeMain
koishijs/koishi#10 0x7ff612bb8555 __libc_start_main
koishijs/koishi#11 0x5564d815222a _start
TROUBLESHOOTING: https://github.com/puppeteer/puppeteer/blob/main/docs/troubleshooting.md
at onClose (/koishi地址/node_modules/puppeteer-core/lib/cjs/puppeteer/node/BrowserRunner.js:241:20)
at Interface.<anonymous> (/koishi地址/node_modules/puppeteer-core/lib/cjs/puppeteer/node/BrowserRunner.js:231:68)
at Interface.emit (events.js:412:35)
at Interface.close (readline.js:530:8)
at Socket.onend (readline.js:254:10)
at Socket.emit (events.js:412:35)
at endReadableNT (internal/streams/readable.js:1334:12)
at processTicksAndRejections (internal/process/task_queues.js:82:21)
2022-04-27 12:51:21 [W] ndefined;1mapp TimeoutError: Timed out after 30000 ms while trying to connect to the browser! Only Chrome at revision r982053 is guaranteed to work.
at Timeout.onTimeout (/koishi地址/node_modules/puppeteer-core/lib/cjs/puppeteer/node/BrowserRunner.js:252:20)
at listOnTimeout (internal/timers.js:557:17)
at processTimers (internal/timers.js:500:7)
No response
新增一个「launch」函数,用于启动一个独立的浏览器
返回值可为Promise
我有个对于「九天」平台的工具箱,需要使用pptr进行登录后拦截数据,但是如果两个人同时使用命令就会导致覆盖cookie
同浏览器不同page隔离cookie
或者不同浏览器之间隔离cookie
如果有别的办法做到请告诉我
日志输出
Puppeteer old Headless deprecation warning:
In the near feature `headless: true` will default to the new Headless mode
for Chrome instead of the old Headless implementation. For more
information, please see https://developer.chrome.com/articles/new-headless/.
Consider opting in early by passing `headless: "new"` to `puppeteer.launch()`
If you encounter any bugs, please report them to https://github.com/puppeteer/puppeteer/issues/new/choose.
现在的配置项只能是一个布尔值
headless: Schema.boolean()
koishi-plugin-puppeteer
index.ts
中写入如下代码import { Context, Schema } from "koishi";
import {} from "koishi-plugin-puppeteer";
export const name = "test-plugin";
export const inject = ["canvas"];
export interface Config {}
export const Config: Schema<Config> = Schema.object({});
export async function apply(ctx: Context) {
const c = (await ctx.canvas.createCanvas(1, 1)).getContext("2d");
console.log(c.measureText("test text"));
}
因为 Puppeteer 插件提供了 canvas
服务,因此可以正常编译。
$ yarn run build test-plugin
external/test-plugin/src/index.ts:13:24 - error TS2339: Property 'canvas' does not exist on type 'Context'.
13 const c = (await ctx.canvas.createCanvas(1, 1)).getContext("2d");
~~~~~~
TSFILE: /home/l/workspace/koishi-app/external/test-plugin/tsconfig.tsbuildinfo
Found 1 error.
packages/core/src/index.ts
declare module 'koishi' {
interface Context {
puppeteer: Puppeteer;
canvas: Canvas;
}
}
已解决
使用 shot https://www.baidu.com/s?ie=utf-8&wd=百度
截图会截图百度首页
使用 shot https://www.baidu.com/s?wd=百度
截图会截图搜索页面
代码中 url 没有被 validate 过滤掉的话会直接喂给 page.goto ,不理解这个问题是什么导致的
tmpHtml 里面使用了css和图片,都是绝对路径
代码:
return await ctx.puppeteer.render(tmpHtml)
代码
/**
* `chromium` 截图
* @param data 模板参数
* @param data.tplFile 模板路径,必传
* @param data.saveId 生成html名称,为空name代替
* @param data.imgType screenshot参数,生成图片类型:jpeg,png
* @param data.quality screenshot参数,图片质量 0-100,jpeg是可传,默认90
* @param data.omitBackground screenshot参数,隐藏默认的白色背景,背景透明。默认不透明
* @param data.path screenshot参数,截图保存路径。截图图片类型将从文件扩展名推断出来。如果是相对路径,则从当前路径解析。如果没有指定路径,图片将不会保存到硬盘。
* @return oicq img
*/
async screenshot (name, data = {}) {
if (!await this.browserInit()) {
return false
}
let savePath = this.dealTpl(name, data)
if (!savePath) return false
let buff = ''
let start = Date.now()
this.shoting.push(name)
try {
const page = await this.browser.newPage()
await page.goto(`file://${_path}${lodash.trim(savePath, '.')}`, data.pageGotoParams || {})
let body = await page.$('#container') || await page.$('body')
let randData = {
// encoding: 'base64',
type: data.imgType || 'jpeg',
omitBackground: data.omitBackground || false,
quality: data.quality || 90,
path: data.path || ''
}
if (data.imgType == 'png') delete randData.quality
buff = await body.screenshot(randData)
page.close().catch((err) => logger.error(err))
} catch (error) {
logger.error(`图片生成失败:${name}:${error}`)
/** 关闭浏览器 */
if (this.browser) {
await this.browser.close().catch((err) => logger.error(err))
}
this.browser = false
buff = ''
return false
}
this.shoting.pop()
if (!buff) {
logger.error(`图片生成为空:${name}`)
return false
}
this.renderNum++
/** 计算图片大小 */
let kb = (buff.length / 1024).toFixed(2) + 'kb'
logger.info(`[图片生成][${name}][${this.renderNum}次] ${kb} ${`${Date.now() - start}ms`}`)
this.restart()
return segment.image(buff)
}
···
### 使用环境:
操作系统: WINDOWS 10
Node version: v16.15.1
puppeteer version: 3.0.2
koishi version: 4.10.3
(node:13084) [DEP0040] DeprecationWarning: The `punycode` module is deprecated. Please use a userland alternative instead.
at node:punycode:3:9
at BuiltinModule.compileForInternalLoader (node:internal/bootstrap/realm:398:7)
at BuiltinModule.compileForPublicLoader (node:internal/bootstrap/realm:337:10)
at loadBuiltinModule (node:internal/modules/helpers:104:7)
at Module._load (node:internal/modules/cjs/loader:999:17)
at Module.require (node:internal/modules/cjs/loader:1230:19)
at require (node:internal/modules/helpers:179:18)
at Object.<anonymous> (F:\koishi-dev\node_modules\whatwg-url\lib\url-state-machine.js:2:18)
at Module._compile (node:internal/modules/cjs/loader:1368:14)
at Module._extensions..js (node:internal/modules/cjs/loader:1426:10)
node-fetch@npm:2.7.0
└─ whatwg-url@npm:5.0.0 (via npm:^5.0.0)
cross-fetch@npm:4.0.0
└─ node-fetch@npm:2.7.0 [643a2] (via npm:^2.6.7 [643a2])
puppeteer-core@npm:22.3.0
└─ cross-fetch@npm:4.0.0 (via npm:4.0.0)
解决办法:更新 puppeteer-core
至 ^22.5.0
puppeteer/puppeteer@d5da9fb
22.5.0
移除了 cross-fetch
依赖
复用 page 比每次都开新的 page 快很多
我用一张140kb的背景ctx.puppeteer.render()渲染后,图片的大小来到了2.6mb,图片质量没有提高,但响应时间大大增加了
在图片质量不重要时,能不能增加某些可选参数降低一下图片的大小?
No response
No response
渲染出的图片(png)过大,对小水管不是很友好
修改渲染图片的格式或者内部压缩
No response
No response
由于docker内没有浏览器内核..
导致其找不到可执行文件。
请问能否内置Chromium呢
app Error: Failed to launch the browser process!
Failed to move to new namespace: PID namespaces supported, Network namespace supported, but failed: errno = Operation not permitted
[0203/185746.127214:ERROR:process_memory_range.cc(86)] read out of range
[0203/185746.127284:ERROR:elf_image_reader.cc(606)] missing nul-terminator
[0203/185746.127989:WARNING:process_reader_linux.cc(95)] sched_getscheduler: Function not implemented (38)
[0203/185746.128150:WARNING:process_reader_linux.cc(95)] sched_getscheduler: Function not implemented (38)
TROUBLESHOOTING: https://github.com/puppeteer/puppeteer/blob/main/docs/troubleshooting.md
at onClose (/koishi/node_modules/puppeteer-core/lib/cjs/puppeteer/node/BrowserRunner.js:299:20)
at ChildProcess.<anonymous> (/koishi/node_modules/puppeteer-core/lib/cjs/puppeteer/node/BrowserRunner.js:290:24)
at ChildProcess.emit (node:events:525:35)
at ChildProcess._handle.onexit (node:internal/child_process:291:12)
尝试关闭无头模式,但问题依旧(
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.