资讯专栏INFORMATION COLUMN

手把手教你如何用Crawlab构建技术文章聚合平台(二)

zhunjiee / 1402人阅读

摘要:上一篇文章手把手教你如何用构建技术文章聚合平台一介绍了如何使用搭建的运行环境,并且将与集成,对掘金进行技术文章的抓取,最后可以查看抓取结果。本篇文章将继续讲解如何利用编写一个精简的聚合平台,将抓取好的文章内容展示出来。

上一篇文章《手把手教你如何用Crawlab构建技术文章聚合平台(一)》介绍了如何使用搭建Crawlab的运行环境,并且将Puppeteer与Crawlab集成,对掘金、SegmentFault、CSDN进行技术文章的抓取,最后可以查看抓取结果。本篇文章将继续讲解如何利用Flask+Vue编写一个精简的聚合平台,将抓取好的文章内容展示出来。

文章内容爬虫

首先,我们需要对爬虫部分做点小小的补充。上篇文章中我们只编写了抓取文章URL的爬虫,我们还需要抓取文章内容,因此还需要将这部分爬虫编写了。上次爬虫的结果collection全部更改为results,文章的内容将以content字段保存在数据库中。

经分析知道每个技术网站的文章页都有一个固定标签,将该标签下的HTML全部抓取下来就OK了。具体代码分析就不展开了,这里贴出具体代码。

const puppeteer = require("puppeteer");
const MongoClient = require("mongodb").MongoClient;

(async () => {
  // browser
  const browser = await (puppeteer.launch({
    headless: true
  }));

  // page
  const page = await browser.newPage();

  // open database connection
  const client = await MongoClient.connect("mongodb://192.168.99.100:27017");
  let db = await client.db("crawlab_test");
  const colName = process.env.CRAWLAB_COLLECTION || "results";
  const col = db.collection(colName);
  const col_src = db.collection("results");

  const results = await col_src.find({content: {$exists: false}}).toArray();
  for (let i = 0; i < results.length; i++) {
    let item = results[i];

    // define article anchor
    let anchor;
    if (item.source === "juejin") {
      anchor = ".article-content";
    } else if (item.source === "segmentfault") {
      anchor = ".article";
    } else if (item.source === "csdn") {
      anchor = "#content_views";
    } else {
      continue;
    }

    console.log(`anchor: ${anchor}`);

    // navigate to the article
    try {
      await page.goto(item.url, {waitUntil: "domcontentloaded"});
      await page.waitFor(2000);
    } catch (e) {
      console.error(e);
      continue;
    }

    // scrape article content
    item.content = await page.$eval(anchor, el => el.innerHTML);

    // save to database
    await col.save(item);
    console.log(`saved item: ${JSON.stringify(item)}`)
  }

  // close mongodb
  client.close();

  // close browser
  browser.close();

})();

然后将该爬虫按照前一篇文章的步骤部署运行爬虫,就可以采集到详细的文章内容了。

文章内容爬虫的代码已经更新到Github了。

接下来,我们可以开始对这些文章做文章了。

前后端分离

目前的技术发展来看,前后端分离已经是主流:一来前端技术越来越复杂,要求模块化、工程化;二来前后端分离可以让前后端团队分工协作,更加高效地开发应用。由于本文的聚合平台是一个轻量级应用,后端接口编写我们用Python的轻量级Web应用框架Flask,前端我们用近年来大红大紫的上手容易的Vue。

Flask

Flask被称为Micro Framework,可见其轻量级,几行代码便可以编写一个Web应用。它靠Extensions插件来扩展其特定功能,例如登录验证、RESTful、数据模型等等。这个小节中我们将搭建一个REST风格的后台API应用。

安装

首先安装相关的依赖。

pip install flask flask_restful flask_cors pymongo
基本应用

安装完成后我们可以新建一个app.py文件,输入如下代码

from flask import Flask
from flask_cors import CORS
from flask_restful import Api

# 生成Flask App实例
app = Flask(__name__)

# 生成API实例
api = Api(app)

# 支持CORS跨域
CORS(app, supports_credentials=True)

if __name__ == "__main__":
    app.run()

命令行中输入python app.py就可以运行这个基础的Flask应用了。

编写API

接下来,我们需要编写获取文章的接口。首先我们简单分析一下需求。

这个Flask应用要实现的功能为:

从数据库中获取抓取到的文章,将文章ID、标题、摘要、抓取时间返回给前端做文章列表使用;

对给定文章ID,从数据库返回相应文章内容给前端做详情页使用。

因此,我们需要实现上述两个API。下面开始编写接口。

列表接口

app.py中添加如下代码,作为列表接口。

class ListApi(Resource):
    def get(self):
        # 查询
        items = col.find({"content": {"$exists": True}}).sort("_id", DESCENDING).limit(40)

        data = []
        for item in items:
            # 将pymongo object转化为python object
            _item = json.loads(json_util.dumps(item))

            data.append({
                "_id": _item["_id"]["$oid"],
                "title": _item["title"],
                "source": _item["source"],
                "ts": item["_id"].generation_time.strftime("%Y-%m-%d %H:%M:%S")
            })
            
        return data
详情接口

同样的,在app.py中输入如下代码。

class DetailApi(Resource):
    def get(self, id):
        item = col.find_one({"_id": ObjectId(id)})
        
        # 将pymongo object转化为python object
        _item = json.loads(json_util.dumps(item))
        
        return {
            "_id": _item["_id"]["$oid"],
            "title": _item["title"],
            "source": _item["source"],
            "ts": item["_id"].generation_time.strftime("%Y-%m-%d %H:%M:%S"),
            "content": _item["content"]
        }
映射接口

编写完接口,我们需要将它们映射到对应到URL中。

api.add_resource(ListApi, "/results")
api.add_resource(DetailApi, "/results/")
完整代码

以下是完整的Flask应用代码,很简单,实现了文章列表和文章详情两个功能。接下来,我们将开始开发前端的部分。

import json

from bson import json_util, ObjectId
from flask import Flask, jsonify
from flask_cors import CORS
from flask_restful import Api, Resource
from pymongo import MongoClient, DESCENDING

# 生成Flask App实例
app = Flask(__name__)

# 生成MongoDB实例
mongo = MongoClient(host="192.168.99.100")
db = mongo["crawlab_test"]
col = db["results"]

# 生成API实例
api = Api(app)

# 支持CORS跨域
CORS(app, supports_credentials=True)


class ListApi(Resource):
    def get(self):
        # 查询
        items = col.find({}).sort("_id", DESCENDING).limit(20)

        data = []
        for item in items:
            # 将pymongo object转化为python object
            _item = json.loads(json_util.dumps(item))

            data.append({
                "_id": _item["_id"]["$oid"],
                "title": _item["title"],
                "source": _item["source"],
                "ts": item["_id"].generation_time.strftime("%Y-%m-%d %H:%M:%S")
            })

        return data


class DetailApi(Resource):
    def get(self, id):
        item = col.find_one({"_id": ObjectId(id)})

        # 将pymongo object转化为python object
        _item = json.loads(json_util.dumps(item))

        return {
            "_id": _item["_id"]["$oid"],
            "title": _item["title"],
            "source": _item["source"],
            "ts": item["_id"].generation_time.strftime("%Y-%m-%d %H:%M:%S"),
            "content": _item["content"]
        }


api.add_resource(ListApi, "/results")
api.add_resource(DetailApi, "/results/")

if __name__ == "__main__":
    app.run()

运行python app.py,将后台接口服务器跑起来。

Vue

Vue近年来是热得发烫,在Github上已经超越React,成为三大开源框架(React,Vue,Angular)中star数最多的项目。相比于React和Angular,Vue非常容易上手,既可以双向绑定数据快速开始构建简单应用,又可以利用Vuex单向数据传递构建大型应用。这种灵活性是它受大多数开发者欢迎的原因之一。

为了构建一个简单的Vue应用,我们将用到vue-cli3,一个vue项目的脚手架。首先,我们从npm上安装脚手架。

安装vue-cli3
yarn add @vue/cli

如果你还没有安装yarn,执行下列命令安装。

npm i -g yarn
创建项目

接下来,我们需要用vue-cli3构建一个项目。执行以下命令。

vue create frontend

命令行中会弹出下列选项,选择default

? Please pick a preset: (Use arrow keys)
❯ default (babel, eslint) 
  preset (vue-router, vuex, node-sass, babel, eslint, unit-jest) 
  Manually select features 

然后vue-cli3会开始准备构建项目必要的依赖以及生成项目结构。

此外,我们还需要安装完成其他功能所需要的包。

yarn add axios
文章列表页面

views目录中创建一个List.vue文件,写入下列内容。





其中,引用了axios来与API进行ajax交互,这里获取的是列表接口。布局用来经典的双圣杯布局。methods中的showArticle方法接收id参数,将页面跳转至详情页。

文章详情页面

views目录中,创建Detail.vue文件,并输入如下内容。





这个页面也是经典的双圣杯布局,中间占40%。由API获取的文章内容输出到content中,由v-html绑定。这里其实可以做进一步的CSS优化,但作者太懒了,这个任务就交给读者来实现吧。

添加路由

编辑router.js文件,将其修改为以下内容。

import Vue from "vue"
import Router from "vue-router"
import List from "./views/List"
import Detail from "./views/Detail"

Vue.use(Router)

export default new Router({
  mode: "hash",
  base: process.env.BASE_URL,
  routes: [
    {
      path: "/",
      name: "List",
      component: List
    },
    {
      path: "/:id",
      name: "Detail",
      component: Detail
    }
  ]
})
运行前端

在命令行中输入以下命令,打开http://localhost:8080就可以看到文章列表了。

npm run serve
最终效果

最后的聚合平台效果截屏如下,可以看到基本的样式已经出来了。

总结

本文在上一篇文章《手把手教你如何用Crawlab构建技术文章聚合平台(一)》的基础上,介绍了如何利用Flask+Vue和之前抓取的文章数据,搭建一个简易的技术文章聚合平台。用到的技术很基础,当然,肯定也还有很多需要优化和提升的空间,这个就留给读者和各位大佬吧。

Github

tikazyq/crawlab

tikazyq/tech-news

如果感觉Crawlab还不错的话,请加作者微信拉入开发交流群,大家一起交流关于Crawlab的使用和开发。

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/43418.html

相关文章

  • 爬虫平台Crawlab v0.2发布

    摘要:是一个专注于爬虫的集成了爬虫管理任务调度任务监控数据分析等模块的分布式爬虫管理平台,非常适合对爬虫管理爬虫工程化有要求的开发者及企业。从目前开源的框架来看,大部分爬虫平台是以为核心,因此只能支持框架的爬虫,而不仅支持,还支持其他框架的爬虫。 showImg(https://segmentfault.com/img/remote/1460000019143107?w=2559&h=112...

    yiliang 评论0 收藏0
  • 把手你如何用Crawlab构建技术文章聚合平台(一)

    摘要:本文将介绍如何使用和抓取主流的技术博客文章,然后用搭建一个小型的技术文章聚合平台。是谷歌开源的基于和的自动化测试工具,可以很方便的让程序模拟用户的操作,对浏览器进行程序化控制。相对于,是新的开源项目,而且是谷歌开发,可以使用很多新的特性。 背景 说到爬虫,大多数程序员想到的是scrapy这样受人欢迎的框架。scrapy的确不错,而且有很强大的生态圈,有gerapy等优秀的可视化界面。但...

    LinkedME2016 评论0 收藏0
  • 把手你如何用Crawlab构建技术文章聚合平台(一)

    摘要:本文将介绍如何使用和抓取主流的技术博客文章,然后用搭建一个小型的技术文章聚合平台。是谷歌开源的基于和的自动化测试工具,可以很方便的让程序模拟用户的操作,对浏览器进行程序化控制。相对于,是新的开源项目,而且是谷歌开发,可以使用很多新的特性。 背景 说到爬虫,大多数程序员想到的是scrapy这样受人欢迎的框架。scrapy的确不错,而且有很强大的生态圈,有gerapy等优秀的可视化界面。但...

    Jeffrrey 评论0 收藏0
  • [爬虫手记] 我是如何在3分钟内开发完一个爬虫的

    摘要:前言开发爬虫是一件有趣的事情。的可配置爬虫是基于的,因此天生是支持并发的。遵守协议这个默认是开启的。的可配置爬虫降低了爬虫的开发时间,增加了爬虫开发效率,完善了工程化水平,将爬虫工程师从日常的繁琐配置工作中解放出来。 前言 开发爬虫是一件有趣的事情。写一个程序,对感兴趣的目标网站发起HTTP请求,获取HTML,解析HTML,提取数据,将数据保存到数据库或者存为CSV、JSON等格式,再...

    sushi 评论0 收藏0
  • [爬虫手记] 我是如何在3分钟内开发完一个爬虫的

    摘要:前言开发爬虫是一件有趣的事情。的可配置爬虫是基于的,因此天生是支持并发的。的可配置爬虫降低了爬虫的开发时间,增加了爬虫开发效率,完善了工程化水平,将爬虫工程师从日常的繁琐配置工作中解放出来。前言 开发爬虫是一件有趣的事情。写一个程序,对感兴趣的目标网站发起HTTP请求,获取HTML,解析HTML,提取数据,将数据保存到数据库或者存为CSV、JSON等格式,再用自己熟悉的语言例如Python对...

    YorkChen 评论0 收藏0

发表评论

0条评论

zhunjiee

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<