Endless Google And Baidu

谷歌和百度搜索时候免翻页自动加载搜索结果 + 搜索页面去广告.

您需要先安装一个扩展,例如 篡改猴Greasemonkey暴力猴,之后才能安装此脚本。

You will need to install an extension such as Tampermonkey to install this script.

您需要先安装一个扩展,例如 篡改猴暴力猴,之后才能安装此脚本。

您需要先安装一个扩展,例如 篡改猴Userscripts ,之后才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。

您需要先安装用户脚本管理器扩展后才能安装此脚本。

(我已经安装了用户脚本管理器,让我安装!)

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

(我已经安装了用户样式管理器,让我安装!)

// ==UserScript==
// @name            Endless Google And Baidu
// @description     谷歌和百度搜索时候免翻页自动加载搜索结果 + 搜索页面去广告.
// @author          zhengshangchao
// @namespace       [email protected]
// @icon            https://encrypted-tbn0.gstatic.com/images?q=tbn%3AANd9GcQFx1p53_ITBIbIJ01mkd-9whP3CvzIwrNiUKjqeC2G5XvHg2Uk&usqp=CAU
// @include         http://www.baidu.com*
// @include         https://www.baidu.com*
// @include         http://www.google*
// @include         https://www.google*
// @run-at          document-start
// @version         0.0.4
// @license         MIT
// @noframes
// ==/UserScript==

// 不能用于百度图片搜索或者谷歌的图片搜索
if (location.href.indexOf("tn=baiduimage") !== -1 || location.href.indexOf("tbm=isch") !== -1) return;
// 不能运行在iframes内嵌的场景
if (window.top !== window.self) return;
let flag = null;
// 判断百度还是谷歌搜索
if(location.href.includes("www.baidu.com")) {
    flag = "baidu";
} else if(location.href.includes("www.google.com")) {
    flag = "google";
} else{
    return;
}

// 百度搜索结果区和尾部的百度声明和翻页部分元素
const centerBaiduElement = "#container";
const filtersBaidu = ["#page","#content_right","#rs", "#rs_top_new", ".head_nums_cont_outer"];
const filtersBaiduCol = filtersBaidu.concat(["#content_bottom"]);

// 谷歌搜索结果区和尾部的谷歌声明和翻页部分元素
const centerGoogleElement = "#center_col";
const filtersGoogle = ["#foot"];
const filtersGoogleCol = filtersGoogle.concat(["#extrares", "#imagebox_bigimages"]);

// 自定义div部分的样式
const css = `
.page-number {
  position: relative;
  display: flex;
  flex-direction: row-reverse;
  align-items: center;
	margin-bottom: 2em;
	color: #808080;
}
.page-number::before {
  content: "";
  background-color: #ededed;
  height: 1px;
  width: 90%;
  margin: 1em 3em;
}
.endless-msg {
  position:fixed;
  bottom:0;
  left:0;
  padding:5px 10px;
  background: darkred;
  color: white;
  font-size: 11px;
  display: none;
}
.endless-msg.shown {
  display:block;
}
`;

// 公共变量声明部分
const loadWindowSize = 1.6
let pageNumber = 1;
let prevScrollY = 0;
let nextPageLoading = false;
let msg = "";

function requestNextPage() {
    nextPageLoading = true;
    // 将当前页的超链接作为下一页初始化的值
    let nextPage = new URL(location.href);
    // 如果没有查询参数就直接返回
    if ((flag == "baidu") && !nextPage.searchParams.has("wd")) return;
    if ((flag == "google") && !nextPage.searchParams.has("q")) return;
    // 请求下一页的页码
    if(flag == "baidu") {
        nextPage.searchParams.set("pn", String(pageNumber * 10));
    } else if(flag == "google") {
        nextPage.searchParams.set("start", String(pageNumber * 10));
    }
    !msg.classList.contains("shown") && msg.classList.add("shown");
    // 请求下一页
    fetch(nextPage.href)
        .then(response => response.text())
        // 提取请求下一页的返回结果
        .then(text => {
            // 新建dom解析器
            let parser = new DOMParser();
            // 解析并提取text/html
            let htmlDocument = parser.parseFromString(text, "text/html");
            // 解析并提取搜索页的结果
            let content = null;
            if(flag == "baidu"){
                if(!hasNextPage(htmlDocument.querySelector("#page"))) {
                    onScrollPageEnd()
                }
                content = htmlDocument.documentElement.querySelector(centerBaiduElement);
                filter(content, filtersBaiduCol);
            } else if(flag == "google") {
                content = htmlDocument.documentElement.querySelector(centerGoogleElement);
                if(!content.querySelector("#rso")) {
                    onScrollPageEnd()
                }
                filter(content, filtersGoogleCol);
            } else {
                return;
            }
            // 拼接center_col的div的id
            content.id = "col_" + pageNumber;
            // 新建div元素 作为分页间的分割线
            let pageMarker = document.createElement("div");
            // 设置页码+1
            pageMarker.textContent = String(pageNumber);
            // 设置class
            pageMarker.className = "page-number";
            // 创建div
            let col = document.createElement("div");
            // 设置next-col作为下一页内容的存放容器
            col.className = "next-col";
            // 添加页码分割线作为子元素
            col.appendChild(pageMarker);
            // 添加下一页的内容作为子元素
            col.appendChild(content);
            // 找到centerElement后并添加next-col的div
            (flag == "baidu") && document.querySelector(centerBaiduElement).appendChild(col);
            (flag == "google") && document.querySelector(centerGoogleElement).appendChild(col);
            // 执行一次页面自增1
            pageNumber++;
            // 下一页翻页置为false
            nextPageLoading = false;
            // 如果包含分割线的样式则移除
            msg.classList.contains("shown") && msg.classList.remove("shown");
        });
}

/**
 * 鼠标滚动事件触发翻页动作
 */
function onScrollDocumentEnd() {
    // 记录当前鼠标滚动的时候的坐标y值
    let y = window.scrollY;
    // 滚动窗口与上个滚动窗口的差值
    let delta = y - prevScrollY;
    // 如果下一页没加载且滚动差值大于0且当前窗口滚动值超过body的高度值则触发翻页
    if (!nextPageLoading && delta > 0 && isDocumentEnd(y)) {
        // 请求下一页
        requestNextPage();
    }
    // 将上一页的窗口y值暂存
    prevScrollY = y;
}

/**
 * 鼠标滚动事件触发翻页动作
 */
function isDocumentEnd(y) {
    // 当窗口内在高度和当前滚动高度值*1.6的和大于浏览器body可见区域的高度
    return y + window.innerHeight * loadWindowSize >= document.body.clientHeight;
}

/**
 * 在指定的div元素中移除不需要的元素
 */
function filter(node, filters) {
    for (let filter of filters) {
        let child = node.querySelector(filter);
        if (child) {
           child.hidden = true;
        }
    }
}

/**
 * 百度翻页显示没有【下一页】的话证明是尾页
 */
function hasNextPage(node) {
    // 是否有下一页
    let hasNextPage = true;
    for (let page of node.children) {
       if(page.textContent.indexOf("下一页") == -1) {
           hasNextPage = false;
       }
       if(page.textContent.indexOf("下一页") == 0) {
           hasNextPage = true;
       }
    }
    return hasNextPage;
}

/**
 * 尾页处理
 */
function onScrollPageEnd() {
    // 则说明搜索结果不需要再翻页了,移除鼠标滚动事件
    window.removeEventListener("scroll", onScrollDocumentEnd);
    // 翻页的布尔值设置为false
    nextPageLoading = false;
    // 如果包含shown的元素则移除
    msg.classList.contains("shown") && msg.classList.remove("shown");
    return;
}

/**
 * 初始化
 */
function init() {
    // 当前窗口鼠标滚动的高度值
    prevScrollY = window.scrollY;
    // 添加鼠标滚动事件的回调方法
    window.addEventListener("scroll", onScrollDocumentEnd);
    // 过滤掉不需要的元素
    (flag == "baidu") && filter(document, filtersBaidu);
    (flag == "google") && filter(document, filtersGoogle);
    // 创建样式元素
    let style = document.createElement("style");
    // 指定元素类型为css
    style.type = "text/css";
    // 添加css为文本节点
    style.appendChild(document.createTextNode(css));
    // 将css样式元素添加到document的head元素中
    document.head.appendChild(style);
    // 添加div元素
    msg = document.createElement("div");
    // 新增加载下一页的提醒框
    msg.setAttribute("class", "endless-msg");
    // 添加提醒框的提示语
    msg.innerText = "自动加载下一页...";
    // 将提醒框元素添加到document的body中
    document.body.appendChild(msg);
}

// 初始化DOMContentLoaded监听(html文档完全被加载和解析事件)
document.addEventListener("DOMContentLoaded", init);