DIY 掘金搜索

1,773 阅读4分钟

前言

自己平时比较喜欢看掘金,也会用掘金来搜索自己感兴趣或者需要的内容,但是掘金官方的搜索功能只提供了一个时间筛选的过滤选项,有时候不能满足自己的需要,所以基于官方搜索接口,做了一个二次过滤的小工具 体验

Github —— JueJin-Search

获取数据

首先要拿到官方的接口数据,分析页面接口,核心为请求的参数和 header 信息

分析接口返回的数据结构

设置对应 axios 请求

const axios = require("axios");

function getData() {
    let url = "https://web-api.juejin.im/query";
    // 构建请求参数
    let params = {
        extensions: { query: { id: "a53db5867466eddc50d16a38cfeb0890" } },
        operationName: "",
        query: "",
        variables: { type: "ALL", query: "前端", after: "", period: "ALL", first: 100 }
    };
    axios
        .post(url, params, {
            headers: { "X-Agent": "Juejin/Web" } // 伪造请求头
        })
        .then(function(response) {
            let dataArr = response.data.data.search.edges;
            console.log(dataArr); // 拿到数据数组
        })
        .catch(function(error) {
            console.log(error);
        });
}
getData(); // 执行函数

现在我们拿到了搜索请求所返回的数据。

数据过滤

拿到了数据之后,可以开始数据的过滤函数的构造:

根据某一个属性的大小过滤

function numFilter(item, property, num) {
    return item[property] >= num;
}

根据时间过滤

function timeFilter(item, property) {
    let time = new Date(new Date().getTime() - 12 * 30 * 24 * 60 * 60 * 1000).toISOString();
    return item[property] > time;
}

根据某属性是否包含某字符串过滤

function includeTest(item, property, text) {
    return item[property] && item[property].includes(text);
}

之后将过滤应用到返回的数据上,修改 axios 请求:

axios
    .post(url, params, {
        headers: { "X-Agent": "Juejin/Web" }
    })
    .then(function(response) {
        let dataArr = response.data.data.search.edges;
        let newInfo = dataArr.filter(
            ({ node: { entity } }) => timeFilter(entity, "createdAt") && numFilter(entity, "likeCount", 1000) // 过滤一年前的文章和点赞少于1000的文章
        );
        console.log(newInfo);
    })
    .catch(function(error) {
        console.log(error);
    });

代码完善

在之前的代码中,数据请求部分,我们可以稍做优化,可以把过滤的参数、查询的参数通过函数传入,方便配置并做好默认值设置

function getData(queryKey = "前端", likeNum = 1000) { // 参数的可配置
    let url = "https://web-api.juejin.im/query";
    let params = {
        extensions: { query: { id: "a53db5867466eddc50d16a38cfeb0890" } },
        operationName: "",
        query: "",
        variables: { type: "ALL", query: queryKey, after: "", period: "ALL", first: 100 }
    };
    axios
        .post(url, params, {
            headers: { "X-Agent": "Juejin/Web" }
        })
        .then(function(response) {
            let dataArr = response.data.data.search.edges;
            let newInfo = dataArr.filter(
                ({ node: { entity } }) => timeFilter(entity, "createdAt") && numFilter(entity, "likeCount", likeNum)
            );
            console.log(newInfo);
        })
        .catch(function(error) {
            console.log(error);
        });
}

起服务返回数据

我们准备将过滤好的数据再次通过接口返回,以 express 为例:

引入 express 以及 cors 模块

const express = require("express");
const cors = require("cors");

const app = express();
app.use(cors());

构建接口监听部分,将函数执行转移到监听内

app.get("/", (req, res) => {
    let promise = getData(); // 执行函数发起抓取
    promise.then(response => {
        res.json(response); // 数据返回
    });
});
app.get("/:queryKey-:likeNum", (req, res) => {
    const {
        queryKey, // 获取查询关键词
        likeNum // 获取点赞数下限
    } = req.params;
    let promise = getData(queryKey, likeNum); // 执行函数发起抓取
    promise.then(response => {
        res.json(response); // 数据返回
    });
});

app.listen(3000, () => console.log("Listening on port 3000!")); // 监听3000端口

将数据包进 promise 返回

function getData(queryKey = "前端", likeNum = 1000) {
    let url = "https://web-api.juejin.im/query";
    let params = {
        extensions: { query: { id: "a53db5867466eddc50d16a38cfeb0890" } },
        operationName: "",
        query: "",
        variables: { type: "ALL", query: queryKey, after: "", period: "ALL", first: 100 }
    };
    return axios // promise 返回出函数
        .post(url, params, {
            headers: { "X-Agent": "Juejin/Web" }
        })
        .then(function(response) {
            let dataArr = response.data.data.search.edges;
            let newInfo = dataArr.filter(
                ({ node: { entity } }) =>
                    timeFilter(entity, "createdAt") &&
                    numFilter(entity, "likeCount", likeNum)
            );
            return Promise.resolve(newInfo); // 将数据包进 promise
        })
        .catch(function(error) {
            console.log(error);
        });
}

数据再加工

最后做一个数据再排序处理,根据文章发布的先后排序

完整代码

const axios = require("axios");
const express = require("express");
var cors = require("cors");
const app = express();

app.use(cors());

function numFilter(item, property, num) {
    return item[property] >= num;
}

function includeTest(item, property, text) {
    return item[property] && item[property].includes(text);
}

function timeFilter(item, property) {
    let time = new Date(new Date().getTime() - 12 * 30 * 24 * 60 * 60 * 1000).toISOString();
    return item[property] > time;
}

function sortList(a, b) { // 按数据结构新增排序函数
    return b.node.entity.createdAt > a.node.entity.createdAt ? 1 : -1;
}

function getData(queryKey = "前端", likeNum = 1000) {
    let url = "https://web-api.juejin.im/query";
    let params = {
        extensions: { query: { id: "a53db5867466eddc50d16a38cfeb0890" } },
        operationName: "",
        query: "",
        variables: { type: "ALL", query: queryKey, after: "", period: "ALL", first: 100 }
    };
    return axios
        .post(url, params, {
            headers: { "X-Agent": "Juejin/Web" }
        })
        .then(function(response) {
            let dataArr = response.data.data.search.edges;
            let newInfo = dataArr.filter(
                ({ node: { entity } }) => timeFilter(entity, "createdAt") && numFilter(entity, "likeCount", likeNum)
            );
            newInfo.sort(sortList); // 数据返回前再排序处理
            return Promise.resolve(newInfo);
        })
        .catch(function(error) {
            console.log(error);
        });
}

app.get("/", (req, res) => {
    let promise = getData();
    promise.then(response => {
        res.json(response);
    });
});
app.get("/:queryKey-:likeNum", (req, res) => {
    const {
        queryKey,
        likeNum
    } = req.params;
    let promise = getData(queryKey, likeNum);
    promise.then(response => {
        res.json(response);
    });
});

app.listen(3000, () => console.log("Listening on port 3000!"));

以上,就搭建了一个可以根据请求的参数而返回掘金搜索过滤之后搜索结果的服务。