Showing Posts From
Chrome
Python 自动安装 Chrome 插件:策略强制 vs 开发者模式加载
写脚本自动帮机器装个 Chrome 插件——听着简单。Chrome 团队故意不让你静默装本地 crx(安全策略,不是技术问题)。想绕开有几条现实可行的路。 路线一:企业策略强制安装(Web Store 上架的插件) Chrome 支持通过 Windows 注册表 / macOS plist / Linux JSON 策略,指定"必须自动装某扩展"。这是 IT 部门批量部署的标准做法。 前提是扩展在 Chrome Web Store 上架——策略只接受 update URL 拉取,不认本地 crx。 Windows 注册表方式 import winregEXT_ID = "aapocclcgogkmnckokdopfmhonfmgoek" # 举例:Google Docs Offline UPDATE_URL = "https://clients2.google.com/service/update2/crx"path = r"SOFTWARE\Policies\Google\Chrome\ExtensionInstallForcelist"key = winreg.CreateKey(winreg.HKEY_LOCAL_MACHINE, path) winreg.SetValueEx(key, "1", 0, winreg.REG_SZ, f"{EXT_ID};{UPDATE_URL}") winreg.CloseKey(key)写完重启 Chrome,扩展会自动安装、无法卸载。 注意:需要管理员权限 ExtensionInstallForcelist 的编号("1"、"2" ...)要不重复 只支持 Web Store 上架的扩展;企业内部扩展需要自建 update.xml配套删除: import winreg key = winreg.OpenKey(winreg.HKEY_LOCAL_MACHINE, path, 0, winreg.KEY_WRITE) winreg.DeleteValue(key, "1")路线二:Selenium 启动时加载本地插件 不做正式安装,只是启动 Chrome 时把插件目录加载进来——最适合自动化脚本、爬虫、批量测试。 加载解压后的目录(源码形式): from selenium import webdriver from selenium.webdriver.chrome.options import Optionsopts = Options() opts.add_argument(r"--load-extension=D:\extensions\my-plugin")driver = webdriver.Chrome(options=opts) driver.get("https://example.com")加载已打包的 crx: opts = Options() opts.add_extension(r"D:\extensions\my-plugin.crx")局限:不会真的"安装",关闭浏览器就没了 需要 Selenium 控制的 Chrome,不影响用户日常浏览器 Chrome 每次启动会有"以开发者模式使用未打包扩展"警告条路线三:Playwright 加载扩展 Playwright 加载扩展要用 persistent context,且必须用 Chromium(Chrome 分发版不能通过所有测试): from playwright.sync_api import sync_playwrightwith sync_playwright() as p: ctx = p.chromium.launch_persistent_context( user_data_dir="D:/tmp/pw-profile", headless=False, args=[ "--disable-extensions-except=D:\\extensions\\my-plugin", "--load-extension=D:\\extensions\\my-plugin", ], ) page = ctx.new_page() page.goto("https://example.com")不推荐的路线 UI 自动化拖 crx 到 chrome://extensions/:Chrome 会弹确认框、快捷键会变、chrome 版本升级后经常挂。别在这个方向上死磕。 改本地 Extensions 目录里的 Preferences JSON:Chrome 会检测校验和,第二次启动直接把你写进去的扩展禁用掉。 场景对应目的 用什么公司/网吧批量部署 Web Store 扩展 策略强制安装爬虫 / 自动化脚本用自己写的扩展 Selenium 加载需要长期挂着扩展,用户不能卸载 策略强制只是测试自己开发中的插件 Chrome 开发者模式手动一句话总结 要"真安装"就上企业策略(Web Store 扩展),要"临时加载"就 Selenium/Playwright --load-extension。Chrome 就是不让你静默装本地 crx,别硬撞。
Plasmo 浏览器扩展项目 tsconfig 与 `~` 别名
用 Plasmo 写 Chrome 扩展项目,脚手架给的 tsconfig.json 是这样: { "extends": "plasmo/templates/tsconfig.base", "exclude": ["node_modules"], "include": [ ".plasmo/index.d.ts", "./**/*.ts", "./**/*.tsx" ], "compilerOptions": { "baseUrl": ".", "paths": { "~*": ["./*"] } } }一份不到 20 行,但每一行都干活。 每行在做什么extends: "plasmo/templates/tsconfig.base" — 继承 Plasmo 的严格模式基线(strict、esModuleInterop、jsx: react 等),只覆盖必要项 exclude: ["node_modules"] — 不给 TS 检查依赖 include: [".plasmo/index.d.ts", ...] — 包含 Plasmo 生成的类型声明和项目源码 baseUrl: "." — 相对根目录解析 paths: { "~*": ["./*"] } — ~utils 会被解析成 ./utils想把代码搬进 src/ Plasmo 默认允许代码散在根目录(popup.tsx、background.ts 直接扔外面)。你想集中放 src/ 下,tsconfig 需要相应改: { "extends": "plasmo/templates/tsconfig.base", "exclude": ["node_modules"], "include": [ "src/**/*.ts", "src/**/*.tsx", ".plasmo/index.d.ts" ], "compilerOptions": { "baseUrl": "src", "paths": { "~*": ["./*"], "@*": ["./*"] } } }三处变化:include 从 ./** 改成 src/** baseUrl 从 . 改成 src paths 里 ~ 和 @ 都指到 src 根之后代码里: import Button from "~/components/Button"; import { fetchUser } from "@/api/user";会被解析为 src/components/Button.tsx 和 src/api/user.ts。 Plasmo 的 url: 前缀 Plasmo 基于 Parcel 打包,导入 HTML 或图片资源有个特殊语法: import fontPickerHTML from "url:./panels/font-picker/index.html";url: 前缀告诉 Parcel"不要把这个当代码解析、当静态资源处理,导出打包后的 URL"。编译产物大致是: const fontPickerHTML = "/assets/font-picker.abc123.html";用途:chrome.windows.create({ url: fontPickerHTML }) 打开一个扩展页面。 代码搬进 src 后要配合修改: import fontPickerHTML from "url:~/panels/font-picker/index.html";因为 ~ 现在指向 src/。 除了 url: 还有 Parcel 支持多个前缀,Plasmo 都能用:url: — 当资源,返回 URL 字符串 data-url: — 编码成 base64 data URL raw: — 读文件原始内容为字符串 bundle: — 把整个 JS 打成单独 bundle data-text: — 直接嵌入文本例如把某个 css 内联进背景 script: import css from "raw:~/styles/inject.css"; chrome.scripting.insertCSS({ target: { tabId }, css });Chrome 扩展 tsconfig 常见字段 Plasmo base 已经配好,但了解一下: { "compilerOptions": { "target": "ES2020", "module": "ESNext", "moduleResolution": "Bundler", "jsx": "react", "strict": true, "esModuleInterop": true, "skipLibCheck": true, "types": ["chrome"] // 让 chrome.* API 有类型 } }types: ["chrome"] 是关键——扩展项目里 chrome.storage、chrome.runtime 得靠它。Plasmo base 里默认带了。 一句话总结 Plasmo 的 ~ 别名跟着 baseUrl 走:搬到 src/ 就把 baseUrl 改成 src、include 换成 src/**。url: 前缀是 Parcel 特有的静态资源导入,改路径时别忘了同步。
