为什么必须用 GM_xmlhttpRequest
用户脚本环境里调用第三方 API,普通 fetch 会被浏览器 CORS 限制卡死。GM_xmlhttpRequest 是油猴环境提供的跨域请求接口,可以绕过这个限制:
// ❌ 这样会报 CORS 错误
fetch("https://open.bigmodel.cn/api/paas/v4/chat/completions", {...})
// ✅ 用 GM_xmlhttpRequest
GM_xmlhttpRequest({
method: "POST",
url: "https://open.bigmodel.cn/api/paas/v4/chat/completions",
...
})
脚本头部必须声明权限:
// @grant GM_xmlhttpRequest
完整示例:调用视觉模型分析页面图片
// ==UserScript==
// @name AI 图片分析
// @namespace http://tampermonkey.net/
// @version 1.0
// @match *://*/*
// @grant GM_xmlhttpRequest
// ==/UserScript==
(function () {
const API_KEY = "your-api-key"; // 换成你的 key
function getImagesFromPage() {
const imgs = document.querySelectorAll("img");
return Array.from(imgs)
.slice(0, 3)
.map(img => ({
type: "image_url",
image_url: {
url: img.src || img.dataset.src // 处理懒加载
}
}))
.filter(item => item.image_url.url);
}
function requestAI(imageItems) {
GM_xmlhttpRequest({
method: "POST",
url: "https://open.bigmodel.cn/api/paas/v4/chat/completions",
headers: {
"Content-Type": "application/json",
"Authorization": "Bearer " + API_KEY
},
data: JSON.stringify({
model: "glm-4v",
messages: [
{
role: "user",
content: [
...imageItems,
{
type: "text",
text: "请分析这些图片的内容"
}
]
}
]
}),
onload: function (res) {
try {
const data = JSON.parse(res.responseText);
const answer = data?.choices?.[0]?.message?.content;
console.log("AI 回答:", answer);
alert(answer);
} catch (e) {
console.error("解析失败", e);
}
},
onerror: function (err) {
console.error("请求失败", err);
}
});
}
const images = getImagesFromPage();
if (images.length > 0) {
requestAI(images);
}
})();
图片来源处理
指定区域内的图片
function getQuestionImages() {
const container = document.querySelector(".question-area");
if (!container) return [];
return Array.from(container.querySelectorAll("img")).map(img => ({
type: "image_url",
image_url: {
url: new URL(img.getAttribute("src") || "", location.href).href
}
}));
}
new URL(src, location.href).href 可以把相对路径补全为绝对 URL。
canvas 图片转 base64
页面是 canvas 渲染(反爬、PDF 等)时,需要截图再传:
function getCanvasImage() {
const canvas = document.querySelector("canvas");
if (!canvas) return [];
return [{
type: "image_url",
image_url: {
url: canvas.toDataURL("image/png") // data:image/png;base64,...
}
}];
}
大多数视觉模型 API 同时支持 URL 和 base64 格式的图片。
常见问题
GM_xmlhttpRequest is not a function
脚本头部没有声明 @grant GM_xmlhttpRequest。
图片 URL 404 / 模型报错
- 图片 URL 必须能公网访问,
localhost、blob:、file://都不行 - 带签名的临时 URL(如 S3 presigned URL)容易过期,建议转 base64
@grant none 和 @grant GM_xmlhttpRequest 冲突
用了 GM API 就不能同时 @grant none,两者互斥。
绑定到按钮
把 AI 调用绑定到页面按钮,点击时分析当前可见的图片:
const btn = document.createElement("button");
btn.textContent = "AI 分析";
Object.assign(btn.style, {
position: "fixed",
right: "20px",
bottom: "20px",
padding: "10px 18px",
background: "#2563eb",
color: "#fff",
border: "none",
borderRadius: "8px",
cursor: "pointer",
zIndex: 9999
});
btn.onclick = () => requestAI(getImagesFromPage());
document.body.appendChild(btn);