具体思路:

建立一个flask项目,通过界面输入的股票代码,提交到后台以后,根据对应的股票代码去某网站爬取需要的数据,并将数据展示在index.html页面中。

具体操作步骤如下:

  1. 新建一个工程

工程名称为stock如下:

  1. 新建一个文件夹templates,并在文件夹下新建index.html文件

目录结构如下:

  1. 清空main.py文件,在文件中按Ctrl+j,并输入下面的提示词,自动生成代码。

提示词:

创建一个flask项目,判断如果前台提交方法不是post则直接返回index.html,如果提交方法是post,则接收前台提交的stockCode参数,并将取得的参数传入fetch_stock_data函数,将返回的值放入data中,如果data值是None直接返回前台,并错误提示:股票代码错误,无法获取股票数据。调用process_data函数并传入data['Result']['newMarketData']['marketData'][0]['p']参数,将返回值放入processed_data中。并循环读取processed_data值,将第一个元素放入列表1中,将第二个元素放入列表2中。将1到242放入列表3中,并把data,列表1、列表2、列表3作为参数返回前台。编写一个自定义过滤器,将传入的列表进行反转并返回。编写process_data函数,传入一个参数,以;为分隔符进行分割。并循环取出子元素,对子元素以,作为分隔符。并把子元素中第一个元素以空格为分隔符后取第一个元素,子元素的第二个元素,子元素的第三个元素组成一个列表,并将该列表追加到新列表中,作为函数的返回值。建立fetch_stock_data函数传入股票代码,并用股票代码替换网址https://finance.pae.baidu.com/vapi/v1/getquotation?all=1&srcid=5353&pointType=string&group=quotation_minute_ab&market_type=ab&new_Format=1&finClientType=pc&query={stock_code}&code={stock_code}中的stock_code,并爬取该网址的内容,传入headers,如果爬取数据中Result为None,则返回None,如果有值,则返回json数据

下图是自动生成main.py与修改后的main.py文件对比。红色部分为手工修改代码。

  1. 打开templates/index.html文件,按ctrl+j,输入提示词

提示词:

创建一个html页面,标题名称为股票查询界面,页面背景颜色为#F3F5FA。页面布局,创建一个div名称为container,宽900高800,背景颜色#E3E7F6,居中显示边框1px红色。container内部第一行创建一个div名称为div1占满整行边框1px绿色,靠左显示,第二行创建一个div名称为div2,占满整行,边框1px紫色,靠左显示,第三行创建一个div名称div3,占满整行,边框1px黄色靠左显示。第四行创建一个div名称为div4,占满整行,边框1px蓝色。第五行创建一个div名称div5,占满整行边框1px黑色,在div5中创建div名称为div51占整行的75%边框1px粉色,在创建一个div名称div52占整行的24%边框1px橙色。在div1中创建一个form表单并以post方式提交,里面有一个标签名称为股票代码,一个文本框,一个提交按钮。在div2中使用{%if data%}判断,并使用{%if  data.Result.cur.increase|float>=0 %}判断是否大于0,如果大于0则cur.avgPrice、cur.increase和cur.ratio的字体为#FF3333颜色,否则字体颜色为#0AAB62。在后面显示avgPrice(字体大小为25px)、increase和ratio,只显示值不显示标题,如果返回的error有值,则显示在container中间。在div3中判断{% if data %}如果为真,则在div3中显示data.Result.basicinfos中的显示name(字体大小为25px)、code、exchange、tradeStatus四个值显示在一行都使用span标签。在div4中判断{% if data %}是否为真,如果为真循环取出data.Result.pankouinfos.list的元素,判断loop.index-1取5的余数,如果等于0,则添加换行符。显示元素中的name,元素中的status如果值为up则value值为#FF3333,如果为down则value值为#0AAB62,否则,value颜色为黑色,并且name设置固定宽度100px边框1px颜色为红色左浮动和value设置固定宽度85px边框1px绿色左浮动,name左对齐,value右对齐。在div51中使用Chart.js将{{ list1}}设置为横坐标,将{{ list2 }}设置为第一个折线的纵坐标,折线颜色#416DF9,label名称为价格,将{{ list3 }}设置为第二个折线的纵坐标,折线颜色#FAA90E,label名称为均价,并隐藏x轴刻度数据。在div52中如果{% if data %}有值,则循环取出data.Result.askinfos元素,循环展示askprice、askvolume。循环取出data.Result.buyinfos元素使用span标签展示bidprice、bidvolume。循环取出data.Result.detailinfos元素,使用span标签展示formatTime、price、volume、bsFlag(如果bsFlag为B则颜色为#FF3333,如果为S则#0AAB62),只展示10条,并添加竖向滚动条。

自动生成的index.html与修改后的对比如下:

  1. 最终代码

1)、main.py

from flask import Flask, request, render_template
import requests

app = Flask(__name__)

@app.route('/', methods=['GET', 'POST'])
def index():
    data=None
    if request.method != 'POST':
        return render_template('index.html',data=data)
    
    stock_code = request.form.get('stockCode')
    data = fetch_stock_data(stock_code)
    
    if data is None:
        return render_template('index.html', data=None,error="股票代码错误,无法获取股票数据")
    
    processed_data = process_data(data['Result']['newMarketData']['marketData'][0]['p'])
    list1 = []
    list2 = []
    for  item in processed_data:

  
        list1.append(eval(item[1]))

        list2.append(eval(item[2]))    
    list3 = list(range(1, 243))
    
    return render_template('index.html', data=data, list1=list1, list2=list2, list3=list3)


#自制的过滤器,用于反转字符串
def reverse_filter(s):
    return s[::-1]
app.add_template_filter(reverse_filter,'lireverse')
def process_data(data):
    new_list = []
    sub_elements = data.split(';')
    
    for sub in sub_elements:
        items = sub.split(',')
        if len(items) >= 3:
            new_list.append([items[1].split(' ')[1], items[2], items[3]])
    
    return new_list

def fetch_stock_data(stock_code):
    url = f"https://finance.pae.baidu.com/vapi/v1/getquotation?all=1&srcid=5353&pointType=string&group=quotation_minute_ab&market_type=ab&new_Format=1&finClientType=pc&query={stock_code}&code={stock_code}"
    headers = {
                'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.88 Safari/537.36',
                'Cookie':'BIDUPSID=25A7A5A3B1146E8D3BFF1E36733F20CC; PSTM=1721007250; BAIDUID=25A7A5A3B1146E8DADC7CD866B54B1AE:FG=1; BDUSS_BFESS=Q3anVZVjNOWkN1NzR-V3RrOEtXNnlqamlTcXBrckowajIyTm52UGtEWC13NzVtRUFBQUFBJCQAAAAAAAAAAAEAAACdlpJFd2FzYWlfMTk4MjA3MjMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP42l2b-NpdmdV; H_WISE_SIDS_BFESS=60276_60359_60465_60491_60498_60551_60564; delPer=0; PSINO=2; BAIDUID_BFESS=25A7A5A3B1146E8DADC7CD866B54B1AE:FG=1; ZFY=BixeZe8xMy5mbWLmW1MB:A7BwtfD1c2hr5D:BoH9FgmXk:C; BDRCVFR[feWj1Vr5u3D]=I67x6TjHwwYf0; H_PS_PSSID=60276_60359_60564; BA_HECTOR=a02g05a4252lak812l8la10l8jr7j11jb054u1u; H_WISE_SIDS=60276_60359_60564; BDORZ=B490B5EBF6F3CD402E515D22BCDA1598; ab_sr=1.0.1_ZGNkOTE1MzQxYTM0OGZiMTI4OTcxMGUxMjNmYmM4MDE4NzBlMTI3ODJlMDdhMTA2ZmJjNDdmYWU0MmIyNWIyMmQ0ZjkwNGNkNjA4NzE5YWVjODcyYzQ4N2JlNGQ2NWMxZWZkY2U2Njc1NjdmMDRmMWUxYmJjODc4YzYwN2IyOGM5YmI1ZDBlZDQ1YjhjMTJjYTU5YWRhMjBmYjI1MzUwYg==',
    }
    
    response = requests.get(url, headers=headers)
    
    if response.ok:
        json_data = response.json()
        if json_data.get('Result') is None:
            return None
        return json_data
    
    return None

if __name__ == '__main__':
    app.run(debug=True)

2)、templates/index.html

<!DOCTYPE html>
<html lang="zh">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>股票查询界面</title>
    <style>
        body {
            background-color: #F3F5FA;
        }
        #container {
            width: 900px;
            height: 800px;
            background-color: #E3E7F6;
            margin: 0 auto;
            /*border: 1px solid red;*/
        }
        .row {
            width: 100%;
            clear: both;
        }
        #div1, #div2, #div3, #div4, #div5 {
            width: 100%;
            /*border: 1px solid;*/
        }
        #div1 {
            /*border-color: green;*/
        }
        #div2 {
            /* border-color: purple;*/
        }
        #div3 {
            /* border-color: yellow;*/
        }
        #div4 {
            /* border-color: blue;*/
        }
        #div5 {
            /* border-color: black;*/
        }
        #div51 {
            float: left;
            width: 75%;
            /* border: 1px solid pink;*/
        }
        #div52 {
            float: left;
            width: 24%;
            /*border: 1px solid orange;*/
        }
        .pankou-info {
            overflow: hidden;
            margin-bottom: 10px;*/
        }
        .name {
            float: left;
            width: 110px;
            /* border: 1px solid red;*/
            text-align: left;
        }
        .value {
            float: left;
            width: 95px;
            /* border: 1px solid green;*/
            text-align: right;
        }

        #ask-l{
            display: inline-block; /*规定长度*/
            width: 30%;
  
         
            text--align: left;
            float:left;
 
        }
        #ask-r{
            display: inline-block; /*规定长度*/
            width: 20%;
            text-align: right;
            float:left;
        }
        #div521{
            float: left;
            width: 100%;
            margin 0,auto;
           /* border: 1px solid red;*/
        }
        #div51 span{
            /* border: 1px solid orange;*/
             margin-right: 250px;
           
         }
         #div77 {
           
            width: 100%;
            height: 200px;

            overflow-y: scroll;
        }
        #de-l{
            display: inline-block; /*规定长度*/
            width: 25%;
  
         
            text--align: left;
            float:left;
 
        }
        #de-r{
            display: inline-block; /*规定长度*/
            width: 30%;
            text-align: right;
            float:left;
        }
        #de-rr{
            display: inline-block; /*规定长度*/
            width: 15%;
            text-align: right;
            float:left;
        }

    </style>
</head>
<body>
    <div id="container">
        <div id="div1" class="row">
            <form method="post">
                <label for="stockCode">股票代码:</label>
                <input type="text" id="stockCode" name="stockCode">
                <button type="submit">提交</button>
            </form>
        </div>
        <div id="div2" class="row">
            {% if data %}
                <span style="color: {% if data.Result.cur.increase|float >= 0 %}#FF3333{% else %}#0AAB62{% endif %}; font-size: 25px;">{{ data.Result.cur.avgPrice }}</span>
                <span style="color: {% if data.Result.cur.increase|float >= 0 %}#FF3333{% else %}#0AAB62{% endif %};">{{ data.Result.cur.increase }}</span>
                <span style="color: {% if data.Result.cur.increase|float >= 0 %}#FF3333{% else %}#0AAB62{% endif %};">{{ data.Result.cur.ratio }}</span>
            {% endif %}
            {% if  error %}
                <div style="text-align: center;">{{  error }}</div>
            {% endif %}
        </div>
        <div id="div3" class="row">
            {% if data %}
                <span style="font-size: 25px;">{{ data.Result.basicinfos.name }}</span>
                <span>{{ data.Result.basicinfos.code }}</span>
                <span>{{ data.Result.basicinfos.exchange }}</span>
                <span>{{ data.Result.basicinfos.tradeStatus }}</span>
            {% endif %}
        </div>
        <div id="div4" class="row">
            {% if data %}
                {% for info in data.Result.pankouinfos.list %}
                    
                        <span class="name">{{ info.name }}</span>
                        <span class="value" style="color: {% if info.status == 'up' %}#FF3333{% elif info.status == 'down' %}#0AAB62{% else %}black{% endif %};">{{ info.value }}</span>
                    
                    {% if loop.index % 5 == 0 %}
                        <br>
                    {% endif %}
                {% endfor %}
            {% endif %}
        </div>
        <div id="div5" class="row">
            <div id="div51">
                {%if data%}
                <div style="text-align: center;font-size:47px;">分时折线图</div>
                <canvas id="myChart"></canvas>
                <span >09:30</span><span >11:30/13:00</span><span >15:00</span>
                {%endif%}
            </div>
            <div id="div52" class="scrollable">
                <div id='div521'>
                {% if data %}
                    {% for ask in data.Result.askinfos %}
                    <span id='ask-l'>卖{{5-loop.index+1}} </span><span id='ask-l'> {{ask.askprice}}</span> <span id='ask-r'> {{((ask.askvolume|int) /100)|int}}</span>
                    {% endfor %}</div><hr>
                    <div id='div521'>
                    {% for bid in data.Result.buyinfos %}
                    <span id='ask-l'>买{{loop.index}}</span><span id='ask-l'> {{bid.bidprice}}</span> <span id='ask-r'> {{((bid.bidvolume|int)/100)|int}}<br></span>
                    {% endfor %}</div><hr>
                    <div  id='div77'>
                    {% for detail in data.Result.detailinfos|lireverse %}
                    <span id='de-l'> {{detail.formatTime}}</span><span id='de-l'>{{detail.price}}</span><span id='de-r'>{{((detail.volume|int)/100)|int}}</span>
                    <span id='de-rr'>
                        {%if detail.bsFlag=='B' %}
                        <span style ="color:#FF3333">
                        {%elif detail.bsFlag=='S'  %}
                        <span style ="color:#0AAB62">
                         {%endif%}   
                        {{detail.bsFlag}}</span>
                        <br></span>
                    {% endfor %}
                {% endif %}
            </div>
        </div>
    </div>
    <script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
    <script>
        const ctx = document.getElementById('myChart').getContext('2d');
        const myChart = new Chart(ctx, {
            type: 'line',
            data: {
                labels: {{ list3 }},
                datasets: [{
                    label: '价格',
                    data: {{ list1 }},
                    borderColor: '#416DF9',
                    borderWidth: 1,pointRadius: 0,
                    fill: false
                }, {
                    label: '均价',
                    data: {{ list2 }},
                    borderColor: '#FAA90E',
                    borderWidth: 1,pointRadius: 0,
                    fill: false
                }]
            },
            options: {
                scales: {
                    x: {
                        display: false
                    }
                }
            }
        });
    </script>
</body>
</html>
  1. 运行代码展示结果

在终端界面输入python main.py

  1. 展示网页

输入http://127.0.0.1:5000/展示界面如下:

Logo

分享最新、最前沿的AI大模型技术,吸纳国内前几批AI大模型开发者

更多推荐