Json and requests in python - python

import requests
import json
url = 'mywebsite/test.php'
myobj = data = {"username" : "test", "password" : "1234"}
myobj = json.dumps(myobj)
x = requests.post("loginUser",url, data = myobj)
print(x)
I get the following error:
Traceback (most recent call last):
File "main.py", line 55, in <module> x = requests.post("loginUser",url, data = myobj) TypeError: post() got multiple values for argument 'data'
Can anyone help with this?

Look at the docs:
https://docs.python-requests.org/en/latest/api/
requests.post(url, data=None, json=None, **kwargs)[source]
Sends a POST request.
Parameters:
url – URL for the new Request object.
data – (optional) Dictionary, list of tuples, bytes, or file-like object to send in the body of the Request.
json – (optional) json data to send in the body of the Request.
**kwargs – Optional arguments that request takes.
Returns:
Response object
and so your command should be:
myobj = json.dumps(myobj).encode("ascii")
x = requests.post(url = url, data = myobj)
or without using json.dumps:
x = requests.post(url = url, json = myobj)
What exactly is "loginUser" for in this case? is that a URI route, field, or parameter?

I'm just learning python myself and have used requests a bit.
I've always put the url at the beggining and payload at the end:
i.e Should "LoginUser" go at the end?

I have fixed it. Problem was that I didn’t put http:// in front of the url and I didn’t format my JSON request the way my php was expecting.

Related

Unable to access nodes/tags in JSON response in Python

Trying to learn Python finally. Having read all the other questions on the topic I have deducted I am an idiot.
I'm making a Python request to an open API like below
import requests
import json
url = 'http://api.turfgame.com/v4/users'
payload = [{"name": "tbone"}]
headers = {'content-type': 'application/json'}
r = requests.post(url, data=json.dumps(payload), headers=headers)
This all goes well and I can print the response
print r.text
However, it's when I want to access certain tags/nodes in the response that I run into a wall. The output is
[{"country":"se","medals":[34,54,13,5,46,28,16,6],"zones":[323,7577,14606],"pointsPerHour":21,"points":21809,"blocktime":17,"taken":2290,"name":"tbone","totalPoints":347388,"rank":30,"id":95195,"place":1931,"uniqueZonesTaken":269,"region":{"name":"Stockholm","id":141}}]
And I've tried to
rj = r.json()
print rj['name']
But that only gives me
Traceback (most recent call last):
File "post.py", line 16, in <module>
print rj['name']
TypeError: list indices must be integers, not str
I cannot get my head around how to access any individual tags/nodes in the JSON response.
The answer you got : [{"country":"se",..."region":{"name":"Stockholm","id":141}}]
is a list of JSON objects (notice the [] surrounding the dictionary).
So, to get your object, you have to do :
rj = r.json()
print rj[0]['name'] # the [0] to indicate you take the first element of your list

Post array as parameters for API call

I am trying to send a tweet to the Buffer API using the POST /updates/create method. I get a 405 error as a response. I think the problem comes from the profile_ids parameter which should be an array. What is the correct syntax for this case ?
import requests
import json
url = "https://api.bufferapp.com/1/updates/create.json"
params = dict()
params['access_token'] = myToken
params["profile_ids"] = myID
params['text']= "This is a test"
r = requests.post(url, params=params)
print(r.status_code)
Please note that myToken and myID are variables I did not share for the post.

How to use requests to send a PATCH request with headers

I have a Rails 4 application which uses token based authentication for APIs and need to be able to update records through Python 3 script.
My current script looks like this
import requests
import json
url = 'http://0.0.0.0:3000/api/v1/update_experiment.json'
payload = {'expt_name' : 'A60E001', 'status' : 'done' }
r = requests.patch(url, payload)
which works OK if I disable API authentication.
I can't figure out how to add headers to it, requests.patch only takes two parameters according to docs.
I would need to get to the point where the following header info would added
'Authorization:Token token="xxxxxxxxxxxxxxxxxxxxxx"'
This type of header works OK in curl. How can I do this in Python 3 and requests?
patch takes kwargs, just pass headers = {your_header}:
def patch(url, data=None, **kwargs):
"""Sends a PATCH request.
:param url: URL for the new :class:`Request` object.
:param data: (optional) Dictionary, bytes, or file-like object to send in the body of the :class:`Request`.
:param \*\*kwargs: Optional arguments that ``request`` takes.
:return: :class:`Response <Response>` object
:rtype: requests.Response
"""
return request('patch', url, data=data, **kwargs)
So something like this:
head = {"Authorization":"Token token=xxxxxxxxxxxxxxxxxxxxxx"}
url = 'http://0.0.0.0:3000/api/v1/update_experiment.json'
payload = {'expt_name' : 'A60E001', 'status' : 'done' }
r = requests.patch(url, payload, headers=head)

How do I make a GET request with JSON in the request body

I need to send this JSON array in a GET request
{"user": "jähn", "id": 3}
I tried to use
data = '{"user": "jähn", "id": 3}'
headers = {
'Content-type': 'application/json',
'Accept': 'text/plain'
}
request = urllib.request.Request(self.update_url, data=data,
headers=headers, method='GET')
response = urllib.request.urlopen(request)
But its failing with: TypeError: POST data should be bytes or an iterable of bytes. It cannot be of type str.
Another thing that I find quite weird is that it tells me about POST data although I set the method on the Request to GET.
Since this is a simple script I'd prefer not to use a library like python-requests
You cannot make a GET request with a JSON-encoded body, as a GET request only ever consists of the URL and the headers. Parameters are encoded into the URL using URL encoding instead, there is no option to encode such parameters to JSON instead.
You create URL-encoded parameters with the urllib.parse.urlencode() function, then appended to the URL with ?.
from request.parse import urlencode
data = {"user": "jähn", "id": 3} # note, a Python dictionary, not a JSON string
parameters = urlencode(data)
response = urllib.request.urlopen('?'.join((self.update_url, parameters)))
Do not use the data parameter; using that keyword argument forces a request to use the POST method:
data must be a bytes object specifying additional data to send to the server, or None if no such data is needed. Currently HTTP requests are the only ones that use data; the HTTP request will be a POST instead of a GET when the data parameter is provided. data should be a buffer in the standard application/x-www-form-urlencoded format.

Making a POST call instead of GET using urllib2

There's a lot of stuff out there on urllib2 and POST calls, but I'm stuck on a problem.
I'm trying to do a simple POST call to a service:
url = 'http://myserver/post_service'
data = urllib.urlencode({'name' : 'joe',
'age' : '10'})
content = urllib2.urlopen(url=url, data=data).read()
print content
I can see the server logs and it says that I'm doing GET calls, when I'm sending the data
argument to urlopen.
The library is raising an 404 error (not found), which is correct for a GET call, POST calls are processed well (I'm also trying with a POST within a HTML form).
Do it in stages, and modify the object, like this:
# make a string with the request type in it:
method = "POST"
# create a handler. you can specify different handlers here (file uploads etc)
# but we go for the default
handler = urllib2.HTTPHandler()
# create an openerdirector instance
opener = urllib2.build_opener(handler)
# build a request
data = urllib.urlencode(dictionary_of_POST_fields_or_None)
request = urllib2.Request(url, data=data)
# add any other information you want
request.add_header("Content-Type",'application/json')
# overload the get method function with a small anonymous function...
request.get_method = lambda: method
# try it; don't forget to catch the result
try:
connection = opener.open(request)
except urllib2.HTTPError,e:
connection = e
# check. Substitute with appropriate HTTP code.
if connection.code == 200:
data = connection.read()
else:
# handle the error case. connection.read() will still contain data
# if any was returned, but it probably won't be of any use
This way allows you to extend to making PUT, DELETE, HEAD and OPTIONS requests too, simply by substituting the value of method or even wrapping it up in a function. Depending on what you're trying to do, you may also need a different HTTP handler, e.g. for multi file upload.
This may have been answered before: Python URLLib / URLLib2 POST.
Your server is likely performing a 302 redirect from http://myserver/post_service to http://myserver/post_service/. When the 302 redirect is performed, the request changes from POST to GET (see Issue 1401). Try changing url to http://myserver/post_service/.
Have a read of the urllib Missing Manual. Pulled from there is the following simple example of a POST request.
url = 'http://myserver/post_service'
data = urllib.urlencode({'name' : 'joe', 'age' : '10'})
req = urllib2.Request(url, data)
response = urllib2.urlopen(req)
print response.read()
As suggested by #Michael Kent do consider requests, it's great.
EDIT: This said, I do not know why passing data to urlopen() does not result in a POST request; It should. I suspect your server is redirecting, or misbehaving.
The requests module may ease your pain.
url = 'http://myserver/post_service'
data = dict(name='joe', age='10')
r = requests.post(url, data=data, allow_redirects=True)
print r.content
it should be sending a POST if you provide a data parameter (like you are doing):
from the docs:
"the HTTP request will be a POST instead of a GET when the data parameter is provided"
so.. add some debug output to see what's up from the client side.
you can modify your code to this and try again:
import urllib
import urllib2
url = 'http://myserver/post_service'
opener = urllib2.build_opener(urllib2.HTTPHandler(debuglevel=1))
data = urllib.urlencode({'name' : 'joe',
'age' : '10'})
content = opener.open(url, data=data).read()
Try this instead:
url = 'http://myserver/post_service'
data = urllib.urlencode({'name' : 'joe',
'age' : '10'})
req = urllib2.Request(url=url,data=data)
content = urllib2.urlopen(req).read()
print content
url="https://myserver/post_service"
data["name"] = "joe"
data["age"] = "20"
data_encoded = urllib2.urlencode(data)
print urllib2.urlopen(url + "?" + data_encoded).read()
May be this can help

Categories