作者 | 周萝卜

来源 | 萝卜大杂烩

一直想做一个从爬虫到数据处理,到API部署,再到小程序展示的一条龙项目,最近抽了些时间,实现了一个关于知乎热榜的,今天就来分享一下!

数据爬取

首先我们看下需要爬取的知乎热榜

https://www.zhihu.com/billboard

这个热榜可以返回50条热榜数据,而这些数据都是通过页面的一个 JavaScript 返回的

于是我们就可以通过解析这段 JS 代码来获取对应数据

url = 'https://www.zhihu.com/billboard'
headers = {"User-Agent": "", "Cookie": ""}def get_hot_zhihu():res = requests.get(url, headers=headers)content = BeautifulSoup(res.text, "html.parser")hot_data = content.find('script', id='js-initialData').stringhot_json = json.loads(hot_data)hot_list = hot_json['initialState']['topstory']['hotList']return hot_list

然后我们再点击一个热榜,查看下具体的热榜页面,我们一直向下下拉页面,并打开浏览器的调试板,就可以看到如下的一个请求

该接口返回了一个包含热榜回答信息的 json 文件,可以通过解析该文件来获取对应的回答

def get_answer_zhihu(id):url = 'https://www.zhihu.com/api/v4/questions/%s/answers?include=' % idheaders = {"User-Agent": "", "Cookie": ""}res = requests.get(url + Config.ZHIHU_QUERY, headers=headers)data_json = res.json()answer_info = []for i in data_json['data']:if 'paid_info' in i:continueanswer_info.append({'author': i['author']['name'], 'voteup_count': i['voteup_count'],'comment_count': i['comment_count'], 'content': i['content'],'reward_info': i['reward_info']['reward_member_count']})return answer_info

数据存储

获取到数据之后,我们需要存储到数据库中,以便于后续使用。因为后面准备使用 Flask 来搭建 API 服务,所以这里存储数据的过程也基于 Flask 来做,用插件 flask_sqlalchemy。

定义数据结构

我们定义三张表,分别存储知乎热榜的详细列表信息,热榜的热度信息和热榜对应的回答信息

class ZhihuDetails(db.Model):__tablename__ = 'ZhihuDetails'id = db.Column(db.Integer, primary_key=True)hot_id = db.Column(db.String(32), unique=True, index=True)hot_name = db.Column(db.Text)hot_link = db.Column(db.String(64))hot_cardid = db.Column(db.String(32))class ZhihuMetrics(db.Model):__tablename__ = 'ZhihuMetrics'id = db.Column(db.Integer, primary_key=True)hot_metrics = db.Column(db.String(64))hot_cardid = db.Column(db.String(32), index=True)update_time = db.Column(db.DateTime)class ZhihuContent(db.Model):__tablename__ = 'ZhihuContent'id = db.Column(db.Integer, primary_key=True)answer_id = db.Column(db.Integer, index=True)author = db.Column(db.String(32), index=True)voteup_count = db.Column(db.Integer)comment_count = db.Column(db.Integer)reward_info = db.Column(db.Integer)content = db.Column(db.Text)

定时任务

由于我们需要定时查询热榜列表和热榜的热度值,所以这里需要定时运行相关的任务,使用插件 flask_apscheduler 来做定时任务

我们的定时任务,涉及到了网络请求和数据入库的操作,把这部分定时任务代码单独拉出来,在 Flask 项目的根目录下创建一个文件 apschedulerjob.py,由于在运行该文件时,是没有 Flask app 变量的,所以我们需要手动调用 app_context() 方法来创建 app 上下文

def opera_db():with scheduler.app.app_context():
...

当然,这里的 scheduler 变量是在 create_app 中初始化过的

from flask_apscheduler import APSchedulerscheduler = APScheduler()def create_app(config_name):app = Flask(__name__)app.config.from_object(config[config_name])config[config_name].init_app(app)db.init_app(app)scheduler.init_app(app)
...

接着,我们就可以根据前面的两个爬虫函数,来分别入库数据了

入库热榜热度数据

update_metrics = ZhihuMetrics(hot_metrics=i['target']['metricsArea']['text'],hot_cardid=i['cardId'],update_time=datetime.datetime.now())

入库热榜列表数据

new_details = ZhihuDetails(hot_id=i['id'], hot_name=i['target']['titleArea']['text'],hot_link=i['target']['link']['url'], hot_cardid=i['cardId'])

入库热榜回答数据

new_content = ZhihuContent(answer_id=answer_id, author=answer['author'], voteup_count=answer['voteup_count'],comment_count=answer['comment_count'], reward_info=answer['reward_info'],content=answer['content'])

最后我们就可以在 Flask 的入口程序中启动定时任务了

import os
from app import create_app, schedulerapp = create_app(os.getenv('FLASK_CONFIG') or 'default')if __name__ == '__main__':scheduler.start()app.run(debug=True)

编写 API

热榜列表 API

我们首先来做热榜列表的接口,在数据库表 ZhihuMetrics 中拿到当天热榜的最新热度信息,然后再根据热榜热度信息来获取对应的列表信息,可以总结到如下的一个函数中

def zhihudata():current_time = '%s-%s-%s 00:00:00' % (datetime.now().year, datetime.now().month, datetime.now().day,)zhihumetrics_data = ZhihuMetrics.query.filter(ZhihuMetrics.update_time > current_time).group_by(ZhihuMetrics.hot_cardid).order_by(ZhihuMetrics.update_time).all()metrics_list = db_opera.db_to_list(zhihumetrics_data)details_list = []for d in metrics_list:zhihudetails_data = ZhihuDetails.query.filter_by(hot_cardid=d[1]).first()details_list.append([zhihudetails_data.hot_name, zhihudetails_data.hot_link, d[0], d[1], d[2]])return details_list

接着定义一个视图函数返回 json 数据

@api.route('/api/zhihu/hot/')
def zhihu_api_data():zhihu_data = zhihudata()data_list = []for data in zhihu_data:data_dict = {'title': data[0], 'link': data[1], 'metrics': data[2], 'hot_id': data[3], 'update_time': data[4]}data_list.append(data_dict)return jsonify({'code': 0, 'content': data_list}), 200

热榜详情 API

下面再来做热榜详情接口,该接口可以返回热榜热度走势信息,为前端画图提供数据。

def zhihudetail(hot_id):zhihumetrics_details = ZhihuMetrics.query.filter_by(hot_cardid=hot_id).order_by(ZhihuMetrics.update_time).all()Column = {'categories': [], 'series': [{'name': '热度走势', 'data': []}]}for i in zhihumetrics_details:Column['categories'].append(datetime.strftime(i.update_time, "%Y-%m-%d %H:%M"))Column['series'][0]['data'].append(int(i.hot_metrics.split()[0]))return Column@api.route('/api/zhihu/detail/<id>/')
def zhihu_api_detail(id):zhihu_detail = zhihudetail(id)return jsonify({'code': 0, 'data': zhihu_detail}), 200

接入小程序

对于小程序端,我们这里使用了 uni-app 框架,这是一个可以一份代码多端运行的框架,还是比较不错的。

创建项目

首先通过 IDE HBuilder 创建一个 uni-app 模板

改造项目

我们简单改造下该模板,首先修改下 index.nvue 文件,把 tabList 修改如下

data() {return {tabList: [{id: "tab01",name: '知乎热榜',newsid: 0}, {id: "tab02",name: '微博热榜',newsid: 23},

我们暂时只保留两个 tab 页签,没错后面还要再做微博的热榜!

接下来打开 news-page.nvue 文件,修改网络请求地址

uni.request({url: 'http://127.0.0.1:5000/api/zhihu/hot/',data: '',

把 URL 地址指向我们自己的 API 服务地址

然后再添加我们自己的新闻参数

hot_id: news.hot_id,
metrics: news.metrics,
news_url: news.link

再修改函数 goDetail 如下

goDetail(detail) {if (this.navigateFlag) {return;}this.navigateFlag = true;uni.navigateTo({url: '/pages/detail/detail-new?query=' + encodeURIComponent(JSON.stringify(detail))});setTimeout(() => {this.navigateFlag = false;}, 200)},

点击每条热榜时,就会跳转到 url 对应的 /pages/detail/detail-new 页面

引入 uCharts

下面编写 detail-new.nvue 文件,这里主要用到了 uni-app 的插件 uCharts。这是一个高性能的跨端图表插件,非常好用。

template 部分

<template><view class="qiun-columns"><view class="qiun-bg-white qiun-title-bar qiun-common-mt" ><view class="qiun-title-dot-light">柱状热力分布</view></view><view class="qiun-charts" ><canvas canvas-id="canvasColumn" id="canvasColumn" class="charts" @touchstart="touchColumn"></canvas></view><view class="qiun-bg-white qiun-title-bar qiun-common-mt" ><view class="qiun-title-dot-light">线性走势</view></view><view class="qiun-charts" ><canvas canvas-id="canvasLine" id="canvasLine" class="charts" @touchstart="touchColumn"></canvas></view></view>
</template>

创建两个 view,分别用于展示柱状图和折线图

再编写 script 部分

getServerData(){uni.request({url: 'http://127.0.0.1:5000/api/zhihu/detail/' + this.details.hot_id,data:{},success: function(res) {_self.serverData=res.data.data;let Column={categories:[],series:[]};Column.categories=res.data.data.categories;Column.series=res.data.data.series;_self.showColumn("canvasColumn",Column);_self.showLine("canvasLine",Column);},fail: () => {_self.tips="网络错误,小程序端请检查合法域名";},});}

再根据 uCharts 的官方文档编写对应的展示图表函数

showColumn(canvasId,chartData){canvaColumn=new uCharts({$this:_self,canvasId: canvasId,type: 'column',legend:{show:true},fontSize:11,background:'#FFFFFF',pixelRatio:_self.pixelRatio,animation: true,categories: chartData.categories,series: chartData.series,enableScroll: true,xAxis: {disableGrid:true,scrollShow:true,itemCount:4,},yAxis: {//disabled:true},dataLabel: true,width: _self.cWidth*_self.pixelRatio,height: _self.cHeight*_self.pixelRatio,extra: {column: {type:'group',width: _self.cWidth*_self.pixelRatio*0.45/chartData.categories.length}}});}

这样,我们就完成了基本的项目开发

我们可以到小程序的模拟器来查看效果啦

热榜列表页面

热榜详情页面

基本的效果是有了,不过还有很多需要优化的地方,下一次,我会分享出优化后的代码以及如何把 API 服务部署到云端,同时还是提供出供大家练习的 API,不要错过哦!

资讯

活体人脑细胞5分钟学会打游戏

资讯

AI 技术大牛纷纷回归学术界

资讯

380万播放量,机器学习视频

技术

从深度学习到深度森林方法

分享

点收藏

点点赞

点在看

太好玩了,爬虫、部署API、加小程序,一条龙玩转知乎热榜!相关推荐

  1. libvirt 用c语言编译,基于C语言libvirt API简单小程序

    libvirt API简单小程序 1.程序代码如下 #include #include int getDomainInfo(int id) { virConnectPtr conn = NULL; v ...

  2. 如何快速部署积分商城小程序

    随着移动互联网的发展,小程序越来越受企业的认可.在小程序时代光环下,我们已经见证不少奇迹,它不像APP那样需要单独下载安装,也不用花费太多手机内存,更不会造成卡顿.如此方便的小程序,引起了企业的热潮. ...

  3. 好玩的表情包机器人微信小程序源码下载支持直接搜索仿聊天界面

    这是一款和表情包有关的一款机器人小程序 界面就相当于是聊天界面,然后是你和AI的界面 打开小程序后会自动全网推送几个表情包给你 然后你可以点击下方的说你还要然后又会随机发给你 当然你也可以输入关键词然 ...

  4. 好玩的表情包机器人微信小程序源码下载支持直接搜索仿聊天界面获取支持流量主

    这是一款和表情包有关的一款机器人小程序 界面就相当于是聊天界面,然后是你和AI的界面 打开小程序后会自动全网推送几个表情包给你 然后你可以点击下方的说你还要然后又会随机发给你 当然你也可以输入关键词然 ...

  5. 谷歌地图api 微信小程序_使用Google的融合位置提供程序API进行实时位置跟踪

    谷歌地图api 微信小程序 Location tracking and monitoring have seen a surge in modern application development w ...

  6. Java后端服务器点餐系统的部署+前端微信小程序开发(13)

    Java后端服务器点餐系统的部署+前端微信小程序开发(13) 编译运行小程序 1,本地调试 这和你上面java的运行要保持一致,如果是本地的java项目运行你就用 localhost 后台Java直接 ...

  7. JAVA 调用微信API 生成小程序跳转地址 亲测有效 【附效果图】

    JAVA 调用微信API 生成小程序跳转地址 JAVA 调用微信API 生成小程序跳转地址 由于工作需要,需要在后台生成自己公司的小程序分享地址以供前端工作人员使用,在开发当前功能时因为遇到一些问题导 ...

  8. 【知乎热榜爬虫】python爬取知乎热榜问题及答案

    所用库 requests xpath解析库 multiprocessing多进程 pymysql数据库操作库 实战背景 主要是爬取知乎热榜的问题及点赞数比较高的答案,通过requests请求库进行爬取 ...

  9. Scriptable入门——创建知乎热榜的小组件

    最近笔者被IOS上的一个软件迷上了,那就是Scriptable. 这款软件提供了一些易用的API,使用户可以使用Javascript快捷的构建自定义的小组件. Scriptable可以做什么 根据笔者 ...

最新文章

  1. 新转机!2020年想裸辞的程序员们注意了
  2. mybatis的#和$的差别
  3. python零基础入门教程视频下载-Python零基础入门学习视频教程全42集,资源教程下载...
  4. Python异常体系结构图
  5. FFMPEG结构体分析之AVPacket
  6. 基于tutk方案的p2p源码_以太坊源码分析--p2p节点发现
  7. 应用层为何不能设置分辨率
  8. npm 报错cb.apply is not a function
  9. SPSS调节效应检验(图文+数据集)【SPSS 045期】
  10. java_web tomcat服务器的安装与配置
  11. tcp粘包 java_详说tcp粘包和半包
  12. ANSYS Products 2020中文版
  13. 获取深户股市列表api_获取股票api
  14. android studio深色模式,Xamarin 中的深色模式
  15. 试题 基础练习 特殊回文数(123321是一个非常特殊的数,它从左边读和从右边读是一样的。   输入一个正整数n, 编程求所有这样的五位和六位十进制数,满足各位数字之和等于n 。)
  16. STIL和WGL的例子文件
  17. 找不到设备.将计算机连接,win10系统宽带连接显示不可使用找不到设备的修复方法...
  18. php不建议用织梦cms,你不得不知的织梦cms安全性设置常识 - DeDecms
  19. com.oracle:ojdbc6:12.1.0.1-atlassian-hosted‘ not found
  20. 下取整函数的含义_向上取整⌈⌉和向下取整⌊⌋符号含义及应用

热门文章

  1. 2.最详细的WSDD配置文件注释
  2. CSS3模拟IOS滑动开关
  3. 精品软件 推荐 硬盘物理序列号修改专家
  4. Quartz定时任务学习(四)调度器
  5. Android Volley 库通过网络获取 JSON 数据
  6. C技巧:结构体参数转成不定参数
  7. 关于RAID与SCSI的一些基本概念(转)
  8. 在idea项目中的android包不能识别_项目调试编译和部署运行
  9. Oracle 金融类型获得前一交易日
  10. 2018/5/1 ----1986年图灵奖PPT