自学python的数据分析,爬虫后,花了几天时间学习Flask做了一个简单的股票查询网页。本想着加入其它的分析板块,不过发现部署到服务器还要花钱,于是先到此为止,后面可能会继续加入其它模块。欢迎交流讨论。
先放一张最终效果图。网页左上角输入股票代码,可以在下方显示实时行情、历史走势、股评词云等信息。原本想加入财务指标的,不过买不起服务器,所以先做一个简单的版本。
一、准备
工具主要用到pycharm,jupyter notebook,mysql.还有echarts制作网页图表。
整个项目并不复杂,下图中的项目文件app.py用来写后端,main.html和main.css用来写前端,utils用来写一些函数。
二、爬虫
历史数据和实时行情数据是从网易财经和腾讯财经提供的api接口获取的,股评从东方财富网爬取。
三、各文档代码
1.app.py
from flaskimport Flask
from flaskimport request
from flaskimport render_template
from flaskimport jsonify
# import pymysql
import uitls
import sys
from jieba.analyseimport extract_tags
import string
# sys.setrecursionlimit(100000)
stock_id ='600009'
app = Flask(__name__)
@app.route("/be")
def get_data():
data = uitls.get_be_data(str(stock_id))
return jsonify({"股票名称": data[1],"当前价格": data[3],"成交量": data[6],"涨跌幅": data[32],"流通市值": data[44]})
@app.route("/his", methods=["get", "post"])
def get_history_data():
msg = uitls.get_history_data(str(stock_id))
print(msg)
print(type(msg))
return jsonify({"日期":msg['日期'],"开盘价":msg['开盘价'],"收盘价":msg['收盘价'],"最低价":msg['最低价'],"最高价":msg['最高价']})
# jsonify({"日期": msg['日期'][0],"开盘价":msg['开盘价'][0]})
@app.route("/gp", methods=["get", "post"])
def get_guping():
data = uitls.get_guping(stock_id)
d = []
for iin data:
k = i.rstrip(string.digits)
v = i[len(k):]
ks = extract_tags(k)
# print(v)
for jin ks:
if not j.isdigit():
d.append({'name': j, 'value': v})
return jsonify({'kws':d})
@app.route("/time", methods=["get", "post"])
def get_time():
return uitls.get_time()
@app.route("/", methods=["get", "post"])
def input_id():
return render_template("main.html")
@app.route("/ind", methods=["get", "post"])
def get_id():
global stock_id
stock_id = request.values.get("股票代码")
print(stock_id)
return render_template("main.html")
if __name__ =='__main__':
app.run()
2 main.html
<!DOCTYPE html>
<head link rel="shortcut icon" href="#" />
<meta charset="utf-8">
<title>股票数据
<script src="../static/js/jquery-3.5.1.min.js">
<script src="../static/js/echarts.min.js">
<script src="../static/js/echarts-wordcloud.min.js">
<link href = "../static/css/main.css" rel = "stylesheet"/>
<div id = "title">股票查询
<form action="/ind">
股票代码 <input name = "股票代码" placeholder="请输入股票代码">
<button>提交
<div id = "tim">我是时间
<div id = "be">
<div class ="tex"><h2>股票名称
<div class ="tex"><h2>当前价格
<div class ="tex"><h2>成交量
<div class ="tex"><h2>涨跌幅
<div class ="tex"><h2>流通市值
<div class ="num"><h1>123
<div class ="num"><h1>123
<div class ="num"><h1>123
<div class ="num"><h1>123
<div class ="num"><h1>123
<div id="bl" style="width:800px;height:435px;">我是瞎做
var hisdata =echarts.init(document.getElementById('bl'));
var upColor ='#ec0000';
var upBorderColor ='#8A0000';
var downColor ='#00da3c';
var downBorderColor ='#008F28';
hisdata_option = {
title: {
text:'历史趋势',
left:0
},
tooltip: {
trigger:'axis',
axisPointer: {
type:'cross'
}
},
legend: {
data: ['日K', 'MA5', 'MA10', 'MA20', 'MA30']
},
grid: {
left:'10%',
right:'10%',
bottom:'15%'
},
xAxis: {
type:'category',
data: [],
scale:true,
boundaryGap:false,
axisLine: {onZero:false},
splitLine: {show:false},
splitNumber:20,
min:'dataMin',
max:'dataMax'
},
yAxis: {
scale:true,
splitArea: {
show:true
}
},
dataZoom: [
{
type:'inside',
start:50,
end:100
},
{
show:true,
type:'slider',
top:'90%',
start:50,
end:100
}
],
series: [
{
name:'日K',
type:'candlestick',
data: [],
itemStyle: {
color:upColor,
color0:downColor,
borderColor:upBorderColor,
borderColor0:downBorderColor
},
markPoint: {
label: {
normal: {
formatter:function (param) {
return param !=null ?Math.round(param.value) :'';
}
}
},
data: [
{
name:'XX标点',
coord: ['2013/5/31', 2300],
value:2300,
itemStyle: {
color:'rgb(41,60,85)'
}
},
{
name:'highest value',
type:'max',
valueDim:'highest'
},
{
name:'lowest value',
type:'min',
valueDim:'lowest'
},
{
name:'average value on close',
type:'average',
valueDim:'close'
}
],
tooltip: {
formatter:function (param) {
return param.name +'<br>' + (param.data.coord ||'');
}
}
},
markLine: {
symbol: ['none', 'none'],
data: [
[
{
name:'from lowest to highest',
type:'min',
valueDim:'lowest',
symbol:'circle',
symbolSize:10,
label: {
show:false
},
emphasis: {
label: {
show:false
}
}
},
{
type:'max',
valueDim:'highest',
symbol:'circle',
symbolSize:10,
label: {
show:false
},
emphasis: {
label: {
show:false
}
}
}
],
{
name:'min line on close',
type:'min',
valueDim:'close'
},
{
name:'max line on close',
type:'max',
valueDim:'close'
}
]
}
},
{
name:'MA5',
type:'line',
data:'',
smooth:true,
lineStyle: {
opacity:0.5
}
},
{
name:'MA10',
type:'line',
data:'',
smooth:true,
lineStyle: {
opacity:0.5
}
},
{
name:'MA20',
type:'line',
data:'',
smooth:true,
lineStyle: {
opacity:0.5
}
},
{
name:'MA30',
type:'line',
data:'',
smooth:true,
lineStyle: {
opacity:0.5
}
},
]
};
<div id="br" style="width:800px;height:435px;">我是下游
var gp =echarts.init(document.getElementById('br'));
var ddd = [{
name:'Farrah Abraham',
value:366,
// Style of single text
}];
image1="data:image/png;base64,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"
var maskResource =new Image()
maskResource.src=image1;
gp_option = {
title:{
text:'股评词云图',
left:'center',
},
//数据可以点击
tooltip:{
show:false
},
series: [{
type:'wordCloud',
// The shape of the "cloud" to draw. Can be any polar equation represented as a
// callback function, or a keyword present. Available presents are circle (default),
// cardioid (apple or heart shape curve, the most known polar equation), diamond (
// alias of square), triangle-forward, triangle, (alias of triangle-upright, pentagon, and star.
shape:'circle',
// A silhouette image which the white area will be excluded from drawing texts.
// The shape option will continue to apply as the shape of the cloud to grow.
// maskImage: maskResource,
// // Folllowing left/top/width/height/right/bottom are used for positioning the word cloud
// // Default to be put in the center and has 75% x 80% size.
left:'center',
top:'center',
width:'70%',
height:'80%',
right:null,
bottom:null,
// Text size range which the value in data will be mapped to.
// Default to have minimum 12px and maximum 60px size.
sizeRange: [12, 60],
// Text rotation range and step in degree. Text will be rotated randomly in range [-90, 90] by rotationStep 45
rotationRange: [-90, 90],
rotationStep:45,
// size of the grid in pixels for marking the availability of the canvas
// the larger the grid size, the bigger the gap between words.
gridSize:8,
// set to true to allow word being draw partly outside of the canvas.
// Allow word bigger than the size of the canvas to be drawn
drawOutOfBound:false,
// Global text style
textStyle: {
normal: {
fontFamily:'sans-serif',
fontWeight:'bold',
// Color can be a callback function or a color string
color:function () {
// Random color
return 'rgb(' + [
Math.round(Math.random() *160),
Math.round(Math.random() *160),
Math.round(Math.random() *160)
].join(',') +')';
}
},
emphasis: {
shadowBlur:10,
shadowColor:'#333'
}
},
// Data is an array. Each array item must have name and value property.
data: [{
name:'Farrah Abraham',
value:366,
// Style of single text
}]
}]
}
function getatime(){
$.ajax({
url:"/time",
success:function(d){
$("#tim").html(d)
},
error:function(jqXHR, textStatus, errorThrown){
console.log(jqXHR.responseText);
}
})
}
function get_be_data(){
$.ajax({
url:"/be",
success:function(data){
$(".num h1").eq(0).text(data['股票名称'])
$(".num h1").eq(1).text(data['当前价格'])
$(".num h1").eq(2).text(data['成交量'])
$(".num h1").eq(3).text(data['涨跌幅'])
$(".num h1").eq(4).text(data['流通市值'])
},
error:function(jqXHR, textStatus, errorThrown){
console.log(jqXHR.responseText);
}
})
}
function get_guping(){
$.ajax({
url:"/gp",
success:function(data){
gp_option.series[0].data = data.kws;
gp.setOption(gp_option);
},
error:function(jqXHR, textStatus, errorThrown){
console.log(jqXHR.responseText);
}
})
}
function get_his_data(){
$.ajax({
url:"/his",
success:function(msg){
var datalen = msg['日期'].length
k_time =[]
k_value = []
for (var i =0; i < datalen; i++) {
k_time.push(msg['日期'][i]);
k_value.push([msg['开盘价'][i],
msg['收盘价'][i],
msg['最低价'][i],
msg['最高价'][i]])
}
console.log(k_time)
console.log(k_value)
function calculateMA(dayCount) {
var result = [];
for (var i =0, len =k_value.length; i < len; i++) {
if (i < dayCount) {
result.push('-');
continue;
}
var sum =0;
for (var j =0; j < dayCount; j++) {
sum +=k_value[i - j][1];
}
result.push(sum / dayCount);
}
return result;
}
hisdata_option.xAxis.data =k_time;
hisdata_option.series[0].data =k_value;
hisdata_option.series[1].data =calculateMA(5);
hisdata_option.series[2].data =calculateMA(10);
hisdata_option.series[3].data =calculateMA(20);
hisdata_option.series[4].data =calculateMA(30);
hisdata.setOption(hisdata_option);
},
error:function(){
console.log("获取失败");
}
})
}
setInterval(getatime,1000)
setInterval(get_be_data,1000)
get_his_data()
get_guping()
3.main.css
body{
margin:0;
background:#333;
}
#title{
position:absolute;
width:40%;
height:10%;
top:0;
left:30%;
/* background-color: #666666; */
color:white;
font-size:30px;
display:flex;
align-items:center;
justify-content:center;
}
#ins{
position:absolute;
width:40%;
height:20%;
top:10%;
left:0;
background-color:grey;
}
#tim{
position:absolute;
/* width: 30%; */
height:10%;
top:5%;
right:2%;
color:#FFFFFF;
font-size:20px;
/* background-color: green; */
}
#be{
position:absolute;
width:100%;
height:30%;
top:10%;
left:0;
color:white;
/* background-color: #777777; */
}
#bl{
position:absolute;
width:50%;
height:60%;
top:40%;
left:0;
background-color:#888888;
}
#br{
position:absolute;
width:50%;
height:60%;
top:40%;
left:50%;
background-color:#999999;
}
.num{
width:20%;
float:left;
display:flex;
align-items:center;
justify-content:center;
color:yellow;
font-size:20px;
}
.tex{
width:20%;
float:left;
font-family:"幼圆";
display:flex;
align-items:center;
justify-content:center;
}
4 utils.py
import time
import pymysql
import urllib.request
import pandasas pd
import requests
import re
from bs4import BeautifulSoup
def get_time():
time_str = time.strftime("%Y{}%m{}%d{} %X")
return time_str.format("年", "月", "日")
def get_conn():
conn = pymysql.connect(host='127.0.0.1', user='root', password='199395', db='stock', charset='utf8')
cursor = conn.cursor()
return conn,cursor
def close_conn(conn,cursor):
cursor.close()
conn.close()
def query(sql,*args):
conn,cursor = get_conn()
cursor.execute(sql,args)
res = cursor.fetchall()
close_conn(conn,cursor)
return res
# def get_be_data(*args):
# sql = "SELECT * FROM hangqing where stockid = %s"
# res = query(sql, args)
# print(res)
# return res[0]
def get_be_data(code):
url ='http://qt.gtimg.cn/q=sh' +str(code)
content = urllib.request.urlopen(url, timeout=2).read()
content = content.decode("gbk").encode("utf-8").decode("utf8", "ignore")
content = content.split('~')
return content
def get_history_data(code):
url ='http://quotes.money.163.com/service/chddata.html?code=0'+str(code)
try:
content = urllib.request.urlopen(url).read()
content = content.decode("gbk").encode("utf-8")
with open('E:/hisdata.csv', 'wb')as f:
f.write(content)
data = pd.read_csv('E:/hisdata.csv')
# data = data.to_dict('record')
data = data[["日期","开盘价","收盘价","最低价","最高价"]]
# print(data)
data = data.to_dict()
data['日期'] =list(data['日期'].values())
data['开盘价'] =list(data['开盘价'].values())
data['收盘价'] =list(data['收盘价'].values())
data['最低价'] =list(data['最低价'].values())
data['最高价'] =list(data['最高价'].values())
data['日期'] = data['日期'][::-1]
data['开盘价'] = data['开盘价'][::-1]
data['收盘价'] = data['收盘价'][::-1]
data['最低价'] = data['最低价'][::-1]
data['最高价'] = data['最高价'][::-1]
except Exception as e:
print(e)
return data
def get_guping(id):
max_page =2 # input('请输入爬取页数')
b = []
# head = {'User-Agent':' Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.116 Safari/537.36'}
for pagein range(1, int(max_page) +1):
url ='http://guba.eastmoney.com/list,{}_{}.html'.format(id, page)
res = requests.get(url)
soup = BeautifulSoup(res.text, 'html.parser')
urllist = soup.find_all('div', {'class':'articleh'})
for iin urllist:
if i.find('a') !=None:
try:
title = i.find('a').get_text()
yuedu = i.find('span',{'class':'l1 a1'}).get_text()
# time = i.find('span', {'class': 'l5 a5'}).get_text()
# a = [title + yuedu]
b.append(title + yuedu)
except Exception as e:
print(e)
pass
return b[7:]
if __name__ =='__main__':
msg = get_guping(600002)
print(msg)