Im trying to create simple python code that would communicate with 9kw.eu captcha solving service through their api https://www.9kw.eu/api.html#apisubmit-tab. Basically I'm sending base64 encoded image with some keys:values and response from server should be number like: 58952554, but I'm only getting
<response[200]>
Which should mean that the server got my data, but im not getting anything else.
I'm able to get the right result with simple html form:
<form method="post" action="https://www.9kw.eu/index.cgi" enctype="multipart/form-data">
KEY:<br>
<input name="apikey" value="APIKEY"><br>
ACTION<br>
<input name="action" value="usercaptchaupload"><br>
FILE:<br>
<input name="file-upload-01" value="BASE64IMAGEDATAHERE"><br>
TOOL<br>
<input name="source" value="htmlskript"><br>
ROTATE<br>
<input name="rotate" value="1"><br>
Angle<br>
<input name="angle" value="40"><br>
BASE64
<input name="base64" value="1"><br>
Upload:<br>
<input type="submit" value="Upload and get ID">
</form>
This is the python code, which should do the same thing:
import requests
import time
#base64 image encoding
with open("funcaptcha1.png", "rb") as f:
data = f.read()
filekodovany = data.encode("base64")
#captcha uploader
udajepost = {'apikey':'APIKEY','action':'usercaptchaupload','file-upload-01':filekodovany,'source':'pythonator','rotate':'1','angle':'40','base64':'1'}
headers = {'Content-Type':'multipart/form-data'}
r = requests.post('https://www.9kw.eu/index.cgi', data = udajepost)
print(r)
Thanks for any help.
r = requests.post('https://www.9kw.eu/index.cgi', data = udajepost)
Here, r is the whole response object which has many attributes. I guess, you only need r.text. So, you can just use:
print(r.text)
You're looking for the response of the request:
print(r.text)
In this way you'll have the plain text response.
get json output by:
r.json()
and response_code by:
r.status_code
Related
I have a complicated task and for now I don't know reason why things don't work correctly.
So I have 2 services - my Django main server and OCR service. OCR service is built with FastAPI and only takes image, processes it and returns response as JSON with data from image. That's how my fastapi file looks like:
from fastapi import FastAPI, File, UploadFile, Request
import celery_launch
from cleaning_folders import cleaning_folder
from config import save_img_from_form
f_app = FastAPI()
def save_img_from_form(image):
ts = time.time() * 1000
digit = random.randint(0, 9)
file_name = "img_{digit}_{ts}.jpg".format(digit=digit, ts=ts)
with open(os.path.join('temp_img', file_name), 'wb') as buffer:
shutil.copyfileobj(image.file, buffer)
return buffer
#f_app.post("/api/ocr")
async def send_request(image: UploadFile = File(default='Any', media_type='multipart/form-data')):
buffer = save_img_from_form(image)
response = celery_launch.ocr_process(
selected_town='Templates/Chernomorsk',
raw_img_path=buffer.name,
selected_billing_type=1
)
json_response = response.get()
cleaning_folder('temp_img')
return json_response
so save_img_from_form() gets an image object from request and saves it to the disk for next processing. Then celery runs and does all OCR process and then returns a dict.
So when I use Swagger UI as interactive API testing service, it all works, so in Swagger UI I can load my image through html input and then click the button to run my endpoint. And then I get right JSON as response. I also checked the network activity (ctrl+shift+I in Chrome) and in network action, which is linked to my endpoint I see lots of stuff about my request and also form data (image ofc).
But the question is in another. I need to load an image at my Django server and then using requests library send request with this file to FastAPI service. But here I faced with lots of troubles. I have such an html form:
<form method="POST" action="{% url 'send_ocr_form' %}" enctype="multipart/form-data">
{% csrf_token %}
<input type="hidden" name="pk" value="{{pk}}">
<input type="file" id="ocr_image" name="ocr_image" accept=".jpg, .jpeg"><br>
<button type="submit">Recognize</button>
</form>
Hidden field with name="pk" is needed for some service stuff. So for loading an image I have a field with name="ocr_image".
My view for this form is:
def send_ocr_bill_form(request):
image = request.FILES['ocr_image'].temporary_file_path()
ocr_response = send_ocr_bill(image=image)
files = {'file': open(image, 'rb')}
ocr_response = requests.post('http://127.0.0.1:5005/api/ocr', files=files)
print(ocr_response.json())
return redirect(request.META.get('HTTP_REFERER', '/accounts/profile_page/'))
It's not the full functionality of this view, it just not ended because of current trouble.
So when I send my form with image FastAPI uses default='Any' as an image variable, so that means that there are no files in request. And when I check network I also don't see 'form data' block in my request. So it seems like I don't send image. But in my view I can easily get and print an object from request.FILES, see its name and temporary path, so that means that I load image and send it in my request.
And interesting fact. When I delete my file input and leave only csrf token and pk hidden input and then submit form, in my request in network I can see form data and then get my "pk" in a view. But when I return file input, form data block disappears.
So many hours spent to solve the issue and answer was so easy.
Well, my fail was with requests library.
Let's look at my FastAPI's endpoint first string:
async def send_request(image: UploadFile = File(default='Any', media_type='multipart/form-data')):
So i define 'image' as an UploadFile object, and of course my endpoint waits for a file in request, but when I send image in a Django view I do this:
files = {'file': open(image, 'rb')}
ocr_response = requests.post('http://127.0.0.1:5005/api/ocr', files=files)
So in 'files' variable I also use 'file' key to assign image to it.
And all I needed to change is:
files = {'image': open(image, 'rb')}
ocr_response = requests.post('http://127.0.0.1:5005/api/ocr', files=files)
Now when FastAPI endpoint gets a request, it takes image argument from the right place and then I can do all stuff with it.
I have a .html file where I am sending a value using the submit button as follows:
<HTML>
<HEAD>
<TITLE>XYZ Ltd.</TITLE>
</HEAD>
<BODY>
<FORM ACTION="http://192.168.2.2/cgi-bin/http_recv.cgi" METHOD="POST">
<TEXTAREA NAME="DATA_SEND" COLS='160' ROWS='40' WRAP='none'>
</TEXTAREA>
<INPUT TYPE="SUBMIT" VALUE="Send Data">
</FORM>
</BODY>
</HTML>
I did go through selenium and from my understanding it doesn't suit me. I would like to have a .html as above and maintain it, so it has to be opened and clicked. A cgi/python example did come into my notice but I would go for it only if there is no other alternative.
How can I use python to:
Open the .html file and
Press the "Send Data" button
Read any response given (assuming the response maybe displayed within a HTML page or a dialog box)
Python code for sending Data
`def hello():
Dict={'Title': 'This is title','Subtitle':'subtitle'}
return render_template('hello.html',Dict=Dict)`
Code for writing values which is passed from python as dictionary into HTML
`<form accept-charset="utf-8" class="simform" method="POST"
enctype=multipart/form-data>
Title <input type="text" name="Title" value="{{ Dict.get('Title')
}}" maxlength="36">
SubTitle <input type="text" name="SubTitle" value="{{
Dict.get('SubTitle') }}" maxlength="70">
<button type="submit" class="save btn btn-default">Submit</button>
</form>`
I believe this is exactly what you are looking for .Its a simple python server with the baseHttpHandler of Python.
class S(BaseHTTPRequestHandler):
def _set_headers(self):
self.send_response(200)
self.send_header('Content-type', 'text/html')
self.end_headers()
def do_GET(self):
self._set_headers()
self.wfile.write("<html><body><h1>hi!</h1></body></html>")
def do_HEAD(self):
self._set_headers()
def do_POST(self):
# Doesn't do anything with posted data
self._set_headers()
self.wfile.write("<html><body><h1>POST!</h1></body></html>")
def run(server_class=HTTPServer, handler_class=S, port=80):
server_address = ('', port)
httpd = server_class(server_address, handler_class)
print 'Starting httpd...'
httpd.serve_forever()
You can run the code by passing an appropriate port of your choice to run method or the default 80 will be used. To test this or to do a get or post , you could run a curl as follows:
Send a GET request:: curl http://localhost
Send a HEAD request:: curl -I http://localhost
Send a POST request:: curl -d "foo=bar&bin=baz" http://localhost
You could also create a seperate file of index.html and read using the codecs in python. Since the input would be string , it could be tampered with , eventually displaying the desired page.
Use flask to host your HTML Page and use a POST request to send data to and from your python script.
This link should help you more :
https://www.tutorialspoint.com/flask/index.htm
"Clicking" a button is nothing more than a POST request with the form data in the body.
If you need something generic, you would have to parse the HTML, find what data the host accepts and POST it.
But if you just need this for this example, meaning, you already know the data the server accepts, you can just forget about the HTML and just use something like requests to post the data
I've taken the below code from the Tornado server documentation and attempted to try it out but instead I keep getting the error
object has no attribute 'get_body_argument'
class MyFormHandler(RequestHandler):
def get(self):
self.write('<html><body><form action="/myform" method="POST">'
'<input type="text" name="message">'
'<input type="submit" value="Submit">'
'</form></body></html>')
def post(self):
self.set_header("Content-Type", "text/plain")
self.write("You wrote " + self.get_body_argument("message"))
Any help appreciated.
All it needed was my installation of Tornado had to be upgraded.
I have a javascript method that reads the input file submitted via a form and tries to post its data to a flask url, which is supposed to read the posted data and return it with some amendments.
The HTML part:
<form id="form_1">
<input type="file" name="file_1" id="file_1">
<input type="submit" value="submit" id="regan">
</form>
The JS part:
$("#form_1").submit(function(e){
e.preventDefault(e);
var reader = new FileReader();
var line_data = $('#file_1').get(0);
if (line_data.files.length) {
var input_file = line_data.files[0];
reader.readAsText(input_file);
$(reader).on('load', function(e){
data_line = e.target.result;
$.ajax({
url:'url/validate/',
type:'POST',
data:{akey: data_line},
success:function(returned_data){console.log(returned_data);},
error:function(){console.log('sorry...');}
});
});
}
});
The Flask/Python part:
#app.route('/validate_line/')
def validate_line_data():
try:
data = request.form['akey']
except:
data = 'bad'
data = str(data)
return data+'was_received'
So far, its reading the submitted text file successfully in javascript, but it seems like its not posting via the ajax post method and giving an error url/validate/ 405 (METHOD NOT ALLOWED).
Any help would be great. Thanks.
For Flask to accept POST requests, you need to specify so in the decorator:
#app.route('/validate_line/', methods=['POST'])
If you want it to accept GET requests as well, change to
['GET', 'POST']
I am trying to upload a extract the response of a site based on the file that upload to file. Site has the following form.
<html>
<head>
<meta http-equiv="content-type" content="text/html; charset=ISO-8859-1">
</head>
<body>
<form method="POST" action="http://somewebsite.com/imgdigest" enctype="multipart/form-data">
quality:<input type="text" name="quality" value="2"><br>
category:<input type="text" name="category" value="1"><br>
debug:<input type="text" name="debug" value="1"><br>
image:<input type="file" name="image"><br>
<input type="submit" value="Submit">
</form>
</body>
</html>
What I want to do is upload a file, submit the form and extract the response.
I started by looking at an example, I think I successfully manage to get the upload work. Because when I ran this I didn't get any errors.
import urllib2_file
import urllib2
import request
import lxml.html as lh
data = {'name': 'image',
'file': open('/user/mydir/21T03NAPE7L._AA75_.jpg')
}
urllib2.urlopen('http://localhost/imgdigestertest.html', data)
Unfortunately I am not doing a request here to get the response back. I am not sure how I should do that response. Once I get the response I should be able to extract the data with some pattern match which I am comfortable off.
Based on the answer provided tried the following code:
import requests
url = 'http://somesite.com:61235/imgdigest'
files = {'file': ('21e1LOPiuyL._SL160_AA115_.jpg',
open('/usr/local/21e1LOPiuyL._SL160_AA115_.jpg', 'rb'))}
other_fields = {"quality": "2",
"category": "1",
"debug": "0"
}
headers={'content-type': 'text/html; charset=ISO-8859-1'}
response = requests.post(url, data=other_fields, files=files, headers=headers)
print response.text
now I get the following error: which tells me that some how image file doesn't get attached correctly. Do we have to specify the file type?
Image::Image(...): bufSize = 0. Can not load image data. Image size = 0. DigestServiceProvider.hpp::Handle(...) |
Use the requests library (pip install requests, if you use pip).
For their example, see here:
http://docs.python-requests.org/en/latest/user/quickstart/#post-a-multipart-encoded-file
To customize that to look like yours:
import requests
url = 'http://localhost:8080/test_meth'
files = {'file': ('21T03NAPE7L._AA75_.jpg',
open('./text.data', 'rb'))}
other_fields = {"quality": "2",
"category": "1",
"debug": "1"
}
response = requests.post(url, data=other_fields, files=files)
print response.text
On my local system, text.data contains this:
Data in a test file.
I wrote a server.py with cherrypy (pip install cherrypy) to test the client I gave above. Here is the source for the server.py:
import cherrypy
class Hello(object):
def test_meth(self, category, debug, quality, file):
print "Form values:", category, debug, quality
print "File name:", file.filename
print "File data:", file.file.read()
return "More stuff."
test_meth.exposed = True
cherrypy.quickstart(Hello())
When I run the above client.py, it prints:
More stuff.
which as you can see in the server.py example is what is returned.
Meanwhile, the server says:
Form values: 1 1 2
File name: 21T03NAPE7L._AA75_.jpg
File data: Data in a test file.
127.0.0.1 - - [14/Jul/2012:00:00:35] "POST /test_meth HTTP/1.1" 200 11 "" "python-requests/0.13.3 CPython/2.7.3 Linux/3.2.0-26-generic"
Thus, you can see that the client is posting the filename as described in the code and the file contents of the specified local file.
One thing to point out, at the beginning of this post I said to use the requests library. This is not to be confused with with the urllib request that you are importing in your original question.