完整的解决方案:爬虫 | 如何构建技术文章聚合平台(二)
优采云 发布时间: 2020-11-30 12:14履带|如何构建技术文章聚合平台(二)
作者|张家辉
来源|掘金
上一篇文章文章介绍了如何构建Crawlab的操作环境,以及如何将Puppeteer与Crawlab集成,以捕获Nuggets,SegmentFault和CSDN技术文章,最后您可以查看捕获结果。本文文章将继续说明如何使用Flask + Vue编写简化的聚合平台并显示文章的捕获内容。
文章内容抓取工具
首先,我们需要对采集器部分进行一些补充。在上一篇文章文章中,我们只编写了对文章 URL进行爬网的采集器,我们还需要对文章的内容进行爬网,因此我们需要编写该采集器的这一部分。最后一个采集器的结果集合全部更改为结果,文章的内容将作为内容字段保存在数据库中。
经过分析,发现每种技术网站的文章页面都有固定的标签,可以捕获该标签下的所有HTML。特定代码分析将不会开始,并且特定代码将发布在此处。
<p>const puppeteer = require('puppeteer');
const MongoClient = require('mongodb').MongoClient;
<br />
(async () => {
// browser
const browser = await (puppeteer.launch({
headless: true
}));
<br />
// page
const page = await browser.newPage();
<br />
// 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');
<br />
const results = await col_src.find({content: {$exists: false}}).toArray();
for (let i = 0; i el.innerHTML);
<br />
// save to database
await col.save(item);
console.log(`saved item: ${JSON.stringify(item)}`)
}
<br />
// close mongodb
client.close();
<br />
// close browser
browser.close();
<br />
})();</p>
然后按照上一篇文章文章中的步骤部署和运行采集器,您可以采集进入文章详细内容。
文章内容采集器的代码已更新为Github。
接下来,我们可以开始对这些文章进行操作。
前端和后端分离
从当前技术发展的角度来看,前端和后端分离已经成为主流:首先,前端技术变得越来越复杂,需要模块化和工程设计;其次,前端和后端分离使前端和后端团队可以协作并更有效地开发应用程序。由于本文的聚合平台是轻量级应用程序,因此我们将Python的轻量级Web应用程序框架Flask用于后端接口和前端Vue,这在最近几年变得很流行。
烧瓶
Flask被称为Micro Framework,它显示出轻量级的特性,几行代码可以编写一个Web应用程序。它依靠扩展来扩展其特定功能,例如登录身份验证,RESTful,数据模型等。在本节中,我们将构建一个REST风格的后台API应用程序。
安装
首先安装相关的依赖项。
<p>pip install flask flask_restful flask_cors pymongo</p>
基本应用
安装完成后,我们可以创建一个新的app.py文件,输入以下代码
<p>from flask import Flask
from flask_cors import CORS
from flask_restful import Api
<br />
# 生成Flask App实例
app = Flask(__name__)
<br />
# 生成API实例
api = Api(app)
<br />
# 支持CORS跨域
CORS(app, supports_credentials=True)
<br />
if __name__ == '__main__':
app.run()</p>
在命令行中输入python app.py以运行此基本的Flask应用程序。
编写API
接下来,我们需要编写一个接口来获取文章。首先,我们简要分析需求。
此Flask应用程序要实现的功能是:
从数据库中获取提取的文章,然后将文章 ID,标题,摘要和获取时间返回到前端,以用作文章列表;
对于给定的文章 ID,请将相应的文章内容从数据库返回到前端,以在详细信息页面中使用。
因此,我们需要实现以上两个API。让我们开始编写界面。
列表界面
在app.py中添加以下代码作为列表接口。
<p>class ListApi(Resource):
def get(self):
# 查询
items = col.find({'content': {'$exists': True}}).sort('_id', DESCENDING).limit(40)
<br />
data = []
for item in items:
# 将pymongo object转化为python object
_item = json.loads(json_util.dumps(item))
<br />
data.append({
'_id': _item['_id']['$oid'],
'title': _item['title'],
'source': _item['source'],
'ts': item['_id'].generation_time.strftime('%Y-%m-%d %H:%M:%S')
})
<br />
return data</p>
详细的界面
类似地,在app.py中输入以下代码。
<p>class DetailApi(Resource):
def get(self, id):
item = col.find_one({'_id': ObjectId(id)})
<br />
# 将pymongo object转化为python object
_item = json.loads(json_util.dumps(item))
<br />
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']
}</p>
映射界面
编写接口后,我们需要将它们映射到URL。
<p>api.add_resource(ListApi, '/results')
api.add_resource(DetailApi, '/results/')</p>
完整代码
以下是完整的Flask应用程序代码,该代码非常简单,并实现了文章列表和文章详细信息的两个功能。接下来,我们将开始开发前端部分。
<p>import json
<br />
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
<br />
# 生成Flask App实例
app = Flask(__name__)
<br />
# 生成MongoDB实例
mongo = MongoClient(host='192.168.99.100')
db = mongo['crawlab_test']
col = db['results']
<br />
# 生成API实例
api = Api(app)
<br />
# 支持CORS跨域
CORS(app, supports_credentials=True)
<br />
<br />
class ListApi(Resource):
def get(self):
# 查询
items = col.find({}).sort('_id', DESCENDING).limit(20)
<br />
data = []
for item in items:
# 将pymongo object转化为python object
_item = json.loads(json_util.dumps(item))
<br />
data.append({
'_id': _item['_id']['$oid'],
'title': _item['title'],
'source': _item['source'],
'ts': item['_id'].generation_time.strftime('%Y-%m-%d %H:%M:%S')
})
<br />
return data
<br />
<br />
class DetailApi(Resource):
def get(self, id):
item = col.find_one({'_id': ObjectId(id)})
<br />
# 将pymongo object转化为python object
_item = json.loads(json_util.dumps(item))
<br />
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']
}
<br />
<br />
api.add_resource(ListApi, '/results')
api.add_resource(DetailApi, '/results/')
<br />
if __name__ == '__main__':
app.run()</p>
运行python app.py以运行后台界面服务器。
Vue
Vue近年来很热门。它已经超过了Github上的React,并已成为三个开源框架(React,Vue,Angular)中明星最多的项目。与React和Angular相比,Vue非常易于使用。它不仅可以双向绑定数据以快速开始构建简单的应用程序,而且还可以使用Vuex单向数据传输来构建大型应用程序。这种灵活性是它在大多数开发人员中受欢迎的原因之一。
为了构建一个简单的Vue应用程序,我们将使用vue-cli3,这是一个vue项目的支架。首先,我们从npm安装脚手架。
安装vue-cli3
<p>yarn add @vue/cli</p>
如果尚未安装yarn,请执行以下命令进行安装。
<p>npm i -g yarn</p>
创建项目
接下来,我们需要使用vue-cli3构建一个项目。执行以下命令。
<p>vue create frontend</p>
以下选项将在命令行上弹出,选择默认值。
<p>? Please pick a preset: (Use arrow keys)
❯ default (babel, eslint)
preset (vue-router, vuex, node-sass, babel, eslint, unit-jest)
Manually select features </p>
然后vue-cli3将开始准备用于构建项目并生成项目结构的必要依赖项。
此外,我们还需要安装完成其他功能所需的软件包。
<p>yarn add axios</p>
文章列表页面
在views目录中创建List.vue文件,并写入以下内容。
<p> {{article.title}}
</a>
{{article.ts}}
<br />
import axios from 'axios'
<br />
export default {
name: 'List',
data () {
return {
list: []
}
},
methods: {
showArticle (id) {
this.$router.push(`/${id}`)
}
},
created () {
axios.get('http://localhost:5000/results')
.then(response => {
this.list = response.data
})
}
}
<br />
.list {
display: flex;
}
<br />
.left {
flex-basis: 20%;
}
<br />
.right {
flex-basis: 20%;
}
<br />
.article-list {
text-align: left;
list-style: none;
}
<br />
.article-item {
background: #c3edfb;
border-radius: 5px;
padding: 5px;
height: 32px;
display: flex;
align-items: center;
justify-content: space-between;
margin-bottom: 10px;
}
<br />
.title {
flex-basis: auto;
color: #58769d;
}
<br />
.time {
font-size: 10px;
text-align: right;
flex-basis: 180px;
}</p>
其中,引用axios与ajax的API进行交互,这是列表接口。该布局用于经典的双圣杯布局。方法中的showArticle方法接收id参数并将页面跳转到详细信息页面。
文章详细信息页面
在views目录中,创建Detail.vue文件并输入以下内容。
<p> {{article.title}}
<br />
import axios from 'axios'
<br />
export default {
name: 'Detail',
data () {
return {
article: {}
}
},
computed: {
id () {
return this.$route.params.id
}
},
created () {
axios.get(`http://localhost:5000/results/${this.id}`)
.then(response => {
this.article = response.data
})
}
}
<br />
.detail {
display: flex;
}
<br />
.left {
flex-basis: 20%;
}
<br />
.right {
flex-basis: 20%;
}
<br />
.center {
flex-basis: 60%;
text-align: left;
}
<br />
.title {
<br />
}</p>
此页面还是经典的双圣杯布局,中间占40%。通过API获得的文章的内容输出到由v-html绑定的内容。实际上,可以在此处进行进一步的CSS优化,但是作者太懒了,所以让读者来完成此任务。
添加路线
编辑router.js文件并将其修改为以下内容。
<p>import Vue from 'vue'
import Router from 'vue-router'
import List from './views/List'
import Detail from './views/Detail'
<br />
Vue.use(Router)
<br />
export default new Router({
mode: 'hash',
base: process.env.BASE_URL,
routes: [
{
path: '/',
name: 'List',
component: List
},
{
path: '/:id',
name: 'Detail',
component: Detail
}
]
})</p>
运行前端
在命令行中输入以下命令,打开:8080,您会看到文章列表。
<p>npm run serve</p>
最终效果
最终聚合平台效果的屏幕截图如下,您可以看到基本样式已经出来。
摘要
基于上一篇文章文章“教您如何使用Crawlab构建技术文章聚合平台(一)”),本文介绍了如何使用Flask + Vue和先前捕获的文章数据构建一个简单的技术文章聚合平台。使用的技术非常基础。当然,必须有很大的优化和改进空间。我将其留给读者和所有人。