写一个 Chrome 表单自动化插件(博客评论表单) - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
请不要在回答技术问题时复制粘贴 AI 生成的内容
lhasa
0.02D

写一个 Chrome 表单自动化插件(博客评论表单)

  •  
  •   lhasa
    achuanya 2024 年 8 月 7 日 1831 次点击
    这是一个创建于 625 天前的主题,其中的信息可能已经有所发展或是发生改变。

    在刷博客的时候,最麻烦的事情之一就是手动填写各种表单。为了提高我的冲浪体验,诞生了这款表单自动化插件。经过爬虫上百次调教,兼容 95%博客,另外 5%的网站正常人写不出来,autocomplete 小伎俩都上不了台面,各种防止逆向、防调试测试,心累。

    项目结构

    插件纯绿色,无隐私可言。除 images 外,全部资源和代码文件都经过 Webpack 打包,下面是项目的目录结构以及各部分的说明:

    Form-automation-plugin │ index.html │ LICENSE │ manifest.json │ package-lock.json │ package.json │ README.md │ webpack.config.js │ ├─dist │ 33a80cb13f78b37acb39.woff2 │ 8093dd36a9b1ec918992.ttf │ 8521c461ad88443142d9.woff │ autoFill.min.js │ eventHandler.min.js │ formManager.min.js │ main.min.css │ └─src │ autoFill.js │ eventHandler.js │ formManager.js │ template.css │ template.html │ ├─fonts │ iconfont.css │ iconfont.ttf │ iconfont.woff │ iconfont.woff2 │ └─images Appreciation-code.jpg icon128.png icon16.png icon48.png 

    webpack.config.js

    const path = require('path'); const MiniCssExtractPlugin = require('mini-css-extract-plugin'); const HtmlWebpackPlugin = require('html-webpack-plugin'); module.exports = { entry: { autoFill: './src/autoFill.js', eventHandler: './src/eventHandler.js', formManager: './src/formManager.js', }, output: { filename: '[name].min.js', path: path.resolve(__dirname, 'dist'), clean: true, }, mode: 'production', module: { rules: [ { test: /\.css$/, use: [ MiniCssExtractPlugin.loader, 'css-loader', ], }, ], }, plugins: [ new MiniCssExtractPlugin({ filename: 'main.min.css', }), new HtmlWebpackPlugin({ template: path.resolve(__dirname, 'src', 'template.html'), filename: '../index.html', inject: 'body', }), ], resolve: { extensions: ['.js', '.css'], }, }; 

    autoFill.js

    // autoFill.js 文件是插件的最重要的核心模块,涉及到了插件的主要输出功能 // 遍历当前页面所有 input ,将 autocomplete 值设置为 on ,监听 Textarea 输入时触发 function handleAutocomplete() { const inputs = document.querySelectorAll('input'); inputs.forEach(input => { const autocompleteAttr = input.getAttribute('autocomplete'); if (autocompleteAttr) { input.setAttribute('autocomplete', 'on'); } else { input.setAttribute('autocomplete', 'on'); } }); } // 这个函数有些臃肿,马上要去骑车,懒得搞了,现在的逻辑已经完善到 9 成了,大多数意外情况都卷了进去,但是一些防逆向防调试,我暂时无法解决,前端菜鸟,还望大哥指点一二 function fillInputFields() { chrome.storage.sync.get(["name", "email", "url"], (data) => { // console.log(data); const hasValidName = data.name !== undefined && data.name !== ""; const hasValidEmail = data.email !== undefined && data.email !== ""; const hasValidUrl = data.url !== undefined && data.url !== ""; // 关键字 const nameKeywords = [ "name", "author", "display_name", "full-name", "username", "nick", "displayname", "first-name", "last-name", "full name", "real-name", "given-name", "family-name", "user-name", "pen-name", "alias", "name-field", "displayname" ]; const emailKeywords = [ "email", "mail", "contact", "emailaddress", "mailadress", "email-address", "mail-address", "email-addresses", "mail-addresses", "emailaddresses", "mailaddresses", "contactemail", "useremail", "contact-email", "user-mail" ]; const urlKeywords = [ "url", "link", "website", "homepage", "site", "web", "address", "siteurl", "webaddress", "homepageurl", "profile", "homepage-link" ]; const inputs = document.querySelectorAll("input, textarea"); inputs.forEach((input) => { const typeAttr = input.getAttribute("type")?.toLowerCase() || ""; const nameAttr = input.getAttribute("name")?.toLowerCase() || ""; let valueToSet = ""; // 处理 URL if (urlKeywords.some(keyword => nameAttr.includes(keyword))) { if (hasValidUrl) { valueToSet = data.url; } } // 处理邮箱 else if (emailKeywords.some(keyword => nameAttr.includes(keyword))) { if (hasValidEmail) { valueToSet = data.email; } } // 处理名称 else if (nameKeywords.some(keyword => nameAttr.includes(keyword))) { if (hasValidName) { valueToSet = data.name; } } // 处理没有 type 属性或者 type 为 text 的情况 if ((typeAttr === "" || typeAttr === "text") && valueToSet === "") { if (nameAttr && nameKeywords.some(keyword => nameAttr.includes(keyword))) { if (hasValidName) { valueToSet = data.name; } } else if (nameAttr && urlKeywords.some(keyword => nameAttr.includes(keyword))) { if (hasValidUrl) { valueToSet = data.url; } } } // 处理 type 为 email if (typeAttr === "email" && valueToSet === "") { if (nameAttr && emailKeywords.some(keyword => nameAttr.includes(keyword))) { if (hasValidEmail) { valueToSet = data.email; } } } // 处理 type 为 url if (typeAttr === "url" && valueToSet === "") { if (nameAttr && urlKeywords.some(keyword => nameAttr.includes(keyword))) { if (hasValidUrl) { valueToSet = data.url; } } } // 填充输入字段 if (valueToSet !== "") { input.value = valueToSet; } }); }); } function clearInputFields() { const inputs = document.querySelectorAll("input"); inputs.forEach((input) => { const typeAttr = input.getAttribute("type")?.toLowerCase(); if (typeAttr === "text" || typeAttr === "email") { input.value = ""; } }); } // 监听 textarea 标签的输入事件 document.addEventListener("input", (event) => { if (event.target.tagName.toLowerCase() === "textarea") { handleAutocomplete(); fillInputFields(); } }); 

    formManager.js

    该文件负责向 Chrome 本地存储和修改,就 CURD ,没啥含量

    import './fonts/iconfont.css'; import './template.css'; document.getElementById("save").addEventListener("click", () => { const saveButton = document.getElementById("save"); if (saveButton.textCOntent=== "更改") { unlockInputFields(); changeButtonText("保存"); return; } const name = document.getElementById("name").value.trim(); const email = document.getElementById("email").value.trim(); const url = document.getElementById("url").value.trim(); // 验证邮箱格式的正则表达式 const emailPattern = /^[^\s@]+@[^\s@]+\.[^\s@]+$/; if (name === "" || email === "") { alert("请填写必填字段:姓名和邮箱!"); return; } if (!emailPattern.test(email)) { alert("请输入有效的邮箱地址!"); return; } // 从 Chrome 存储中读取当前的值 chrome.storage.sync.get(["name", "email", "url"], (data) => { const isNameAndEmailChanged = name !== data.name || email !== data.email; const isUrlChanged = url !== data.url; if (isNameAndEmailChanged || isUrlChanged) { chrome.storage.sync.set({ name, email, url }, () => { lockInputFields(); changeButtonText("更改"); }); } else { lockInputFields(); changeButtonText("更改"); } }); }); // 页面加载完成时执行 document.addEventListener("DOMContentLoaded", () => { chrome.storage.sync.get(["name", "email", "url"], (data) => { document.getElementById("name").value = data.name || ""; document.getElementById("email").value = data.email || ""; document.getElementById("url").value = data.url || ""; if (data.name || data.email || data.url) { lockInputFields(); changeButtonText("更改"); } }); const menuItems = document.querySelectorAll('.dl-menu li a'); const tabCOntents= document.querySelectorAll('.tab-content'); menuItems.forEach(menuItem => { menuItem.addEventListener('click', (event) => { event.preventDefault(); tabContents.forEach(tab => tab.classList.remove('active')); const targetId = menuItem.getAttribute('href').substring(1); document.getElementById(targetId).classList.add('active'); menuItems.forEach(item => item.parentElement.classList.remove('active')); menuItem.parentElement.classList.add('active'); }); }); }); // 锁定输入框 function lockInputFields() { document.getElementById("name").setAttribute("disabled", "true"); document.getElementById("email").setAttribute("disabled", "true"); document.getElementById("url").setAttribute("disabled", "true"); } // 解锁输入框 function unlockInputFields() { document.getElementById("name").removeAttribute("disabled"); document.getElementById("email").removeAttribute("disabled"); document.getElementById("url").removeAttribute("disabled"); } // 更改按钮文本 function changeButtonText(text) { document.getElementById("save").textCOntent= text; } 

    使用方法

    git clone 到本地,浏览器打开:chrome://extensions/,加载已解压的扩展程序

    由于我没有注册 Chrome 应用商店开发者,目前只能本地运行,过几天上线应用商店,Tampermonkey 等骑车回来再做

    Github

    Form-automation-plugin:https://github.com/achuanya/Form-automation-plugin

    博客原文: https://lhasa.icu/FormAutomationPlugin.html

    目前尚无回复
    关于     帮助文档     自助推广系统     博客     API     FAQ     Solana     5423 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 51ms UTC 06:44 PVG 14:44 LAX 23:44 JFK 02:44
    Do have faith in what you're doing.
    ubao msn snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86