谷歌插件实战-百度搜索结果过滤

17 阅读5分钟

前言

当我查询百度时,部分网站提供的答案并不准确或者并无参考价值,那么此时便想直接过滤掉这一部分搜索结果,虽然在谷歌插件市场已有很多类似产品,但是最近我刚好在学习谷歌插件,那么决定自己做一款。

准备工作

  • 编辑器 谷歌插件并不需要特定的编辑器,最普通的记事本亦可编写。本人用的是VSCode。
  • icon 谷歌插件需要四张不同尺寸的icon图片,尺寸分别为1616、3232、4848、128128。
  • 谷歌账号 如果需要上架,那么需要一个google账号。
  • 其它 谷歌插件可以引入js插件,例如jquery等。根据习惯来。

开始写写写了

1 创建基本的文件结构 文件结构 文件结构说明: images文件夹-放置icon图片,其中source为原图,.keep文件为git生成的文件; background.js-相当于插件初始js文件; constan.js-此文件为作者新增的js文件,放置content所需要用到的变量值和常量值; content.js-与页面交互的js文件,可以修改页面的所有内容,包括标签,样式等等; manifest.json-插件配置文件,扩展程序中首先读取的就是该文件; options.css、options.html、options.js-插件选项界面,右键插件图标,点击选项。 popup.css、popup.html、popup.js-插件的操作界面,左键点击插件图标。

2 修改配置文件-manifest.json 配置文件 申请权限说明: storage-插件缓存; tabs-获取当前打开的所有tab页;

3 编写background.js

// 插件内部消息类型
const MESSAGE_TYPE = {
    UPDATE_EXCLUDE_SITE: 1
};
// 排除网站列表-可以设置默认需要排除的网站
const EXCLUDE_SITE_LSIT = [];
// 将以上变量放入缓存
chrome.storage.sync.set({
    messageType: MESSAGE_TYPE,
    excludeSiteList: EXCLUDE_SITE_LSIT
});

4 分析百度搜索结果页 百度搜索结果页 在这里,我们可以清楚的看到每一个搜索结果都是一个div,其中attr为mu的为链接地址,然后每一个div的class为result c-container xpath-log new-pmd,那么我就可以查找所有class=‘result c-container xpath-log new-pmd’的div标签,然后获取mu属性的值,判断是否在需要排除的网站列表中,如果在,试用remove将其移除即可。

5 编写content.js 在编写过程中,发现class=‘result c-container xpath-log new-pmd’的标签和现实的内容条数不对等,因此更换获取方式,后来发现所有的div均在一个id=content_left的div下,因此查找id=content_left的div下所有第一层级的div,然后获取mu,判断是否在需要排除的网站列表中。

$(function (){
    
    // 获取初始化信息
    chrome.storage.sync.get(['messageType', 'excludeSiteList']).then((result) => {
        MESSAGE_TYPE = result.messageType;
        EXCLUDE_SITE_LSIT = result.excludeSiteList;
    });

	// 排除网站搜索结构-采用倒序排除
    function excludeSite(){
        for(var i = $("#content_left>div").length - 1;i >= 0;i --){
            let mu = $("#content_left>div").eq(i).attr("mu");
            if(mu != undefined){
                mu = mu.substr(mu.indexOf("//") + 2);
                mu = mu.substr(0, mu.indexOf("/"));
                if($.inArray(mu, EXCLUDE_SITE_LSIT) !== -1){
                    $("#content_left>div").eq(i).remove();
                }
            }
        }
    }

	// 等待内容显示时,才进行排除操作
    let waitConShow = setInterval(function (){
        let content = $("#content_left");
        if(content != undefined && content){
            clearInterval(waitConShow);
            excludeSite();
        }
    }, 500);

})

6 编写完background.js后即可开始测试,打开谷歌浏览器,打开扩展程序界面,打开开发者模式,加载已解压的文件夹。 加载插件 7 问题以及深思 测试后,发现第一次搜索时可以做到排除,但是后续的搜索无法排除,这里是因为content.js是跟着页面刷新而刷新的,后续的搜索结果是无页面刷新重载结果的形式,因此不会重新触发,这里的解决方案有以下两种: 一、setInterval来定时排除 二、当用户点击搜索按钮或者监控用户的回车按钮点击事件-推荐此种方式 除了上述问题,还有一个问题,那么就是如果我要修改排除的网站列表呢,总不能每次去文件修改,然后刷新插件,再使用吧。因此需要一个操作界面,这个操作界面可以使插件的操作界面,也可以直接在页面中增加一块固定区域,这个操作界面用来设置需要排除的界面。

8 问题解决

  • setInterval定时调用排除方法-修改部分代码
$(function (){
    
    // 获取初始化信息
    chrome.storage.sync.get(['messageType', 'excludeSiteList']).then((result) => {
        MESSAGE_TYPE = result.messageType;
        EXCLUDE_SITE_LSIT = result.excludeSiteList;
    });

	// 排除网站搜索结构-采用倒序排除
    function excludeSite(){
        for(var i = $("#content_left>div").length - 1;i >= 0;i --){
            let mu = $("#content_left>div").eq(i).attr("mu");
            if(mu != undefined){
                mu = mu.substr(mu.indexOf("//") + 2);
                mu = mu.substr(0, mu.indexOf("/"));
                if($.inArray(mu, EXCLUDE_SITE_LSIT) !== -1){
                    $("#content_left>div").eq(i).remove();
                }
            }
        }
    }

	// 等待内容显示时,才进行排除操作
    let waitConShow = setInterval(function (){
        let content = $("#content_left");
        if(content != undefined && content){
            clearInterval(waitConShow);
            excludeSite();

            setInterval(function (){
                excludeSite();
            }, 1000);
        }
    }, 500);
})
  • 监听搜索按钮点击事件和回车按钮点击事件
$(function (){
    
    // 获取初始化信息
    chrome.storage.sync.get(['messageType', 'excludeSiteList']).then((result) => {
        MESSAGE_TYPE = result.messageType;
        EXCLUDE_SITE_LSIT = result.excludeSiteList;
    });

	// 排除网站搜索结构-采用倒序排除
    function excludeSite(){
        for(var i = $("#content_left>div").length - 1;i >= 0;i --){
            let mu = $("#content_left>div").eq(i).attr("mu");
            if(mu != undefined){
                mu = mu.substr(mu.indexOf("//") + 2);
                mu = mu.substr(0, mu.indexOf("/"));
                if($.inArray(mu, EXCLUDE_SITE_LSIT) !== -1){
                    $("#content_left>div").eq(i).remove();
                }
            }
        }
    }

	// 等待内容显示时,才进行排除操作
    function main(){
        let waitConShow = setInterval(function (){
            let content = $("#content_left");
            if(content != undefined && content){
                clearInterval(waitConShow);
                excludeSite();
            }
        }, 500);
    }

	// 等待内容显示时,才进行排除操作
    let waitConShow = setInterval(function (){
        let content = $("#content_left");
        if(content != undefined && content){
            clearInterval(waitConShow);
            excludeSite();

            $("#su").click(function (){
                main();
            });

            $(document).keyup(function(e) {
                if (e.keyCode === 13) {
                    main();
                }
            });
        }
    }, 500);
})
  • 页面增加操作界面-content.js文件直接增加 此种方法编写过程中出现div标签无法显示的问题,通过查看F12的console,看到如下描述,大概意思应该是为了安全给我的标签删除,因此作者放弃本方案,采用第二方案。 在这里插入图片描述
  • 插件弹出页面增加操作界面-popup.html、popup.js、popup.css popup.html
<!-- 弹出框界面 -->
<!DOCTYPE html>
<html>
<head>
  <meta charset="UTF-8">
  <!-- import CSS -->
  <link rel="stylesheet" href="popup.css">
</head>
<body>
  
  <div id="fl-option">
    <div id="fl-option-add">
      <input id="fl-otion-add-con" type="text" placeholder="网站host" />
      <button id="fl-option-add-button" >增加</button>
    </div>
    <div id="fl-option-list">
    </div>
    <div id="fl-option-add">
      <button id="fl-option-del-button">移除选中</button>
    </div>
  </div>
  
  <!-- import jquery script -->
  <script type="text/javascript" charset="utf-8" src='jquery-3.7.1.min.js'></script>
  <!-- import selfDefined script -->
  <script type="text/javascript" charset="utf-8" src='popup.js'></script>
</body>
</html>

popup.js

$(function (){
    // defined constant
    let MESSAGE_TYPE;
    let EXCLUDE_SITE_LSIT = [];

    // init enum
    chrome.storage.sync.get(['messageType', 'excludeSiteList']).then((result) => {
        MESSAGE_TYPE = result.messageType;
        EXCLUDE_SITE_LSIT = result.excludeSiteList;

        refreshSiteListPage();
        document.getElementById("fl-option-add-button").addEventListener("click", optionAdd);
        document.getElementById("fl-option-del-button").addEventListener("click", optionDel);
    });

    async function syncPage(){
        chrome.storage.sync.set({
            excludeSiteList: EXCLUDE_SITE_LSIT
        });
        chrome.tabs.query({ active: true,currentWindow: true}, function(tabs) {
            if (tabs.length > 0) {
                let activeTab = tabs[0];
                (async () => {
                    await chrome.tabs.sendMessage(activeTab.id, getMessage(MESSAGE_TYPE.UPDATE_EXCLUDE_SITE, null));
                })();
            }
        });
    }

    // 添加需要排除的网页
    function optionAdd(){
        EXCLUDE_SITE_LSIT.push($("#fl-otion-add-con").val());
        $("#fl-otion-add-con").val("");
        refreshSiteListPage();
        syncPage();
    }

    // 删除需要排除的网页
    function optionDel(){
        EXCLUDE_SITE_LSIT = [];
        for(var i = 0;i < $("#fl-option-list").find("input:checkbox").length;i ++){
            if($("#fl-option-list").find("input:checkbox").eq(i).prop('checked') == false){
                EXCLUDE_SITE_LSIT.push($("#fl-option-list").find("input:checkbox").eq(i).val());
            }
        }
        refreshSiteListPage();
        syncPage();
    }

    // 刷新排除网站列表界面
    function refreshSiteListPage(){
        $("#fl-option-list").html("");
        let htmlStr = "";
        for(var i = 0;i < EXCLUDE_SITE_LSIT.length;i ++){
            htmlStr += '<label><input type="checkbox" value="' + EXCLUDE_SITE_LSIT[i] + '"/>' + EXCLUDE_SITE_LSIT[i] + '</label>';
        }
        $("#fl-option-list").append(htmlStr);
    }

    // 插件内部通讯实体
    function getMessage(messageType, messageData){
        return {
            type: messageType,
            data: messageData
        };
    }
});

popup.css

body {
    width: 200px;
    height: auto;
    font-size: 12px;
    font-family: "微软雅黑";
}
h1 {
    background-color: antiquewhite;
    font-weight: 100;
}
#fl-option{
    width: 200px;
    height: 400px;

    #fl-option-add{
        display: flex;
        align-items: center;
        justify-content: space-between;

        input{
            width: 130px;
        }

    }

    #fl-option-list{
        display: flex;
        flex-wrap: wrap;
        align-items: center;

        label{
            display: flex;
            align-items: center;
        }

    }

}

下班了下班了,先这样吧,完整代码请参考Gitee仓库