美文网首页
UED Landing 页 - 定时抓取掘金文章

UED Landing 页 - 定时抓取掘金文章

作者: 袋鼠云数栈前端 | 来源:发表于2022-11-17 14:56 被阅读0次

    我们是袋鼠云数栈 UED 团队,致力于打造优秀的一站式数据中台产品。我们始终保持工匠精神,探索前端道路,为社区积累并传播经验价值。

    本文作者:琉易 https://liuxianyu.cn

    本次分享基于『袋鼠云数栈UED团队』新发布的 UED Landing 页 实践得来,UED Landing 页集合了团队目前所有的基础建设以及精选文章,是团队展现风采的一个地方。
    项目基于 next.js、ts、pnpm、koa2、MongoDB 等技术方式实现,代码仓库:https://github.com/DTStack/UED,欢迎 star。

    需求介绍

    Landing 页有一个专栏页面,需要展示团队以往发在掘金社区的文章、对应的标签以及其他社区入口。

    设计思路

    基于上述的需求分析后,进行以下设计:

    1、通过 node-schedule设置一个定时任务,每天去请求掘金的接口查询最新的文章数据,包括每篇文章的标题、发布人、阅读量、发布日期、标签等;

    2、将上述方法拿到的数据处理后存入 MongoDB 数据库,只保留需要的字段;

    3、提供一个 RESTful 风格的接口,分页返回文章列表和标签列表,供专栏页面查询使用;

    4、页面请求接口,查询标签、文章数据 ,渲染页面。

    实现步骤

    以下实现步骤比较详细,类似的需求也可以按以下步骤去实现。

    Docker 安装 MongoDB

    1、下载镜像

    docker pull mongo
    

    2、创建挂载文件夹

    mkdir -p /opt/dtstack/docker/mongo
    cd /opt/dtstack/docker/mongo
    

    3、启动容器

    docker run -v /opt/dtstack/docker/mongo:/data/db --name mongodb -p 27019:27017 -e MONGO_INITDB_ROOT_USERNAME=root -e MONGO_INITDB_ROOT_PASSWORD='Admin123!@#' -d mongo --auth
    

    命令解释

    • -v 挂载本地文件夹,存储数据
    • -name 给容器指定名称
    • -p 表示端口映射,-p 宿主机port:容器port,这里不使用相同端口是为了防止攻击
    • -e 携带密码等参数
    • -d 后台运行容器
    • --auth MongoDB 进行权限校验

    4、进入容器

    docker exec -it mongodb mongo admin
    

    注意:
    rpc error: code = 2 desc = oci runtime error: exec failed: container_linux.go:235: starting container process caused “exec: “mongo”: executable file not found in $PATH”.
    如果出现上述报错,是下载的 mongodb 镜像版本比较高,mongodb 5.0 以上的版本需要使用 mongosh命令来代替原来的 mongo 命令。
    docker exec -it mongodb mongosh admin

    5、验证用户名密码登录
    返回 1 代表登录成功。

    db.auth('root', 'Admin123!@#')
    

    6、使用数据库

    use landingDB
    

    7、创建数据库的管理员

    db.createUser({ user: "landing-user", pwd: "landing-admin.1234", roles: [{ role: "readWrite", db: "landingDB" }] })
    

    MongoDB 不允许同一窗口有多个用户登录,退出再次进入终端:

    db.auth('landing-user', 'landing-admin.1234')
    

    8、创建表

    db.createCollection('article')
    db.createCollection('tag')
    

    9、测试插入数据

    db.article.insert({ id: 1, title: '测试文章标题' })
    

    10、通过 MongoDB Compass 连接数据库

    mongodb://landing-user:landing-admin.1234@127.0.0.1:27019/landingDB
    

    编写 node 服务

    1、借助 koa2 启动 node 服务

    服务入口处新建定时任务,每天去掘金获取文章数据

    // 引入模块
    const Koa = require('koa')
    const schedule = require('node-schedule')
    
    // 实例化
    const app = new Koa()
    
    const main = async () => {
        await initDB()
    
        // 保存文章列表
        const articleList = await getJueJinArticleList()
        await insertArticles(articleList)
    
        // 保存标签列表
        const tagList = getTagList(articleList)
        await insertTags(tagList)
    }
    
    app.listen(envJson.appPort, () => {
        console.log(`app runs on port ${ envJson.appPort }`)
        schedule.scheduleJob(cron, main)
    })
    

    2、将查询的数据存入数据库,并处理历史数据

    const { MongoClient } = require('mongodb')
    
    const url = `mongodb://${username}:${password}@${host}:${port}/${dbName}`
    const client = new MongoClient(url)
    
    // 初始化数据库链接
    const initDB = async () => {
        await client.connect()
        console.log('Connected successfully to mongodb')
    }
    
    // 新增查询到的文章列表
    const insertArticles = async (articleList) => {
        const db = client.db(dbName)
        const collection = db.collection('article')
    
        const updateResult = await collection.updateMany({ isDelete: 0 }, { $set: { isDelete: 1, updateTime: getDateStr() } })
        console.log('updateArticles documents =>', updateResult)
    
        const insertResult = await collection.insertMany(articleList)
        console.log('insertArticles documents =>', insertResult)
    }
    

    3、提供接口,从数据库读取数据
    接口文档

    const Router = require('koa-router')
    const router = new Router()
    
    router.get('/api/getTagList', async (ctx) => {
        try {
            const db = client.db(dbName)
            const collection = db.collection('tag')
            
            const data = await collection.find({ isDelete: 0 }).toArray()
            ctx.body = {
                code: 200,
                data,
                message: '成功',
            }
        } catch (error) {
            ctx.body = {
                code: 1,
                error
            }
        }
    })
    

    编写页面

    1、页面请求接口,拿到文章数据进行渲染,在标签、分页等参数变化时重新请求接口

    useEffect(() => {
        const params = {
            page,
            pageSize,
            tag_id,
            sort_type,
        }
        fetch(`/api/getArticleList?${new URLSearchParams(params).toString()}`)
            .then(res => res.json())
            .then(res => {
                const { articleList, total } = res.data
                setArticleList(articleList || [])
                setTotal(total || [])
            })
    }, [tag_id, sort_type, page])
    

    部署方式

    一台 CentOS 服务器,安装 node 14+,pnpm,pm2,Docker(可选),MongoDB,nginx。

    mkdir -p /opt/dtstack
    git clone https://github.com/DTStack/UED.git
    cd UED
    pnpm i
    pnpm deploy
    

    因为后端服务的接口一般不对外暴露,此处通过 nginx 进行转发:

    # ued landing 的 nginx 配置
    
    # http
    server {
      listen          80;
      server_name     ued.dtstack.cn;
    
      location / {
        proxy_pass http://localhost:3004/;
      }
    
      location /api {
        proxy_pass http://localhost:3002/api;
      }
    }
    

    实现效果

    http://ued.dtstack.cn/article

    相关文章

      网友评论

          本文标题:UED Landing 页 - 定时抓取掘金文章

          本文链接:https://www.haomeiwen.com/subject/zdspxdtx.html