-1

Is it possible to run a python script from html code without any limitations

I am trying to create a combo of a webpage and a python script which lets users to scrape a particular website/s and display the information using requests module in python with the python script being executed from my server , in such a way that my webpage being the frontend and the python script being the backend

I tried using php with shell_exec function as shown in this answer but all it shows is a blank screen with the code being unexecuted in my browser

I also tried using pyscript but was unable to import python requests since it's not in their supported packages

shaik moeed
  • 5,300
  • 1
  • 18
  • 54
  • 3
    You could write a little API with FastAPI and create an endpoint that is fired by your client (browser) - you could leave the API running in a Docker container. – mrpbennett Aug 01 '23 at 19:06
  • Please provide enough code so others can better understand or reproduce the problem. – Community Aug 01 '23 at 19:25
  • @mrpbennett can you please share some example code or tutorial/refrences , sorry am currently learning and doesn't know much about api , your help would be greatly appreciated. Thanks for giving time – Ayush Kumar Aug 01 '23 at 23:45
  • See [ask]. I strongly suspect you already know the answer, "It's impossible". It will be a critical security vulnerability if your browser can execute an arbitrary CPython code like ```os.system('gnome-session-quit')``` in a HTML. – relent95 Aug 02 '23 at 05:42

2 Answers2

1

There's a library called Brython (https://brython.info/), it can help you somewhat, but of course consider that there are limitations.

Here's the example of how to send request to HTTP site:

<html>

<head>
    <meta charset="utf-8">
    <script type="text/javascript"
        src="https://cdn.jsdelivr.net/npm/brython@3.11.0/brython.min.js">
    </script>
    <script type="text/javascript"
        src="https://cdn.jsdelivr.net/npm/brython@3.11.0/brython_stdlib.js">
    </script>
</head>

<body onload="brython()">

<script type="text/python">
from browser import ajax
from browser import document

query = ''
url = 'http://www.http2demo.io/'

def get_request(url, q):
    req = ajax.ajax()
    req.bind('complete', on_complete)

    req.open('GET', url+'?'+q, True)
    req.set_header('content-type', 'application/x-www-form-urlencoded')
    req.send()

def on_complete(r):
    if r.status==200 or r.status==0:
       document <= r.text
    else:
        document <= "error: " + r.text

get_request(url, query)
</script>

</body>

</html>

The better approach would be to create microservice, which would consist of front-end (user inputs URL to parse) and back-end (python logic - requests, etc.).

Anton
  • 11
  • 3
0

Sure, I am no pro by any means but this is how I would do it.

# main.py

""" FastAPI endpoint that your front end can call to fire off your script """

from fastapi import FastAPI
from fastapi.middleware.cors import CORSMiddleware

app = FastAPI()

# Adjust your CORS settings as you need too
# https://fastapi.tiangolo.com/tutorial/cors/

origins = [
    "http://localhost.tiangolo.com",
    "https://localhost.tiangolo.com",
    "http://localhost",
    "http://localhost:8080",
]

app.add_middleware(
    CORSMiddleware,
    allow_origins=origins,
    allow_credentials=True,
    allow_methods=["*"],
    allow_headers=["*"],
)


@app.get("/")
async def root():
    return {"message": "I am Root!"}

@app.get("/api/name-your-endpoint")
def some_func():
    # add your script here and pass anything you need as an argument
    pass

With the above, you have a simple endpoint called http://localhost/api/name-your-endpoint for example. This can now be called by anything once it's running. You could use fetch() or useEffect() depending if you're going vanilla JS or React.

Below is the Dockerfile I have used for one of my API projects, this is likely to be different for you but gives you an idea of what to expect. you can find more info here: https://fastapi.tiangolo.com/deployment/docker/

Please bare in mind that this Dockerfile uses pipenv and not standard requirements.txt

# DockerFile

# For more information, please refer to https://aka.ms/vscode-docker-python
FROM python:3.8-slim

EXPOSE 80

# Keeps Python from generating .pyc files in the container
ENV PYTHONDONTWRITEBYTECODE=1

# Turns off buffering for easier container logging
ENV PYTHONUNBUFFERED=1

# Install pip requirements
COPY Pipfile Pipfile.lock ./
RUN python -m pip install --upgrade pip
RUN pip install pipenv && pipenv install --dev --system --deploy

WORKDIR /app
COPY . /app

# Creates a non-root user with an explicit UID and adds permission to access the /app folder
# For more info, please refer to https://aka.ms/vscode-docker-python-configure-containers
RUN adduser -u 5678 --disabled-password --gecos "" appuser && chown -R appuser /app
USER appuser

# During debugging, this entry point will be overridden. For more information, please refer to https://aka.ms/vscode-docker-python-debug
CMD ["uvicorn", "main:app", "--proxy-headers", "--host", "0.0.0.0", "--port", "8080"]

Now for the front end, I would use React if you know it, and build something like this, this will have the user call the end point via a button.

// App.jsx

// This component will use a button in the UI to call the endpoint and populate the data

import { useState } from 'react'

function App() {

   const [data, setData] = useState([])

   const generateDataFromEndpoint = async () => {

   try {
        await fetch(
          `${YOUR-HOST-BASE-URL}/api/api/name-your-endpoint`,
        )
          .then(res => res.json())
          .then(data => {
            setData(data)
            return true
          })
      } catch (error) {
        console.log(error)
      }
     }

      return (
        <> 
          <button onClick={generateDataFromEndpoint()}>Get data</button>
          
          {`display your data by mapping over the returned array`}
          <div>
            {data.map((d) => (
              <div>{d.someDataFromReturnedObject}</div>
            ))}
          </div>
        </>
      )

}

Or you could use something like useEffect() where the client will call the endpoint when the component loads.

// App.jsx

import {useEffect, useState} from 'react'

function App() {
  const [data, setData] = useState([])

  const generateDataFromEndpoint = async () => {
    try {
      await fetch(`${YOUR-HOST-BASE-URL}/api/api/name-your-endpoint`)
        .then(res => res.json())
        .then(data => {
          setData(data)
          return true
        })
    } catch (error) {
      console.log(error)
    }
  }

  useEffect(() => {
    generateDataFromEndpoint()
  }, [])

  return (
    <>
      {`display your data by mapping over the returned array`}
      <div>
        {data.map(d => (
          <div>{d.someDataFromReturnedObject}</div>
        ))}
      </div>
    </>
  )
}

Of if you're using vanilla JS you can just use fetch() like so:

const generateDataFromEndpoint = async () => {
    try {
      await fetch(`${YOUR-HOST-BASE-URL}/api/api/name-your-endpoint`)
        .then(res => res.json())
        .then(data => {
          setData(data)
          return true
        })
    } catch (error) {
      console.log(error)
    }
  }

This might be over kill for what you need but this is how I have done it in the past and works very well. But you would need a way to host and run a Docker container for this to work.

If you are using React you could look at something like Vite.JS and host it on something like Vercel

Below I have included some links for your reference

This is also this SO link How can I run a Python script in HTML?

mrpbennett
  • 1,527
  • 15
  • 40
  • It's not a good idea to answer an unclear and unspecific question like this. – relent95 Aug 04 '23 at 10:46
  • How do you mean, the OP asked how to run a python script from a browser...this is how I would do it – mrpbennett Aug 07 '23 at 10:18
  • The OP said both "python script being executed from my server " and "pyscript". So it's not clear whether he wants running the Python inside a browser(as a javascript or web assembly), or transferring Python source in a HTML form to the server and running on the server, or something else. – relent95 Aug 07 '23 at 10:25
  • Also he said he tried a PHP solution from other question, but he didn't provide a [mre] and debugging details. – relent95 Aug 07 '23 at 10:31