Convert a CURL to Python - HTTPS POST - python

I'm trying to POST some data to an HTTPS server. It requires a very particular set of headers. I'm able to complete the request, but I'm unable to do so in Python.
The curl:
curl -i
-H "Authorization: Basic a2V5OnNlY3JldA=="
-H "Content-Type: application/x-www-form-urlencoded"
-H "Content-Length: 99"
-H "User-Agent: Dalvik/2.1.0 (Linux; U; Android 5.1.1; Nexus 6 Build/LMY48Y)"
-H "Host: test.example.com"
-H "Connection: Keep-Alive"
-H "Content-type: application/json"
-d "grant_type=password&username=me%40example.com&password=abcd*1234&scope=scope1_services+scope1_data"
"https://test.example.com/login/get/token/"
The Python is
import httplib, urllib
host = "test.example.com"
url = "/login/get/token/"
params = urllib.urlencode({"grant_type":"password", "username":"me#example.com", "password":"abcd*1234", "scope":"scope1_services+scope1_data" })
headers = {"Authorization": "Basic a2V5OnNlY3JldA==", "Content-type": "application/x-www-form-urlencoded", "Content-Length":"99", "User-Agent":"Dalvik/2.1.0 (Linux; U; Android 5.1.1; Nexus 6 Build/LMY48Y)", "Host":host, "Connection": "Keep-Alive", "Content-type":"application/json"}
conn = httplib.HTTPSConnection(host)
conn.request("POST", url, params, headers)
response = conn.getresponse()
print response.status, response.reason
I just end up with 400 Bad Request and the error message
{
"error":"unsupported_grant_type",
"error_description":"The authorization grant type is not supported by the authorization server."
}
As far as I can tell, everything should be the same.
I've tried manually encoding the POST payload as params="grant_type=password&user... but I still get the same error.
Any idea what incredibly obvious thing I'm missing?

I think it is actually Content-Type not Content-type. Watch out the capital T there.
Also, I think you can remove these safely from the header:
"Content-Length":"99",
"Host":host,
"Connection": "Keep-Alive",
And, are you sure you need this? You are not posting any json here!
"Content-type":"application/json"

Related

CURL POST with Python

I am trying to POST a multipart/base64 xml file to portal using the following in python. How can i run it in Python?
curl -X POST -H 'Accept: application/xml' -H 'Content-Type: multipart/related; boundary=<boundary_value_that_you_have>; type=text/xml; start=<cXML_Invoice_content_id>' --data-binary #<filename>.xml https://<customer_name>.host.com/cxml/invoices
You can use this website
I got this code. Could you try it ?
import requests
headers = {
'Accept': 'application/xml',
'Content-Type': 'multipart/related; boundary=<boundary_value_that_you_have>; type=text/xml; start=<cXML_Invoice_content_id>',
}
data = open('filename.xml', 'rb').read()
response = requests.post('https://<customer_name>.host.com/cxml/invoices', headers=headers, data=data)

how to make a system curl call from terminal using python?

The call I want to make is this:
curl -i \
-H 'Harvest-Account-ID: 3012210627'\
-H 'Authorization: Bearer 184740.pt.VgNF7lMe1YDTjTH4_nfhm8NiH(qMyRI9kFS4BBvztnLM9P0HNgQvAHnlglnTA9q0wlmtrpoEONHVaT7phZAaNw'\
-H 'User-Agent: Harvest API Example' \
"https://api.harvestapp.com/api/v2/time_entries.json"
but I am not quite sure of how to do this. Any help will be appreciated.
It does not authenticate, because you did not send the JWT Token in HTTP headers:
import requests
headers = {
"Harvest-Account-ID": "380637",
"Authorization": "Bearer 184740.pt.VgNF7mMe1YDTjTH4_nfhm8NiT5IMyRI9kFS4AAvztnLM9P0HNgQvAHnlglnTA9X0wlmtrpoEONHVaT7phZAaNw",
"User-Agent": "Harvest API Example"
}
print (requests.get("https://api.harvestapp.com/api/v2/time_entries.json", headers=headers)
Returns:
<Response [200]>

login with python requests

I want to use Python's requests module to login to the webpage https://www.tennistv.com/login.
I read this post on how to achieve this, however, I get stuck. The payload looks as follows:
payload = {"Email":"[MAIL]","Password":"[PASSWORD]"}
I then start a session as follows:
with requests.Session() as s:
p = s.post('https://www.tennistv.com/api/users/v1/login', data=payload, headers=headers)
# print the html returned or something more intelligent to see if it's a successful login page.
print(p.text)
This yields the following error:
{
"error": {
"validationErrors": [{
"key": "loginModel",
"value": [""]
}],
"errorMessage": "There was an error while validating input data (UR001)",
"errorCode": "UR001",
"userErrorCode": "UR001"
}
}
Even when I copy the request from Chrome's developer console as a cURL command and then execute the cURL command, I get the same error.
The cURL command looks as follows:
curl "https://www.tennistv.com/api/users/v1/login" -H "Pragma: no-cache" -H "Origin: https://www.tennistv.com" -H "Accept-Encoding: gzip, deflate, br" -H "Accept-Language: de-DE,de;q=0.9,en-US;q=0.8,en;q=0.7" -H "User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/64.0.3282.186 Safari/537.36" -H "content-type: application/json" -H "Accept: */*" -H "Cache-Control: no-cache" -H "Referer: https://www.tennistv.com/login" -H "Connection: keep-alive" --data-binary "^{^\^"Email^\^":^\^"[MAIL]^\^",^\^"Password^\^":^\^"[PASS]^\^"^}" --compressed
What am I doing wrong? Where is the difference between the cURL command and the request sent by the browser?
I could resolve this issue. The payload has to look as follows (different quotation marks):
payload = {'Email':'[MAIL]','Password':'[PASSWORD]'}

Python HTTP Request Binary Data using Requests

The following code only works in curl. It would be nice if you could tell me why it isnt working in Python using Requests
curl 'http://cdcnepal.com/Modules/HOmeMoviesLists/WebService2.asmx/GetShowsByDate' \
-H 'Content-Type: application/json; charset=UTF-8' \
-d '{"portalId":"1","showDate":"26/05/2014","flag":0,"size":9}'
However in Python with the following code
import requests
import json
url = """http://cdcnepal.com/Modules/HOmeMoviesLists/WebService2.asmx/GetShowsByDate"""
headers = {"content-type":["application/json", "charset=UTF-8"]}
payload = {"portalId":"1","showDate":"26/05/2014","flag":0,"size":9}
r = requests.get(url, headers=headers, data=payload)
print r.text
Originally the curl request had other content, below, however I realised I could remove several. I'm not sure that is causing the error because the curl request is working. I'm not getting the same response from both the code.
This might be useful. A Curl Requests extracted from Chrome Dev Tools
curl 'http://cdcnepal.com/Modules/HOmeMoviesLists/WebService2.asmx/GetShowsByDate'
-H 'Cookie: OriginalReferrer=https://www.google.com/;
OriginalURL=http://cdcnepal.com/;
ASP.NET_SessionId=i5lbnql5hpp0wm1ywyqbywtj;
VisitCount=4'
-H 'Origin: http://cdcnepal.com'
-H 'Accept-Encoding: gzip,deflate,sdch'
-H 'Accept-Language: en-US,en;q=0.8,hi;q=0.6'
-H 'User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_9_3)
AppleWebKit/537.36 (KHTML, like Gecko) Chrome/35.0.1916.114 Safari/537.36'
-H 'Content-Type: application/json; charset=UTF-8'
-H 'Accept: application/json, text/javascript, */*; q=0.01'
-H 'Referer:http://cdcnepal.com/Home.aspx'
-H 'X-Requested-With: XMLHttpRequest' -H 'Connection: keep-alive'
-H 'DNT: 1'
--data-binary '{"portalId":"1","showDate":"27/05/2014","flag":0,"size":9}' --compressed
The curl -d switch sends a POST request, but you are using requests.get() instead, sending a GET request (whose body is ignored).
Make it a POST instead, by using request.post():
import requests
import json
url = "http://cdcnepal.com/Modules/HOmeMoviesLists/WebService2.asmx/GetShowsByDate"
headers = {"content-type": "application/json; charset=UTF-8"}
payload = {"portalId":"1","showDate":"26/05/2014","flag":0,"size":9}
r = requests.post(url, headers=headers, data=json.dumps(payload))
print r.text
You also need to:
not use a list for the content-type header, there is no support for paramaters being specified separately.
Encode your JSON data to a JSON string; requests doesn't do this for you. Instead, a dictionary passed to data is encoded as application/x-www-form-urlencoded data instead.
You can compare the curl command with requests more easily using http://httpbin.org/post:
$ curl http://httpbin.org/post \
> -H 'Content-Type: application/json; charset=UTF-8' \
> -d '{"portalId":"1","showDate":"26/05/2014","flag":0,"size":9}'
{
"args": {},
"data": "{\"portalId\":\"1\",\"showDate\":\"26/05/2014\",\"flag\":0,\"size\":9}",
"files": {},
"form": {},
"headers": {
"Accept": "*/*",
"Connection": "close",
"Content-Length": "58",
"Content-Type": "application/json; charset=UTF-8",
"Host": "httpbin.org",
"User-Agent": "curl/7.30.0",
"X-Request-Id": "78d7bb7d-e29b-482b-908a-48d2395a050f"
},
"json": {
"flag": 0,
"portalId": "1",
"showDate": "26/05/2014",
"size": 9
},
"origin": "84.92.98.170",
"url": "http://httpbin.org/post"
}
and
>>> import requests
>>> import json
>>> from pprint import pprint
>>> url = 'http://httpbin.org/post'
>>> headers = {"content-type":"application/json; charset=UTF-8"}
>>> payload = {"portalId":"1","showDate":"26/05/2014","flag":0,"size":9}
>>> r = requests.post(url, headers=headers, data=json.dumps(payload))
>>> pprint(r.json())
{u'args': {},
u'data': u'{"portalId": "1", "flag": 0, "size": 9, "showDate": "26/05/2014"}',
u'files': {},
u'form': {},
u'headers': {u'Accept': u'*/*',
u'Accept-Encoding': u'gzip, deflate, compress',
u'Connection': u'close',
u'Content-Length': u'65',
u'Content-Type': u'application/json; charset=UTF-8',
u'Host': u'httpbin.org',
u'User-Agent': u'python-requests/2.2.1 CPython/2.7.6 Darwin/13.1.0',
u'X-Request-Id': u'06d6b542-c279-4898-8701-2c0d502aa36e'},
u'json': {u'flag': 0,
u'portalId': u'1',
u'showDate': u'26/05/2014',
u'size': 9},
u'origin': u'84.92.98.170',
u'url': u'http://httpbin.org/post'}
Both cases show the same json dictionary being returned.
If you are using requests version 2.4.2 or newer, you can also leave the JSON encoding to the library; it'll set the correct Content-Type header too, if you pass in the data to send as the json keyword argument:
import requests
url = "http://cdcnepal.com/Modules/HOmeMoviesLists/WebService2.asmx/GetShowsByDate"
payload = {"portalId":"1","showDate":"26/05/2014","flag":0,"size":9}
r = requests.post(url, json=payload)
print r.text

Convert a curl POST request to Python only using standard library

I would like to convert this curl command to something that I can use in Python for an existing script.
curl -u 7898678:X -H 'Content-Type: application/json' \
-d '{"message":{"body":"TEXT"}}' http://sample.com/36576/speak.json
TEXT is what i would like to replace with a message generated by the rest of the script.(Which is already working reasonable, although I don't think it is following best practices or particularity reliable. - need to find out how to properly learn to program (ie not use google for assembling stuff))
I would like this to work with the standard library if possible.
I would like this to work with the standard library if possible.
The standard library provides urllib and httplib for working with URLs:
>>> import httplib, urllib
>>> params = urllib.urlencode({'apple': 1, 'banana': 2, 'coconut': 'yummy'})
>>> headers = {"Content-type": "application/x-www-form-urlencoded",
... "Accept": "text/plain"}
>>> conn = httplib.HTTPConnection("example.com:80")
>>> conn.request("POST", "/some/path/to/site", params, headers)
>>> response = conn.getresponse()
>>> print response.status, response.reason
200 OK
If you want to execute curl itself, though, you can just invoke os.system():
import os
TEXT = ...
cmd = """curl -u 7898678:X -H 'Content-Type: application/json'""" \
"""-d '{"message":{"body":"%{t}"}}' http://sample.com/36576/speak.json""" % \
{'t': TEXT}
If you're willing to relax the standard-library-only restriction, you can use PycURL. Beware that it isn't very Pythonic (it's pretty much just a thin veneer over libcurl), and I'm not sure how compatible it is with Python 3.
While there are ways to handle authentication in urllib2, if you're doing Basic Authorization (which means effectively sending the username and password in clear text) then you can do all of what you want with a urllib2.Request and urllib2.urlopen:
import urllib2
def basic_authorization(user, password):
s = user + ":" + password
return "Basic " + s.encode("base64").rstrip()
req = urllib2.Request("http://localhost:8000/36576/speak.json",
headers = {
"Authorization": basic_authorization("7898678", "X"),
"Content-Type": "application/json",
# Some extra headers for fun
"Accept": "*/*", # curl does this
"User-Agent": "my-python-app/1", # otherwise it uses "Python-urllib/..."
},
data = '{"message":{"body":"TEXT"}}')
f = urllib2.urlopen(req)
I tested this with netcat so I could see that the data sent was, excepting sort order, identical in both cases. Here the first one was done with curl and the second with urllib2
% nc -l 8000
POST /36576/speak.json HTTP/1.1
Authorization: Basic Nzg5ODY3ODpY
User-Agent: curl/7.19.4 (universal-apple-darwin10.0) libcurl/7.19.4 OpenSSL/0.9.8k zlib/1.2.3
Host: localhost:8000
Accept: */*
Content-Type: application/json
Content-Length: 27
{"message":{"body":"TEXT"}} ^C
% nc -l 8000
POST /36576/speak.json HTTP/1.1
Accept-Encoding: identity
Content-Length: 27
Connection: close
Accept: */*
User-Agent: my-python-app/1
Host: localhost:8000
Content-Type: application/json
Authorization: Nzg5ODY3ODpY
{"message":{"body":"TEXT"}}^C
(This is slightly tweaked from the output. My test case didn't use the same url path you used.)
There's no need to use the underlying httplib, which doesn't support things that urllib2 gives you like proxy support. On the other hand, I do find urllib2 to be complicated outside of this simple sort of request and if you want better support for which headers are sent and the order they are sent then use httplib.
Thanks every
this works
import urllib2
def speak(status):
def basic_authorization(user, password):
s = user + ":" + password
return "Basic " + s.encode("base64").rstrip()
req = urllib2.Request("http://example.com/60/speak.json",
headers = {
"Authorization": basic_authorization("2345670", "X"),
"Content-Type": "application/json",
"Accept": "*/*",
"User-Agent": "my-python-app/1",
},
data = '{"message":{"body":'+ status +'}}')
f = urllib2.urlopen(req)
speak('Yay')
Take a look at pycurl http://pycurl.sourceforge.net/

Categories