如何使用python通过浏览器下载数据框

Posted

技术标签:

【中文标题】如何使用python通过浏览器下载数据框【英文标题】:How to make a dataframe download through browser using python 【发布时间】:2021-09-02 06:12:14 【问题描述】:

我有一个函数,它在函数末尾生成一个数据框,我将其导出为 Excel 工作表。 df.to_excel('response.xlsx') 这个 excel 文件被保存在我的工作目录中。 现在我将它作为 web 应用程序托管在 heroku 上的 Streamlit 中,但是一旦调用此函数,我希望将这个 excel 文件下载到用户的本地磁盘(普通浏览器下载)中。有什么办法吗?

【问题讨论】:

截至今天,2021 年 6 月 17 日,还没有正式的下载实现。然而。有这个解决方法:github.com/MarcSkovMadsen/awesome-streamlit/blob/master/gallery/… Streamlit 现在支持原生下载blog.streamlit.io/0-88-0-release-notes 【参考方案1】:

来自streamlit 的Snehan Kekre 在this thread 中编写了以下解决方案。


streamlit as st
import pandas as pd
import io

import base64
import os
import json
import pickle
import uuid
import re


def download_button(object_to_download, download_filename, button_text, pickle_it=False):
    """
    Generates a link to download the given object_to_download.
    Params:
    ------
    object_to_download:  The object to be downloaded.
    download_filename (str): filename and extension of file. e.g. mydata.csv,
    some_txt_output.txt download_link_text (str): Text to display for download
    link.
    button_text (str): Text to display on download button (e.g. 'click here to download file')
    pickle_it (bool): If True, pickle file.
    Returns:
    -------
    (str): the anchor tag to download object_to_download
    Examples:
    --------
    download_link(your_df, 'YOUR_DF.csv', 'Click to download data!')
    download_link(your_str, 'YOUR_STRING.txt', 'Click to download text!')
    """
    if pickle_it:
        try:
            object_to_download = pickle.dumps(object_to_download)
        except pickle.PicklingError as e:
            st.write(e)
            return None

    else:
        if isinstance(object_to_download, bytes):
            pass

        elif isinstance(object_to_download, pd.DataFrame):
            #object_to_download = object_to_download.to_csv(index=False)
            towrite = io.BytesIO()
            object_to_download = object_to_download.to_excel(towrite, encoding='utf-8', index=False, header=True)
            towrite.seek(0)

        # Try JSON encode for everything else
        else:
            object_to_download = json.dumps(object_to_download)

    try:
        # some strings <-> bytes conversions necessary here
        b64 = base64.b64encode(object_to_download.encode()).decode()

    except AttributeError as e:
        b64 = base64.b64encode(towrite.read()).decode()

    button_uuid = str(uuid.uuid4()).replace('-', '')
    button_id = re.sub('\d+', '', button_uuid)

    custom_css = f""" 
        <style>
            #button_id 
                display: inline-flex;
                align-items: center;
                justify-content: center;
                background-color: rgb(255, 255, 255);
                color: rgb(38, 39, 48);
                padding: .25rem .75rem;
                position: relative;
                text-decoration: none;
                border-radius: 4px;
                border-width: 1px;
                border-style: solid;
                border-color: rgb(230, 234, 241);
                border-image: initial;
             
            #button_id:hover 
                border-color: rgb(246, 51, 102);
                color: rgb(246, 51, 102);
            
            #button_id:active 
                box-shadow: none;
                background-color: rgb(246, 51, 102);
                color: white;
                
        </style> """

    dl_link = custom_css + f'<a download="download_filename" id="button_id" href="data:application/vnd.openxmlformats-officedocument.spreadsheetml.sheet;base64,b64">button_text</a><br></br>'

    return dl_link


vals= ['A','B','C']
df= pd.DataFrame(vals, columns=["Title"])  

filename = 'my-dataframe.xlsx'
download_button_str = download_button(df, filename, f'Click here to download filename', pickle_it=False)
st.markdown(download_button_str, unsafe_allow_html=True)

我建议在该论坛上搜索主题。这段代码似乎至少有 3-4 种替代方案。

【讨论】:

【参考方案2】:

Mark Madson 在 github 上发布了 this workaround。我从 repo 中取出它并粘贴在这里作为答案。

import base64
import pandas as pd
import streamlit as st
  
def st_csv_download_button(df):
    csv = df.to_csv(index=False) #if no filename is given, a string is returned
    b64 = base64.b64encode(csv.encode()).decode()
    href = f'<a href="data:file/csv;base64,b64">Download CSV File</a>'
    st.markdown(href, unsafe_allow_html=True)  

用法:

st_csv_download_button(my_data_frame)

右击+另存为。

我认为你可以通过 to_excel 而不是 to_csv 来做到这一点。

【讨论】:

以上是关于如何使用python通过浏览器下载数据框的主要内容,如果未能解决你的问题,请参考以下文章

selenium+python自动化80-文件下载(不弹询问框)

Bootstrap 弹出框怎么设置为可拖动

浏览器如何弹出下载框

java下载多个文件浏览器弹出多个下载框

如何从 url 下载文件并使用 python 请求保留其名称和元数据

如何使用来自http url的原始数据在python中下载ms word docx文件