Download HTML file from s3

I have created a Streamlit application and deployed it on Streamlit community cloud. I have added a functionality to download files from s3 (I have html file to download). I have created a button, on clicking of the button calling s3_client.download_file() function to download file but file download in cloud server, I want to download it to my system. Need some functionality to download it through browser. How to achieve it?

Use this code and specify the path of the file then after

with open('Resume.html', 'rb') as f:
            st.download_button('Download resume', f, file_name='file.html')

I have file stored in s3 bucket, so need to read it and download to my system. No able to do it

One easy way is to use Presigned URLs - Boto3 1.28.34 documentation and just give the user a link to click.

If you don’t want to do that, you could use something like S3Fs — S3Fs 2023.6.0+6.gb1d9880.dirty documentation to download the file to a variable in python, and then use st.download_button

1 Like

You could do this process in 2 steps:

First, download your file from your s3 bucket, saving it in a temporal foldre

import boto3
import os
import streamlit as st

temp_folder = "tmp_s3_files/"

if not os.path.exists(temp_folder):
       os.makedirs(temp_folder)


s3 = boto3.client('s3', aws_access_key_id=ACCESS_KEY, 
                   aws_secret_access_key=SECRET_KEY)

s3.download_file(Bucket = 'BUCKET_NAME', 
                 File_name = f"{temp_folder}file.html", 
                 Key = 'file.html')

Then, your file.html (and any type of files) will be saved on your temporal folder. After that, you can use the Streamlit download button functionality.

#Download your file
with open(f"{temp_folder}file.html", "rb") as f:
        st.download_button("Download your s3 file", f, "file.html")

#Delete your temp folder and all the content if you want

rmv_tmp = st.button("Remove my temporal folder")
if rmv_tmp:
     shutil.rmtree(temp_folder)

I hope that this approach is what you’re looking for, at least it worked for me :grin:.

1 Like

Hello @Ashish_Kamboj,

To enable users to download files to their local system through the browser in a Streamlit application, you’ll need to follow a process that involves streaming the file from S3 to the client’s browser directly, rather than downloading the file to the server where your app is hosted.

import streamlit as st
import boto3
from botocore.exceptions import NoCredentialsError
import io

# AWS S3 credentials
AWS_ACCESS_KEY_ID = 'your_access_key'
AWS_SECRET_ACCESS_KEY = 'your_secret_key'
REGION_NAME = 'your_region'

# S3 Bucket and File Details
BUCKET_NAME = 'your_bucket_name'
FILE_KEY = 'path/to/your/file.html'

# Create an S3 client
s3_client = boto3.client('s3', region_name=REGION_NAME,
                         aws_access_key_id=AWS_ACCESS_KEY_ID,
                         aws_secret_access_key=AWS_SECRET_ACCESS_KEY)

def get_s3_file(bucket_name, file_key):
    """
    Fetches a file from S3 and returns it as a bytes object.
    """
    try:
        obj = s3_client.get_object(Bucket=bucket_name, Key=file_key)
        return obj['Body'].read()
    except NoCredentialsError:
        st.error("AWS S3 credentials are not configured properly.")
        return None
    except Exception as e:
        st.error(f"Failed to fetch file from S3: {e}")
        return None

def download_link(object_to_download, download_filename, download_link_text):
    """
    Generates a link to download the given object stored in memory.
    """
    if object_to_download is not None:
        # Create a download button for the object
        b64 = base64.b64encode(object_to_download).decode()
        href = f'<a href="data:file/html;base64,{b64}" download="{download_filename}">{download_link_text}</a>'
        st.markdown(href, unsafe_allow_html=True)
    else:
        st.error("No file to download.")

if st.button('Download HTML File from S3'):
    file_to_download = get_s3_file(BUCKET_NAME, FILE_KEY)
    if file_to_download:
        # Use Streamlit's download button to enable file download
        st.download_button(label="Download HTML File",
                           data=file_to_download,
                           file_name="downloaded_file.html",
                           mime="text/html")