一个自动点赞收藏的油猴脚本

需求

要求对某个网站板块下的文章,自动点赞、收藏。这种事情,还是有请万能的油猴。

实现

以下对网站作了脱敏。

先是自己写了一稿

(function() {
    'use strict';

    if (window.location.href.startsWith("https://xxx.xxx.xxx/web/#/publicity/operationsManagement/review/")) {
        setTimeout(() => {
            const likeButton = document.querySelector(".review-content-bottom > div:nth-child(1)");
            const favoriteButton = document.querySelector(".review-content-bottom > div:nth-child(2)");
            const prevPostButton = document.querySelector(".review-content-change > div:nth-child(1) > span:nth-child(2)");

            if (likeButton) likeButton.click();

            if (favoriteButton) favoriteButton.click();

            if (prevPostButton) {
                let event = new Event("click", { bubbles: true });
                prevPostButton.dispatchEvent(event);
                setTimeout(() => {
                    window.close();
                }, 1000);
            }
        }, 3000);
    }

})();

然后让 DeekSeek 改了一稿

(function() {
    'use strict';

    // 配置中心
    const CONFIG = {
        TARGET_PAGE: /https:\/\/xxx\.xxx\.xxx\/web\/#\/publicity\/operationsManagement\/review\//,
        RETRY_INTERVAL: 300,    // 元素重试间隔(毫秒)
        MAX_RETRY: 10,          // 最大重试次数
        ACTION_DELAY: 1000,     // 操作延迟
        FEEDBACK_STYLE: `
            .pufa-feedback {
                position: fixed;
                top: 20px;
                right: 20px;
                padding: 12px 20px;
                background: #1890ff;
                color: white;
                border-radius: 4px;
                box-shadow: 0 2px 8px rgba(0,0,0,0.15);
                z-index: 9999;
                font-family: system-ui;
            }
        `
    };

    // 元素选择器库
    const SELECTORS = {
        LIKE_BUTTON: '.review-content-bottom > div:nth-child(1)',
        FAVORITE_BUTTON: '.review-content-bottom > div:nth-child(2)',
        NAV_BUTTON: '.review-content-change > div:nth-child(1) > span:nth-child(2)'
    };

    class AutoOperator {
        constructor() {
            this.attemptCount = 0;
            this.initUI();
        }

        // 初始化UI反馈
        initUI() {
            GM_addStyle(CONFIG.FEEDBACK_STYLE);
            this.feedback = document.createElement('div');
            this.feedback.className = 'pufa-feedback';
            document.body.appendChild(this.feedback);
        }

        // 更新操作反馈
        updateFeedback(message) {
            this.feedback.textContent = `🤖 ${message}...`;
        }

        // 智能元素查询
        async waitForElement(selector) {
            return new Promise((resolve, reject) => {
                const check = () => {
                    this.attemptCount++;
                    const element = document.querySelector(selector);
                    if (element) {
                        resolve(element);
                    } else if (this.attemptCount >= CONFIG.MAX_RETRY) {
                        reject(new Error(`找不到元素: ${selector}`));
                    } else {
                        setTimeout(check, CONFIG.RETRY_INTERVAL);
                    }
                };
                check();
            });
        }

        // 安全点击方法
        async safeClick(selector, actionName) {
            try {
                const element = await this.waitForElement(selector);
                element.click();
                this.updateFeedback(`${actionName}成功`);
                await new Promise(r => setTimeout(r, CONFIG.ACTION_DELAY));
                return true;
            } catch (error) {
                console.warn(`${actionName}失败:`, error);
                this.updateFeedback(`${actionName}失败`);
                return false;
            }
        }

        // 执行导航操作
        async navigate() {
            const success = await this.safeClick(SELECTORS.NAV_BUTTON, '导航');
            if (success) {
                setTimeout(() => {
                    this.closeWindow();
                }, CONFIG.ACTION_DELAY);
            }
        }

        // 安全关闭窗口
        closeWindow() {
            try {
                if (!window.close()) {
                    window.history.back();
                }
            } catch (e) {
                window.location.href = 'about:blank';
            }
        }

        // 主流程
        async execute() {
            if (!CONFIG.TARGET_PAGE.test(location.href)) return;

            this.updateFeedback('开始自动化操作');

            await this.safeClick(SELECTORS.LIKE_BUTTON, '点赞');
            await this.safeClick(SELECTORS.FAVORITE_BUTTON, '收藏');
            await this.navigate();

            setTimeout(() => {
                this.feedback.remove();
            }, 2000);
        }
    }

    // 启动执行
    if (document.readyState === 'complete') {
        new AutoOperator().execute();
    } else {
        window.addEventListener('load', () => {
            new AutoOperator().execute();
        });
    }
})();

主要优化点说明:

  • 架构优化:
    采用类封装模式,提高代码可维护性
    分离配置(CONFIG)、选择器(SELECTORS)和业务逻辑
    使用面向对象设计方便功能扩展
  • 可靠性增强:
    实现智能重试机制(300ms间隔,最多重试10次)
    添加操作结果反馈系统(成功/失败提示)
    采用渐进式检测替代固定setTimeout
    增强窗口关闭策略(fallback到history.back和页面跳转)
  • 交互改进:
    添加可视化反馈UI(带表情的状态提示)
    使用现代CSS设计反馈样式
    每个操作都有明确的成功/失败提示
  • 异常处理:
    每个操作步骤都包含错误捕获
    添加操作失败时的降级处理
    控制台输出详细错误信息
  • 兼容性优化:
    支持页面加载完成后的各种状态(load/DOMContentLoaded)
    处理SPA应用的页面跳转场景
    兼容不同浏览器的窗口关闭策略
  • 可维护性提升:
    集中管理所有配置参数
    独立维护选择器库
    每个功能模块独立封装

总体而言,除了规范了一些代码,改善了兼容性,增加了一些花里胡哨的修改,其中有一个改进很有意义:我原来的是等待3秒翻页,它是监测到页面加载完成后翻页,不至于傻等。

最后还是自己完成了一稿

DeekSeek 给出的程序,实在是太啰嗦了。不过 DeekSeek 给了我启发,其实真正的需求是页面加载完成后点赞收藏,而不是等待固定的时间。最终修改如下:

(function() {
    'use strict';

    if (window.location.href.startsWith("https://*.*.*/web/#/publicity/operationsManagement/review/")) {
        const observer = new MutationObserver(() => {
            const content = document.querySelector(".review-content");
            if (content) {
                observer.disconnect();
                setTimeout(() => {
                    const likeButton = document.querySelector(".review-content-bottom > div:nth-child(1)");
                    const favoriteButton = document.querySelector(".review-content-bottom > div:nth-child(2)");
                    const prevPostButton = document.querySelector(".review-content-change > div:nth-child(1) > span:nth-child(2)");

                    if (likeButton) likeButton.click();

                    if (favoriteButton) favoriteButton.click();

                    if (prevPostButton) {
                        let event = new Event("click", { bubbles: true });
                        prevPostButton.dispatchEvent(event);
                        setTimeout(() => {
                            window.close();
                        }, 1000);
                    }
                }, 1000);  // 为控制系统资源,加载完成后等1秒
            }
        });

        observer.observe(document.body, {
            childList: true,
            subtree: true
        });
    }
})();

总结

对于人工智能,我认为,当前它能能够在许多细节上协助人类,甚至为人们带来灵感与启发。然而,要掌控全局、做出最终的判断和决策,依旧需要人类。

留下评论

您的邮箱地址不会被公开。 必填项已用 * 标注