I have a usecase where while browsing a website in some of webpage there is a button. I want to overload the function to actually run my local python script instead of going with href link(pointing to some page on server)
I have three solution -
Repeated polling to check if button is clicked or not. Whenever it get's clicked I will call the required function. This is certainly not a good idea as it will reduce browser speed.
Overriding the button function in source code.
Creating a new button for all pages which will call the function only if the actual button is also present in page (otherwise we will show that 'This action can't be performed for this page')
I think 2 and 3 would be better if they could be done but I couldn't get much resources on google. Any link/answer on how can this be done would be of great help.
The easiest way to do this is probably to run a Python Web server on the local machine, which runs your Selenium code when it receives a particular HTTP request. You could write your server like this using Flask, for example:
from flask import Flask, abort
app = Flask(__name__)
#app.route('/dosomestuff', methods=['POST'])
def display():
# Check that the request is coming from t
if request.remote_addr != '127.0.0.1':
abort(403)
do_some_stuff() # Call whatever code you want to run here
return "Done"
if __name__ == '__main__':
app.run()
(Using Flask is probably overkill here, and you could probably do it without a library, but Flask is the method I'm most familiar with.)
Then on your Web page you'd just set up a button to send the appropriate request:
<form action="http://localhost:8080/dosomestuff" method="post">
<input type="submit" value="Do some stuff">
</form>
Then, so long as your local server is running at the time, clicking the button should trigger your Python code.
Step 2 can be done by using chrome/firefox extension. It is not possible to do it with Selenium because it requires editing DOM.
This link might be helpful.
Related
I finally made a project that I wanted to make since a long time :
I'm using an Arduino Uno to replace my PC power button (with a simple relay) and that Arduino Board is connected to a Raspi 3 for network connection purposes
My wish is to do a webpage (or a API-Like request) that at a touch of a button (preferably in a password-protected page) It'll power the PC on
I know how to code in Python, and my script to control the Arduino is already done but I can't find a way to run, only server-side, a Python Script from a button in a webpage
I found that CherryPy framework but I don't think it'll suit my needs
Can someone give me any ideas about that please?
As already mentioned by #ForceBru, you need a python webserver.
If this can be useful to you, this is a possible unsecure implementation using flask:
from flask import Flask
from flask import request
app = Flask(__name__)
#app.route('/turnOn')
def hello_world():
k = request.args.get('key')
if k == "superSecretKey":
# Do something ..
return 'Ok'
else:
return 'Nope'
If you put this in an app.py name file and, after having installed flask (pip install flask), you run flask run you should be able to see Ok if visiting the url http://localhost:5000/turnOn?key=superSecretKey .
You could write a brief html gui with a button and a key field in a form but I leaves that to you (you need to have fun too!).
To avoid potential security issues you could use a POST method and https.
Look at the flask documentation for more infos.
As far as I know Bottle when used with CherryPy server should behave multi-threaded. I have a simple test program:
from bottle import Bottle, run
import time
app = Bottle()
#app.route('/hello')
def hello():
time.sleep(5)
#app.route('/hello2')
def hello2():
time.sleep(5)
run(app, host='0.0.0.0', server="cherrypy", port=8080)
When I call localhost:8080/hello by opening 2 tabs and refreshing them at the same time, they don't return at the same time but one of them is completed after 5 seconds and the other is completed after 5 more seconds.
But when I call /hello in one tab and /hello2 in another at the same time they finish at the same time.
Why does Bottle not behave multi-threaded when the same end-point is called twice? Is there a way to make it multi-threaded?
Python version: 2.7.6
Bottle version: 0.12.8
CherryPy version: 3.7.0
OS: Tried on both Ubuntu 14.04 64-Bit & Windows 10 64-Bit
I already met this behaviour answering one question and it had gotten me confused. If you would have searched around for related questions the list would go on and on.
The suspect was some incorrect server-side handling of Keep-Alive, HTTP pipelining, cache policy or the like. But in fact it has nothing to do with server-side at all. The concurrent requests coming to the same URL are serialised because of a browser cache implementation (Firefox, Chromium). The best answer I've found before searching bugtrackers directly, says:
Necko's cache can only handle one writer per cache entry. So if you make multiple requests for the same URL, the first one will open the cache entry for writing and the later ones will block on the cache entry open until the first one finishes.
Indeed, if you disable cache in Firebug or DevTools, the effect doesn't persist.
Thus, if your clients are not browsers, API for example, just ignore the issue. Otherwise, if you really need to do concurrent requests from one browser to the same URL (normal requests or XHRs) add random query string parameter to make request URLs unique, e.g. http://example.com/concurrent/page?nocache=1433247395.
It's almost certainly your browser that's serializing the request. Try using two different ones, or better yet a real client. It doesn't reproduce for me using curl.
I'm running a website for personal use using Bottle, a simple web server for python.
I'm using this API to get market data from yahoo finance.
This is a simplified version of my script (my first script with Python, btw) with comments explaining how it works. I hope this is understandable:
EDIT: Don't know if I made it clear but not all the code is here, I took a lot out because in this case it is irrelevant.
from bottle import route, run, template
from yahoo_finance import Share
#Using AAPL and FB as an example..
# Gets market data
AAPL = Share('AAPL')
FB = Share('FB')
# Does a whole bunch of things with the data that eventually makes readable portfolio percentages..
# This is SUPPOSED to be a function that refreshes the data so that when called in the template it has up to date data.
# Refresh market data..
def refreshAll():
AAPL.refresh()
FB.refresh()
#Basically this just has a bunch of lines that refreshes the data for every symbol
# Makes it accessible to my template..
# Variables changed to make it understandable..
my_dict = {'holdings': printTotalHoldings, 'day_change': PercentDayChange, 'total_change': PercentTotalChange, 'date': date}
# This is supposed to make the function accessible by the view. So when I call it, it refreshes the data. Doesn't seem to work though..
my_dict['refresh'] = refreshAll
# Makes the template routed to root directory.
#route('/')
def index():
# Template file index.tpl.. **my_dict makes my variables and functions work on the view.
return template('index', **my_dict)
# Starts the webserver on port 8080
if __name__ == '__main__':
port = int(os.environ.get('PORT', 8080))
run(host='0.0.0.0', port=port, debug=True)
So that's basically what my index.py file looks like.
This is what I have in my template on the top of the page. I would think that each time the page is viewed it refreshes the data, right?
% refresh() #Refreshes market data
Then to call the variables with the data I just put something like this in place of where it should go in the HTML:
<p class="day_change">Today's Change: <span id="price">{{get('day_change')}}</span></p>
That all works fine except the data never changes. In order to actually refresh data I have to stop and start my script on the server.
Does this make sense? So my question is, how can I get my data to refresh without stopping and restarting my script every time?
Thanks! Please let me know if something doesn't make enough sense. I've been having trouble with this for a bit.
If you're not in DEBUG mode, then Bottle is caching your rendered template.
Couple of things:
Turn debug mode on and see if that helps. bottle.debug(True) before you run the server. (EDIT: I hadn't noticed earlier that you're already using debug mode. Leaving this item here anyway for reference.)
Do not call refresh() (or any other state-changing or blocking functions) from within your template. It's bad idea. As totowtwo suggested, you should call it from index before you invoke the template.
#route('/')
def index():
refresh()
return template('index', **my_dict)
Print out the value of AAPL et al. after you call refresh() but before you invoke the template, to confirm that they're being updated as you expect.
#route('/')
def index():
refresh()
# print the value of AAPL here, to confirm that it's updated
return template('index', **my_dict)
How does your template have access to AAPL and FB, anyway? Where are they being passed?
Call the refresh code within index(), before you return.
I currently have a Flask web server that pulls data from a JSON API using the built-in requests object.
For example:
def get_data():
response = requests.get("http://myhost/jsonapi")
...
return response
#main.route("/", methods=["GET"])
def index():
return render_template("index.html", response=response)
The issue here is that naturally the GET method is only run once, the first time get_data is called. In order to refresh the data, I have to stop and restart the Flask wsgi server. I've tried wrapping various parts of the code in a while True / sleep loop but this prevents werkzeug from loading the page.
What is the most Pythonic way to dynamically GET the data I want without having to reload the page or restart the server?
You're discussing what are perhaps two different issues.
Let's assume the problem is you're calling the dynamic data source, get_data(), only once and keeping its (static) value in a global response. This one-time-call is not shown, but let's say it's somewhere in your code. Then, if you are willing to refresh the page (/) to get updates, you could then:
#main.route("/", methods=['GET'])
def index():
return render_template("index.html", response=get_data())
This would fetch fresh data on every page load.
Then toward the end of your question, you ask how to "GET the data I want without having to reload the page or restart the server." That is an entirely different issue. You will have to use AJAX or WebSocket requests in your code. There are quite a few tutorials about how to do this (e.g. this one) that you can find through Googling "Flask AJAX." But this will require an JavaScript AJAX call. I recommend finding examples of how this is done through searching "Flask AJAX jQuery" as jQuery will abstract and simplify what you need to do on the client side. Or, if you wish to use WebSockets for lower-latency connection between your web page, that is also possible; search for examples (e.g. like this one).
To add to Jonathan’s comment, you can use frameworks like stimulus or turbo links to do this dynamically, without having to write JavaScript in some cases as the frameworks do a lot of the heavy lifting. https://stimulus.hotwired.dev/handbook/origin
I am writing an application in Pylons that relies on the output of some system commands such as traceroute. I would like to display the output of the command as it is generated rather than wait for it to complete and then display all at once.
I found how to access the output of the command in Python with the answer to this question:
How can I perform a ping or traceroute in python, accessing the output as it is produced?
Now I need to find a way to get this information to the browser as it is being generated. I was planning on using jQuery's loadContent() to load the output of a script into a . The problem is that Pylons controllers use return so the output has to be complete before Pylons renders the page and the web server responds to the client with the content.
Is there any way to have a page display content as it is generated within Pylons or will this have to be done with scripting outside of Pylons?
Basically, I'm trying to do something like this:
http://network-tools.com/default.asp?prog=trace&host=www.bbc.co.uk
pexpect will let you get the output as it comes, with no buffering.
To update info promptly on the user's browser, you need javascript on that browser sending appropriate AJAX requests to your server (dojo or jquery will make that easier, though they're not strictly required) and updating the page as new responses come -- without client-side cooperation (and JS + AJAX is the simplest way to get that cooperation), there's no sensible way to do it on the server side alone.
So the general approach is: send AJAX query from browser, have server respond as soon as it has one more line, JS on the browser updates contents then immediately sends another query, repeat until server responds with an "I'm all done" marker (e.g. an "empty" response may work for that purpose).
You may want to look at this faq entry. Then with JS, you always clear the screen before writing new stuff.
I haven't tried it with pylons, but you could try to show the output of the slow component in an iframe on the page (using mime type text/plain) and yield each chunk to the iframe as it is generated. For fun I just put this together as a
WHIFF demo. Here is the slowly generated web content wsgi application:
import time
def slow(env, start_response):
start_response("200 OK", [('Content-Type', 'text/plain')])
return slow_generator()
def slow_generator():
yield "slowly generating 20 timestamps\n"
for i in range(20):
yield "%s: %s\n" % (i, time.ctime())
time.sleep(1)
yield "done!"
__wsgi__ = slow
This file is deployed on my laptop at: http://aaron.oirt.rutgers.edu/myapp/root/misc/slow.
Here is the WHIFF configuration template which includes the slow page in an
iframe:
{{env whiff.content_type: "text/html"/}}
Here is an iframe with slowly generated content:
<hr>
<iframe frameborder="1" height="300px" width="300px" scrolling="yes"
style="background-color:#99dddd;"
src="slow"
></iframe>
<hr>
Isn't that cool?
This is deployed on my laptop at http://aaron.oirt.rutgers.edu/myapp/root/misc/showSlowly.
hmmm. I just tried the above link in safari and it didn't work right... apparently there are some browser differences... Seems to work on Firefox at least...