爬虫 | 如何构建技术文章聚合平台(二)
bigegpt 2024-10-07 06:27 4 浏览
作者 | MarvinZhang
来源 | 掘金
上一篇文章《手把手教你如何用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/<string:id>')
完整代码
以下是完整的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/<string:id>')
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
文件,写入下列内容。
<template>
<div class="list">
<div class="left"></div>
<div class="center">
<ul class="article-list">
<li v-for="article in list" :key="article._id" class="article-item">
<a href="javascript:" @click="showArticle(article._id)" class="title">
{{article.title}}
</a>
<span class="time">
{{article.ts}}
</span>
</li>
</ul>
</div>
<div class="right"></div>
</div>
</template>
<script>
import axios from 'axios'
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
})
}
}
</script>
<style scoped>
.list {
display: flex;
}
.left {
flex-basis: 20%;
}
.right {
flex-basis: 20%;
}
.article-list {
text-align: left;
list-style: none;
}
.article-item {
background: #c3edfb;
border-radius: 5px;
padding: 5px;
height: 32px;
display: flex;
align-items: center;
justify-content: space-between;
margin-bottom: 10px;
}
.title {
flex-basis: auto;
color: #58769d;
}
.time {
font-size: 10px;
text-align: right;
flex-basis: 180px;
}
</style>
其中,引用了 axios
来与API进行ajax交互,这里获取的是列表接口。布局用来经典的双圣杯布局。methods
中的showArticle
方法接收id
参数,将页面跳转至详情页。
文章详情页面
在 views
目录中,创建Detail.vue
文件,并输入如下内容。
<template>
<div class="detail">
<div class="left"></div>
<div class="center">
<h1 class="title">{{article.title}}</h1>
<div class="content" v-html="article.content">
</div>
</div>
<div class="right"></div>
</div>
</template>
<script>
import axios from 'axios'
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
})
}
}
</script>
<style scoped>
.detail {
display: flex;
}
.left {
flex-basis: 20%;
}
.right {
flex-basis: 20%;
}
.center {
flex-basis: 60%;
text-align: left;
}
.title {
}
</style>
这个页面也是经典的双圣杯布局,中间占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和之前抓取的文章数据,搭建一个简易的技术文章聚合平台。用到的技术很基础,当然,肯定也还有很多需要优化和提升的空间,这个就留给读者和各位大佬吧。
本文经作者授权发布,如需转载请直接联系原作者。
博客地址:https://juejin.im/user/5a1ba6def265da430b7af463
回复下方「关键词」,获取优质资源
回复关键词「 pybook03」,可立即获取主页君与小伙伴一起翻译的《Think Python 2e》电子版
回复关键词「pybooks02」,可立即获取 O'Reilly 出版社推出的免费 Python 相关电子书合集
回复关键词「书单02」,可立即获取主页君整理的 10 本 Python 入门书的电子版
印度小伙写了套深度学习教程,Github上星标已经5000+
上百个数据文件合并,只能手动复制粘贴?教你一招十秒搞定!
一个提升图像识别准确率的精妙技巧
一文读懂:从 Python 打包到 CLI 工具
如何使用 Python 进行时间序列预测?
美亚Kindle排名第一的Python 3入门书,火遍了整个编程圈
十分钟搭建私有 Jupyter Notebook 服务器
使用 Python 制作属于自己的 PDF 电子书
12步轻松搞定Python装饰器
200 行代码实现 2048 游戏
相关推荐
- 5分钟调色大片的方法(5分钟调色大片的方法有哪些)
-
哈喽大家好。在大家印象中一定觉得ps非常难学非常难。大家不要着急,小编的教学都是针对ps零基础的同学的,而且非常实用哦。只要大家跟着图文练习一两遍,保证大家立马学会~!好了,废话少说,下面开始我们今天...
- 闪白特效原来是这么用的(闪白特效怎么使用)
-
作者|高艳侠订阅|010-86092062闪白特效是影视作品中应用比较多的效果之一,那么具体该在哪些场景使用闪白特效?具体该如何操作?下面就以AdobePremiere(以下简称PR)为例,...
- ppt常用小图标去哪里找?3个矢量素材网站推荐!
-
ppt是一个注重可视化表达的演示载体,除了高清图片,ppt中另一类常用的素材是各种小图标,也叫矢量图标,巧妙运用小图标能提升整体美观度和表现力,那么ppt常用小图标去哪里找呢?为方便各位快速找到合适的...
- 有什么好用的截图录屏工具?试试这9款
-
经常有朋友反馈苦于缺乏截屏和录屏的趁手工具,本期我们分享几个相当好用的截屏和录屏工具,希望能帮到大家。ScreenToGifScreenToGif是一款免费且开源的录屏工具。此款工具最大的特点是可以...
- 配色苦手福音!专业快速色环配色PS插件
-
今天橘子老师给的大家介绍的是一款快速配色的插件,非常强大配色苦手福音来啦!(获取方式见文末)【插件介绍】配色在后期设计中占有主导地位,好的配色能让作品更加抢眼Coolorus这款专业的配色插件,能够...
- 如何用PS抠主体?(ps怎么抠主体)
-
1.主体法抠图-抠花苞和花梗导入一张荷花苞的照片,点击上图中顶部“选择”菜单栏,下拉单击“主体”。可以看到,只有花苞被选中,但是花梗并没有被选中。接下来单击上图中左侧工具栏的“快速选择工具”,上图中顶...
- 2799元的4K电视,有保障吗?(买4k电视机哪个品牌好)
-
在上一期《电脑报》的3·15专题报道中,我们揭露了一款不靠谱的42英寸4K智能电视——TCLD42A561U。这款售价2699元的4K智能电视不仅4K画质方面存在严重问题,而且各种功能和应用体验也不理...
- 苹果电脑的Touch Bar推出一段时间了 这款工具可以帮你开发适用于它的APP
-
距离苹果推出带有TouchBar的MacBookPro已经有一段时间了,除了那些像Adobe、Google和Microsoft大公司在开发适用于TouchBar的应用之外,其实还有很多独立的开...
- 如魔法般吸取颜色的桌灯(如魔法般吸取颜色的桌灯叫什么)
-
色彩为生活带来的感官刺激,逐渐被视为理所当然。一盏桌灯运用它的神奇力量,将隐藏于物件中的颜色逐一释放,成为装点环境的空间魔法师。ColorUp是一款可以改变颜色的吸色台灯,沿用传统灯泡的造型,融入了拾...
- 一篇文章带你用jquery mobile设计颜色拾取器
-
【一、项目背景】现实生活中,我们经常会遇到配色的问题,这个时候去百度一下RGB表。而RGB表只提供相对于的颜色的RGB值而没有可以验证的模块。我们可以通过jquerymobile去设计颜色的拾取器...
- ps拾色器快捷键是什么?(ps2019拾色器快捷键)
-
ps拾色器快捷键是什么?文章末尾有获取方式,按照以下步骤就能自动获得!学会制作PS特效需要一定程度的耐心和毅力。初学者可以从基本的工具和技术开始学习,逐渐提高他们的技能水平。同时,观看更多优秀的特效作...
- 免费开源的 Windows 截图录屏工具,支持 OCR 识别和滚动截图等
-
功能很强大、安装很小巧的免费截图、录屏工具,提供很多使用的工具来帮我么能解决问题,推荐给大家。关于ShareXShareX是一款免费的windows工具,起初是一个小巧的截图工具,经过多年的迭...
- 入门到精通系列PS教程:第13篇 · 拾色器、颜色问题说明及补充
-
入门到精通系列PS教程:第13篇·拾色器、颜色问题说明及补充作者|侯潇问题说明我的第12篇教程里,有个小问题没有说清楚。要说是错误,又不算是错误,只是没有说准确。写完那篇教程后,因为已经到了深...
- PS冷知识:用吸管工具吸取屏幕上的任意颜色
-
今天,我们给大家介绍PS中的一个冷知识:用吸管工具可以吸取屏幕上的任意颜色。其实,操作起来是非常简单的。大多数情况下,我们认为,PS的吸管工具只能吸取PS软件作图区域范围内的颜色,最多加上画布四周的...
- Windows 11 将提供内置颜色选择器工具
-
Windows11内置了颜色选择器,可以扫描并识别屏幕上的颜色并生成颜色代码。此外,微软还利用人工智能技术,让屏幕上的文本扫描和选择变得更加便捷。这两项功能均已在SnippingToolv1...
- 一周热门
- 最近发表
- 标签列表
-
- mybatiscollection (79)
- mqtt服务器 (88)
- keyerror (78)
- c#map (65)
- xftp6 (83)
- bt搜索 (75)
- c#var (76)
- xcode-select (66)
- mysql授权 (74)
- 下载测试 (70)
- linuxlink (65)
- pythonwget (67)
- androidinclude (65)
- libcrypto.so (74)
- linux安装minio (74)
- ubuntuunzip (67)
- vscode使用技巧 (83)
- secure-file-priv (67)
- vue阻止冒泡 (67)
- jquery跨域 (68)
- php写入文件 (73)
- kafkatools (66)
- mysql导出数据库 (66)
- jquery鼠标移入移出 (71)
- 取小数点后两位的函数 (73)