add MyShow
parent
79c789df53
commit
3bb4f7b877
|
@ -0,0 +1,38 @@
|
|||
# _*_ coding: utf-8 _*_
|
||||
|
||||
import pymysql
|
||||
|
||||
con = pymysql.connect(host="xxxx", user="root", passwd="xxxx", db="xxxx", charset="utf8")
|
||||
cursor = con.cursor()
|
||||
con.autocommit(1)
|
||||
|
||||
|
||||
def get_all_topics():
|
||||
cursor.execute("select distinct t_topic_id, t_topic_name from t_zhihutopics where t_topic_haschildren = 1;")
|
||||
return [item for item in cursor.fetchall() if item[0].strip()]
|
||||
|
||||
|
||||
def get_topic_data(topic_id, topic_name):
|
||||
data_dict = {
|
||||
"type": "force",
|
||||
"nodes": [
|
||||
{"id": topic_id, "name": topic_name, "level": 0}
|
||||
],
|
||||
"links": []
|
||||
}
|
||||
|
||||
nodes_set = set([topic_id])
|
||||
dai_ids = set([topic_id])
|
||||
while dai_ids:
|
||||
cursor.execute("select * from t_zhihutopics where t_topic_parentid = %s;", [dai_ids.pop()])
|
||||
for item in cursor.fetchall():
|
||||
_, t_id, t_name, t_pid, t_haschild, _ = item
|
||||
|
||||
if t_id not in nodes_set:
|
||||
nodes_set.add(t_id)
|
||||
data_dict["nodes"].append({"id": t_id, "name": t_name, "level": 1 if t_pid == topic_id else 2})
|
||||
data_dict["links"].append({"source": t_pid, "target": t_id})
|
||||
|
||||
if t_haschild == 1:
|
||||
dai_ids.add(t_id)
|
||||
return data_dict
|
|
@ -0,0 +1,100 @@
|
|||
# _*_ coding: utf-8 _*_
|
||||
|
||||
import logging
|
||||
import GetData_zhihu
|
||||
|
||||
# flask
|
||||
from flask import Flask, session, request
|
||||
from flask import render_template, flash, redirect, url_for, jsonify
|
||||
|
||||
# flask extends
|
||||
from flask_bootstrap import Bootstrap
|
||||
from flask_wtf import FlaskForm
|
||||
from wtforms import StringField, PasswordField, SubmitField
|
||||
from wtforms.validators import Length, Email
|
||||
|
||||
# application
|
||||
app = Flask(__name__)
|
||||
app.config["SECRET_KEY"] = "hard to guess string"
|
||||
|
||||
# manager and bootstrap
|
||||
bootstrap = Bootstrap(app=app)
|
||||
|
||||
# global data
|
||||
zhihu_all_topics = GetData_zhihu.get_all_topics()
|
||||
zhihu_all_topics_key = {}
|
||||
zhihu_init_topics = GetData_zhihu.get_topic_data(topic_id="19559424", topic_name="数据分析")
|
||||
|
||||
|
||||
# form class
|
||||
class UserForm(FlaskForm):
|
||||
name = StringField("name", validators=[Email(message="邮箱格式不正确!")])
|
||||
password = PasswordField("password", validators=[Length(min=6, message="密码长度至少6位!")])
|
||||
submit = SubmitField("提 交")
|
||||
|
||||
|
||||
@app.route("/", methods=["GET", "POST"])
|
||||
def temp():
|
||||
return redirect(url_for("index"))
|
||||
|
||||
|
||||
@app.route("/index/", methods=["GET", "POST"])
|
||||
def index():
|
||||
user_form = UserForm()
|
||||
if request.method == "POST":
|
||||
if user_form.validate_on_submit():
|
||||
session["username"] = user_form.name.data
|
||||
else:
|
||||
flash(user_form.errors["name"][0] if "name" in user_form.errors else user_form.errors["password"][0])
|
||||
else:
|
||||
if request.args.get("action") == "login_out":
|
||||
flash("您已成功退出系统!")
|
||||
session["username"] = None
|
||||
return redirect(url_for("index"))
|
||||
elif request.args.get("action") == "overview":
|
||||
session["page_type"] = "overview"
|
||||
return redirect(url_for("index"))
|
||||
elif request.args.get("action") == "zhihu_topics":
|
||||
session["page_type"] = "zhihu_topics"
|
||||
return redirect(url_for("index"))
|
||||
return render_template("index.html", name=session.get("username"), page_type=session.get("page_type", "overview"), form=user_form)
|
||||
|
||||
|
||||
@app.route("/zhihu_get_topics_list/", methods=["post"])
|
||||
def zhihu_get_topics_list():
|
||||
key = request.form.get("key")
|
||||
result = {"success": 1, "data": []}
|
||||
if key:
|
||||
if key in zhihu_all_topics_key:
|
||||
result = zhihu_all_topics_key[key]
|
||||
else:
|
||||
for item in zhihu_all_topics:
|
||||
if item[1].find(key) >= 0:
|
||||
result["data"].append({"id": item[0], "name": item[1]})
|
||||
if len(result["data"]) > 0:
|
||||
result["success"] = 1
|
||||
zhihu_all_topics_key[key] = result
|
||||
logging.debug("all_topics_key increase: %s", len(zhihu_all_topics_key))
|
||||
return jsonify(result)
|
||||
|
||||
|
||||
@app.route("/zhihu_get_topics_data/", methods=["post"])
|
||||
def zhihu_get_topics_data():
|
||||
if request.form["id"] == "19554449":
|
||||
result = zhihu_init_topics
|
||||
else:
|
||||
result = GetData_zhihu.get_topic_data(request.form["id"], request.form["name"])
|
||||
return jsonify(result)
|
||||
|
||||
|
||||
@app.errorhandler(404)
|
||||
def page_not_found(excep):
|
||||
return render_template("error.html", error=excep, name=session.get("username")), 404
|
||||
|
||||
|
||||
# main process
|
||||
if __name__ == "__main__":
|
||||
logging.basicConfig(level=logging.DEBUG, format="%(asctime)s\t%(levelname)s\t%(message)s")
|
||||
logging.debug("app url_map: %s", app.url_map)
|
||||
|
||||
app.run()
|
|
@ -0,0 +1,105 @@
|
|||
/*
|
||||
* Base structure
|
||||
*/
|
||||
|
||||
/* Move down content because we have a fixed navbar that is 50px tall */
|
||||
body {
|
||||
padding-top: 50px;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Global add-ons
|
||||
*/
|
||||
|
||||
.sub-header {
|
||||
padding-bottom: 10px;
|
||||
border-bottom: 1px solid #eee;
|
||||
}
|
||||
|
||||
/*
|
||||
* Top navigation
|
||||
* Hide default border to remove 1px line.
|
||||
*/
|
||||
.navbar-fixed-top {
|
||||
border: 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Sidebar
|
||||
*/
|
||||
|
||||
/* Hide for mobile, show later */
|
||||
.sidebar {
|
||||
display: none;
|
||||
}
|
||||
@media (min-width: 768px) {
|
||||
.sidebar {
|
||||
position: fixed;
|
||||
top: 51px;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
z-index: 1000;
|
||||
display: block;
|
||||
padding: 20px;
|
||||
overflow-x: hidden;
|
||||
overflow-y: auto; /* Scrollable contents if viewport is shorter than content. */
|
||||
background-color: #f5f5f5;
|
||||
border-right: 1px solid #eee;
|
||||
}
|
||||
}
|
||||
|
||||
/* Sidebar navigation */
|
||||
.nav-sidebar {
|
||||
margin-right: -21px; /* 20px padding + 1px border */
|
||||
margin-bottom: 20px;
|
||||
margin-left: -20px;
|
||||
}
|
||||
.nav-sidebar > li > a {
|
||||
padding-right: 20px;
|
||||
padding-left: 20px;
|
||||
}
|
||||
.nav-sidebar > .active > a,
|
||||
.nav-sidebar > .active > a:hover,
|
||||
.nav-sidebar > .active > a:focus {
|
||||
color: #fff;
|
||||
background-color: #428bca;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Main content
|
||||
*/
|
||||
|
||||
.main {
|
||||
padding: 20px;
|
||||
}
|
||||
@media (min-width: 768px) {
|
||||
.main {
|
||||
padding-right: 40px;
|
||||
padding-left: 40px;
|
||||
}
|
||||
}
|
||||
.main .page-header {
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Placeholder dashboard ideas
|
||||
*/
|
||||
|
||||
.placeholders {
|
||||
margin-bottom: 30px;
|
||||
text-align: center;
|
||||
}
|
||||
.placeholders h4 {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
.placeholder {
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
.placeholder img {
|
||||
display: inline-block;
|
||||
border-radius: 50%;
|
||||
}
|
Binary file not shown.
After Width: | Height: | Size: 66 KiB |
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
|
@ -0,0 +1,60 @@
|
|||
{% extends "bootstrap/base.html" %}
|
||||
{% block title %}MyShow{% endblock %}
|
||||
|
||||
{% block head %}
|
||||
{{ super() }}
|
||||
<meta charset="utf-8">
|
||||
|
||||
<!-- Icon -->
|
||||
<link rel="shortcut icon" href="{{ url_for('static', filename='favicon.ico') }}" type="image/x-icon">
|
||||
|
||||
<!-- Custom styles for this template -->
|
||||
<link href="{{ url_for('static', filename='css/dashboard.css') }}" rel="stylesheet">
|
||||
|
||||
<!-- Loading Js Files -->
|
||||
<script src="{{ url_for('static', filename='js/jquery-3.0.0.min.js') }}"></script>
|
||||
<script src="{{ url_for('static', filename='js/bootstrap.min.js') }}"></script>
|
||||
<script src="{{ url_for('static', filename='js/echarts.min.js') }}"></script>
|
||||
<script src="{{ url_for('static', filename='js/bootstrap-typeahead.min.js') }}"></script>
|
||||
{% endblock %}
|
||||
|
||||
{% block navbar %}
|
||||
<nav class="navbar navbar-inverse navbar-fixed-top" role="navigation">
|
||||
<div class="container-fluid">
|
||||
<div class="nav navbar-header navbar-left">
|
||||
<a class="navbar-brand" href="/">数据展示</a>
|
||||
</div>
|
||||
<div id="navbar" class="nav navbar-nav navbar-right" style="margin-right: 10px">
|
||||
{% if name %}
|
||||
<div class="btn-group navbar-btn navbar-right">
|
||||
<button type="button" class="btn btn-success dropdown-toggle" data-toggle="dropdown">
|
||||
{{ name }}
|
||||
<span class="caret"></span>
|
||||
</button>
|
||||
<ul class="dropdown-menu" role="menu" id="login_out_menu">
|
||||
<li><a href="/index/?action=login_out">退出登录</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
{% elif form %}
|
||||
<form class="navbar-form navbar-right" role="form" method="post">
|
||||
{{ form.csrf_token }}
|
||||
<div class="form-group">
|
||||
{{ form.name(placeholder="Email...", class="form-control") }}
|
||||
</div>
|
||||
<div class="form-group">
|
||||
{{ form.password(placeholder="Password...", class="form-control") }}
|
||||
</div>
|
||||
{{ form.submit(class="btn btn-primary") }}
|
||||
</form>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<div class="container">
|
||||
{% block page_content %}
|
||||
{% endblock %}
|
||||
</div>
|
||||
{% endblock %}
|
|
@ -0,0 +1,8 @@
|
|||
{% extends "base.html" %}
|
||||
{% block title %}数据展示 - Error{% endblock %}
|
||||
|
||||
{% block page_content %}
|
||||
<div class="page-header">
|
||||
<h1>{{ error }}</h1>
|
||||
</div>
|
||||
{% endblock %}
|
|
@ -0,0 +1,165 @@
|
|||
{% extends "base.html" %}
|
||||
{% import "bootstrap/wtf.html" as wtf %}
|
||||
|
||||
{% block head %}
|
||||
{{ super() }}
|
||||
|
||||
<script type="text/javascript">
|
||||
var zhihu_topics = function () {
|
||||
var zhi_graph = echarts.init(document.getElementById("show_data_zhihu"));
|
||||
zhi_graph.showLoading();
|
||||
|
||||
var set_zhi_graph = function (data) {
|
||||
zhi_graph.hideLoading();
|
||||
|
||||
var categories = [];
|
||||
for (var i = 0; i < 3; i++) {
|
||||
categories[i] = {
|
||||
name: "级别" + (i + 1)
|
||||
}
|
||||
}
|
||||
|
||||
data.nodes.forEach(function (node) {
|
||||
node.symbolSize = 10;
|
||||
node.label = {
|
||||
normal: {
|
||||
show: true,
|
||||
position: 'right'
|
||||
}
|
||||
};
|
||||
node.draggable = true;
|
||||
node.category = node.level
|
||||
});
|
||||
|
||||
data.links.forEach(function (link) {
|
||||
link.label = {
|
||||
normal: {
|
||||
show: false
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
var option = {
|
||||
title: {
|
||||
text: '知乎话题关系图',
|
||||
subtext: '展示知乎话题之间的关系',
|
||||
top: 'top',
|
||||
left: 'left'
|
||||
},
|
||||
legend: [{
|
||||
data: categories.map(function (a) {
|
||||
return a.name;
|
||||
})
|
||||
}],
|
||||
animation: false,
|
||||
series: [
|
||||
{
|
||||
type: 'graph',
|
||||
layout: data.type,
|
||||
data: data.nodes,
|
||||
links: data.links,
|
||||
categories: categories,
|
||||
roam: true,
|
||||
force: {
|
||||
repulsion: 100
|
||||
}
|
||||
}
|
||||
]
|
||||
};
|
||||
|
||||
zhi_graph.setOption(option);
|
||||
};
|
||||
|
||||
$.post("/zhihu_get_topics_data/", {id: "19554449", name: "数据"}, set_zhi_graph);
|
||||
|
||||
var subjects = [
|
||||
{ id: 1, name: '北京' },
|
||||
{ id: 2, name: '南京' },
|
||||
{ id: 3, name: '广州' },
|
||||
{ id: 4, name: '深圳' }
|
||||
];
|
||||
|
||||
$('#zhihusearch').typeahead({
|
||||
source: function (query, process) {
|
||||
$.post("/zhihu_get_topics_list/", {key: query}, function (e) {
|
||||
if (e.success) {
|
||||
process(e.data);
|
||||
}
|
||||
});
|
||||
}, {#source: subjects,#}
|
||||
items: 20,
|
||||
minLength: 1,
|
||||
updater: function (item) {
|
||||
return item;
|
||||
},
|
||||
displayText: function (item) {
|
||||
return ":" + item["name"];
|
||||
},
|
||||
afterSelect: function (item) {
|
||||
$.ajax({
|
||||
type: "post",
|
||||
async: true,
|
||||
url: "/zhihu_get_topics_data/",
|
||||
data: item,
|
||||
dataType: "json",
|
||||
beforeSend: function (xhr) {
|
||||
zhi_graph.showLoading();
|
||||
return true
|
||||
},
|
||||
success: function (result) {
|
||||
if (result) {
|
||||
set_zhi_graph(result)
|
||||
}
|
||||
},
|
||||
error: function (error) {
|
||||
alert("请求数据失败!");
|
||||
zhi_graph.hideLoading();
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
};
|
||||
</script>
|
||||
{% endblock %}
|
||||
|
||||
{% block page_content %}
|
||||
<div class="row">
|
||||
<div class="col-sm-3 col-md-2 sidebar">
|
||||
<ul class="nav nav-sidebar">
|
||||
<li class={% if page_type == "overview" %} "active" {% else %} "" {% endif %} >
|
||||
<a href="/index/?action=overview">概 述</a>
|
||||
</li>
|
||||
<li class={% if page_type == "zhihu_topics" %} "active" {% else %} "" {% endif %} >
|
||||
<a href="/index/?action=zhihu_topics">知乎话题关系</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div class="col-sm-9 col-sm-offset-3 col-md-10 col-md-offset-2 main" style="padding-left: 20px; padding-right: 20px">
|
||||
{% for message in get_flashed_messages() %}
|
||||
<div class="alert alert-warning">
|
||||
<button type="button" class="close" data-dismiss="alert">×</button>
|
||||
{{ message }}
|
||||
</div>
|
||||
{% endfor %}
|
||||
|
||||
{% if page_type == "overview" %}
|
||||
<h2>数据展示,点击左边菜单栏即可查看各类数据展示页面</h2>
|
||||
{% elif page_type == "zhihu_topics" %}
|
||||
<div class="nav navbar-nav navbar-right">
|
||||
<input type="text" class="form-control" id="zhihusearch" data-provide="typeahead" placeholder="Search Topic...">
|
||||
</div>
|
||||
<div id="show_data_zhihu" style="width: 900px; height:600px;"></div>
|
||||
|
||||
<script type="text/javascript">
|
||||
zhihu_topics();
|
||||
</script>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
||||
{% block scripts %}
|
||||
<script type="text/javascript">
|
||||
</script>
|
||||
{% endblock %}
|
|
@ -41,6 +41,10 @@
|
|||
### python_restful_api.py: RESTful API进阶: 连接数据库、添加参数、Token认证、返回代码说明等
|
||||
|
||||
### python_context.py: With语句和上下文管理器ContextManager
|
||||
|
||||
### python_flask.py: Flask相关说明
|
||||
|
||||
### MyShow: 玩点好玩的--知乎全部话题关系可视化(Docker+Flask+Bootstrap+echarts+uWSGI+Nginx)
|
||||
===================================================================================================
|
||||
|
||||
### 您可以fork该项目, 并在修改后提交Pull request
|
||||
|
|
Loading…
Reference in New Issue