How to send a HTTP POST with Python 2.7 - python

I'm trying to send a HTTP POST request with Python. I can get it to work with 3.0, but I couldn't find a good example on 2.7.
hdr = {"content-type": "application/json"}
payload= ("<html><body><h1>Sorry it's not Friday yet</h1> </body></html>")
r = requests.post("http://my-url/api/Html", json={"HTML": payload})
with open ('c:/temp/a.pdf', 'wb') as f:
b64str = json.loads(r.text)['BinaryData'] #base 64 string is in BinaryData attr
binStr = binascii.a2b_base64(b64str) #convert base64 string to binary
f.write(binStr)
The api takes a json in this format:
{
HTML : "a html string"
}
and returns a json in this format:
{
BinaryData: 'base64 encoded string'
}

In Python 2.x it should be like this
import json
import httplib
body =("<html><body><h1>Sorry it's not Friday yet</h1> </body></html>")
payload = {'HTML' : body}
hdr = {"content-type": "application/json"}
conn = httplib.HTTPConnection('my-url')
conn.request('POST', '/api/Html', json.dumps(payload), hdr)
response = conn.getresponse()
data = response.read() # same as r.text in 3.x

The standard way is with the urllib2 module
from urllib import urlencode
import urllib2
def http_post(url, data):
post = urlencode(data)
req = urllib2.Request(url, post)
response = urllib2.urlopen(req)
return response.read()

Related

API POST Call throws 401 error when used pytest

I am performing the API Testing and using the pytest framework. Test is failing all the time with 401 error. Couldn't figure out what was the issue.
Here is the code :
import requests
import json,jsonpath
import urllib3
import constants
urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
# variables
dumpFile = "somepath"
url = "someUrl"
headers = {'Authorization' : constants.consts['siteToken'],
'accept':'application/json',
'content-type':'application/json'}
#siteToken = 'Bearer jwt token'
# read json input file
input_file = open("json file path", 'r')
json_input = input_file.read()
request_json = json.loads(json_input)
# make POST request with JSON Input Body
r = requests.post(url, request_json, headers=headers)
# Verification of the response
assert r.status_code == 200
def test_json_result():
# fetch header from response
print(r.headers.get("Date"))
# parse response to JSON Format
response_json = json.loads(r.text)
# validate response using Json Path
name = jsonpath.jsonpath(response_json, 'name')
print(name)
I solved this by just putting json=your_payload.
import requests
import json,jsonpath
import urllib3
import constants
urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
# variables
dumpFile = "somepath"
url = "someUrl"
headers = {'Authorization' : constants.consts['siteToken'],
'accept':'application/json',
'content-type':'application/json'}
#siteToken = 'Bearer jwt token'
# read json input file
input_file = open("json file path", 'r')
json_input = input_file.read()
request_json = json.loads(json_input)
def test_json_result():
# make POST request with JSON Input Body
r = requests.post(url, json=request_json, headers=headers)
# Verification of the response
assert r.status_code == 200
# fetch header from response
print(r.headers.get("Date"))
# parse response to JSON Format
response_json = json.loads(r.text)
# validate response using Json Path
name = jsonpath.jsonpath(response_json, 'name')
print(name)

Equivalent Python code for the following Java http get requests

I am trying to convert the following Java code to Python. Not sure what I am doing wrong, but I end up with an internal server error 500 with python.
Is the "body" in httplib.httpConnection method equivalent to Java httpentity?
Any other thoughts on what could be wrong?
The input information I collect is correct for sure.
Any help will be really appreciated. I have tried several things, but end up with the same internal server error.
Java Code:
HttpEntity reqEntitiy = new StringEntity("loginTicket="+ticket);
HttpRequestBase request = reMethod.getRequest(uri, reqEntitiy);
request.addHeader("ticket", ticket);
HttpResponse response = httpclient.execute(request);
HttpEntity responseEntity = response.getEntity();
StatusLine responseStatus = response.getStatusLine();
Python code:
url = serverURL + "resources/slmservices/templates/"+templateId+"/options"
#Create the request
ticket = ticket.replace("'",'"')
headers = {"ticket":ticket}
print "ticket",ticket
reqEntity = "loginTicket="+ticket
body = "loginTicket="+ticket
url2 = urlparse.urlparse(serverURL)
h1 = httplib.HTTPConnection(url2.hostname,8580)
print "h1",h1
url3 = urlparse.urlparse(url)
print "url path",url3.path
ubody = {"loginTicket":ticket}
data = urllib.urlencode(ubody)
conn = h1.request("GET",url3.path,data,headers)
#conn = h1.request("GET",url3.path)
response = h1.getresponse()
lines = response.read()
print "response.status",response.status
print "response.reason",response.reason
You don't need to go this low level. Using urllib2 instead:
import urllib2
from urllib import urlencode
url = "{}resources/slmservices/templates/{}/options".format(
serverURL, templateId)
headers = {"ticket": ticket}
params = {"loginTicket": ticket}
url = '{}?{}'.format(url, urlencode(params))
request = urllib2.Request(url, headers=headers)
response = urllib2.urlopen(request)
print 'Status', response.getcode()
print 'Response data', response.read()
Note that the parameters are added to the URL to form URL query parameters.
You can do this simpler still by installing the requests library:
import requests
url = "{}resources/slmservices/templates/{}/options".format(
serverURL, templateId)
headers = {"ticket": ticket}
params = {"loginTicket": ticket}
response = requests.get(url, params=params, headers=headers)
print 'Status', response.status
print 'Response data', response.content # or response.text for Unicode
Here requests takes care of URL-encoding the URL query string parameters and adding it to the URL for you, just like Java does.

python urllib2 post request [duplicate]

This question already has answers here:
Is there any way to do HTTP PUT in python
(14 answers)
Closed 9 years ago.
Is it posisble to adapt this piece of code for make put request:
#!/usr/bin/python
import urllib2, base64, urllib
dir="https://domain.com/api/v1/"
use="one#two.com"
pas="123456"
base64string = base64.encodestring('%s:%s' % (use, pas)).replace('\n', '')
request = urllib2.Request(dir, headers={"Authorization" : "Basic %s" % base64string})
response = urllib2.urlopen(request).read()
print response
I try with this other code, but I think that it do a get request, isn't it?
#!/usr/bin/python
import urllib2, base64, urllib
dir="https://domain.com/api/v1/"
use="one#two.com"
pas="123456"
values = {
'list' :["201.22.44.12","8.7.6.0/24"]
}
data = urllib.urlencode(values)
base64string = base64.encodestring('%s:%s' % (use, pas)).replace('\n', '')
request = urllib2.Request(dir, data, headers={"Authorization" : "Basic %s" % base64string})
response = urllib2.urlopen(request).read()
I am not sure It will work or not for you but check this piece of code
You can encode a dict using urllib like this:
import urllib
import urllib2
url = 'http://example.com/...'
values = { 'productslug': 'bar','qty': 'bar' }
data = urllib.urlencode(values)
req = urllib2.Request(url, data)
response = urllib2.urlopen(req)
result = response.read()
print result

Not possible to set content-type to application/json using urllib2

This little baby:
import urllib2
import simplejson as json
opener = urllib2.build_opener()
opener.addheaders.append(('Content-Type', 'application/json'))
response = opener.open('http://localhost:8000',json.dumps({'a': 'b'}))
Produces the following request (as seen with ngrep):
sudo ngrep -q -d lo '^POST .* localhost:8000'
T 127.0.0.1:51668 -> 127.0.0.1:8000 [AP]
POST / HTTP/1.1..Accept-Encoding: identity..Content-Length: 10..Host: localhost:8000..Content-Type: application/x-www-form-urlencoded..Connection: close..User-Agent:
Python-urllib/2.7....{"a": "b"}
I do not want that Content-Type: application/x-www-form-urlencoded. I am explicitely saying that I want ('Content-Type', 'application/json')
What's going on here?!
If you want to set custom headers you should use a Request object:
import urllib2
import simplejson as json
opener = urllib2.build_opener()
req = urllib2.Request('http://localhost:8000', data=json.dumps({'a': 'b'}),
headers={'Content-Type': 'application/json'})
response = opener.open(req)
I got hit by the same stuff and came up with this little gem:
import urllib2
import simplejson as json
class ChangeTypeProcessor(BaseHandler):
def http_request(self, req):
req.unredirected_hdrs["Content-type"] = "application/json"
return req
opener = urllib2.build_opener()
self.opener.add_handler(ChangeTypeProcessor())
response = opener.open('http://localhost:8000',json.dumps({'a': 'b'}))
You just add a handler for HTTP requests that replaces the header that OpenerDirector previously added.
Python version:Python 2.7.15
I found that in urllib2.py:1145:
for name, value in self.parent.addheaders:
name = name.capitalize()
if not request.has_header(name):
request.add_unredirected_header(name, value)
...
def has_header(self, header_name):
return (header_name in self.headers or
header_name in self.unredirected_hdrs)
Otherwise,application/x-www-form-urlencoded has been in unredirected_hdrs and it won't be overwrite
You can solve like
import urllib.request
from http.cookiejar import CookieJar
import json
url = 'http://www.baidu.com'
req_dict = {'k': 'v'}
cj = CookieJar()
handler = urllib.request.HTTPCookieProcessor(cj)
opener = urllib.request.build_opener(handler)
req_json = json.dumps(req_dict)
req_post = req_json.encode('utf-8')
headers = {}
#headers['Content-Type'] = 'application/json'
req = urllib.request.Request(url=url, data=req_post, headers=headers)
#urllib.request.install_opener(opener)
#res = urllib.request.urlopen(req)
# or
res = opener.open(req)
res = res.read().decode('utf-8')
The problem is the capitalization of the Header name. You should use Content-type and not Content-Type.

Simple URL GET/POST function in Python

I can't seem to Google it, but I want a function that does this:
Accept 3 arguments (or more, whatever):
URL
a dictionary of params
POST or GET
Return me the results, and the response code.
Is there a snippet that does this?
requests
https://github.com/kennethreitz/requests/
Here's a few common ways to use it:
import requests
url = 'https://...'
payload = {'key1': 'value1', 'key2': 'value2'}
# GET
r = requests.get(url)
# GET with params in URL
r = requests.get(url, params=payload)
# POST with form-encoded data
r = requests.post(url, data=payload)
# POST with JSON
import json
r = requests.post(url, data=json.dumps(payload))
# Response, status etc
r.text
r.status_code
httplib2
https://github.com/jcgregorio/httplib2
>>> from httplib2 import Http
>>> from urllib import urlencode
>>> h = Http()
>>> data = dict(name="Joe", comment="A test comment")
>>> resp, content = h.request("http://bitworking.org/news/223/Meet-Ares", "POST", urlencode(data))
>>> resp
{'status': '200', 'transfer-encoding': 'chunked', 'vary': 'Accept-Encoding,User-Agent',
'server': 'Apache', 'connection': 'close', 'date': 'Tue, 31 Jul 2007 15:29:52 GMT',
'content-type': 'text/html'}
Even easier: via the requests module.
import requests
get_response = requests.get(url='http://google.com')
post_data = {'username':'joeb', 'password':'foobar'}
# POST some form-encoded data:
post_response = requests.post(url='http://httpbin.org/post', data=post_data)
To send data that is not form-encoded, send it serialised as a string (example taken from the documentation):
import json
post_response = requests.post(url='http://httpbin.org/post', data=json.dumps(post_data))
# If using requests v2.4.2 or later, pass the dict via the json parameter and it will be encoded directly:
post_response = requests.post(url='http://httpbin.org/post', json=post_data)
You could use this to wrap urllib2:
def URLRequest(url, params, method="GET"):
if method == "POST":
return urllib2.Request(url, data=urllib.urlencode(params))
else:
return urllib2.Request(url + "?" + urllib.urlencode(params))
That will return a Request object that has result data and response codes.
import urllib
def fetch_thing(url, params, method):
params = urllib.urlencode(params)
if method=='POST':
f = urllib.urlopen(url, params)
else:
f = urllib.urlopen(url+'?'+params)
return (f.read(), f.code)
content, response_code = fetch_thing(
'http://google.com/',
{'spam': 1, 'eggs': 2, 'bacon': 0},
'GET'
)
[Update]
Some of these answers are old. Today I would use the requests module like the answer by robaple.
I know you asked for GET and POST but I will provide CRUD since others may need this just in case: (this was tested in Python 3.7)
#!/usr/bin/env python3
import http.client
import json
print("\n GET example")
conn = http.client.HTTPSConnection("httpbin.org")
conn.request("GET", "/get")
response = conn.getresponse()
data = response.read().decode('utf-8')
print(response.status, response.reason)
print(data)
print("\n POST example")
conn = http.client.HTTPSConnection('httpbin.org')
headers = {'Content-type': 'application/json'}
post_body = {'text': 'testing post'}
json_data = json.dumps(post_body)
conn.request('POST', '/post', json_data, headers)
response = conn.getresponse()
print(response.read().decode())
print(response.status, response.reason)
print("\n PUT example ")
conn = http.client.HTTPSConnection('httpbin.org')
headers = {'Content-type': 'application/json'}
post_body ={'text': 'testing put'}
json_data = json.dumps(post_body)
conn.request('PUT', '/put', json_data, headers)
response = conn.getresponse()
print(response.read().decode(), response.reason)
print(response.status, response.reason)
print("\n delete example")
conn = http.client.HTTPSConnection('httpbin.org')
headers = {'Content-type': 'application/json'}
post_body ={'text': 'testing delete'}
json_data = json.dumps(post_body)
conn.request('DELETE', '/delete', json_data, headers)
response = conn.getresponse()
print(response.read().decode(), response.reason)
print(response.status, response.reason)

Categories