I am making a post request and I have a payload variable but I am trying to set some of the data in the payload variable as user input so I am doing:
payload = "{\r\"user\": \"{}\",\r\"password\": \"{}\",\r\"gdn\": 0\r}".format(name, pass)
I get this error:
File "testing.py", line 24, in sndReq
payload = "{\r\"user\": \"{}\",\r\"password\": \"{}\",\r\"gdn\": 0\r}".format(name, pass)
KeyError: '\r"user"
If I take out .format and put hard values in there it works. (I also tried using an 'f' string)
My request line is this if it matters:
r = requests.request("POST", url, data=payload, headers=headers)
It seems your string is not formatted/escaped properly. How about doing something which is more readable, such as:
import requests
# some example values because your question doesn't give too many details
user, password ="user", "password"
url="http://google.com" # example url
headers={'pragma': 'no-cache'} # whatever your headers are
# now do the request, note we're not passing a single string here
requests.post(
url,
json={
"user": user,
"password": password
},
headers=headers
)
Additionally, I'd encourage you to work with something a bit easier than those unreadable strings! Put it into something that python (and us) can work with more easily. The first thing I'd do is get your string into a python object:
import json
payload = "{\r\"user\": \"{}\",\r\"password\": \"{}\",\r\"gdn\": 0\r}"
data=json.loads(payload)
data.update({'password': 'secret', 'user': 'me'})
# {u'password': 'secret', u'user': 'me', u'gdn': 0}
And finally, if you truly want to use the {} as the format string (which I hope the rest of my answer shows you is much more difficult than you need to make it), you'll need to remove the leading and trailing braces in the formatted text:
"{" + "\r\"user\": \"{}\",\r\"password\": \"{}\",\r\"gdn\": 0\r".format("user", "secret") + "}"
# '{\r"user": "user",\r"password": "secret",\r"gdn": 0\r}
Related
(https://i.stack.imgur.com/xgoMx.jpg)
I want to be able to pass a variable through to where the registration plate (AA19AAA) is
Overall, I want a function to check the number plate, therefore I need to pass a parameter through the function and use it in the payload, but I'm not sure how to actually pass a string to the inside of the payload.
I have tried using .format(...) to add things to the string, concatenating the variable into the payload, and another method similar to .format(...). However, if you believe any of these could be applicable, please don't hesitate to tell me as I may have made a mistake somewhere.
I hope some of you can assist me in this, I'm sorry if there is an incredibly simple solution to this, but I have tried a few, and feel that it is time to ask the professionals.
Thank you so much
you have 2 options:
import requests
import json
payload = {'registrationNumber': some_var}
headers = {..., 'content': 'application/json'}
result = requests.post(url, headers = headers, data=json.dumps(payload))
or
import requests
headers = {...}
payload = {'registrationNumber': some_var}
result = requests.post(url, headers=headers, json=payload)
So when I access the API target via Postman with the URL below, it works fine without any issues
base_url = https://api.cats.net/orgs/CatEmpire/audit-log?phrase=action:stuck_on_tree+date_of_event:2022-01-11
However, when I append the below parameters into my request, the URL comes out differently and I'm no longer able to get results
parameters = {
'action:': 'stuck_on_tree',
'date_of_event:': '2022-01-11'
}
PAT = asdasdhdhdhhd123123
response = requests.get(base_url, headers={"Accept": "application/vnd.github.v3+json", "Authorization": f"Bearer {PAT}"}, params=parameters)
print(response.request.url)
#This returns https://api.cats.net/orgs/CatEmpire/audit-log?phrase=&action%3A=stuck_on_tree&date_of_event%3A=2022-01-11
I have tried to use:
paramters_string = urllib.parse.urlencode(parameters, safe='')
And then I updated my response variable below, but the results are still exaxtly the same. I have tried to do some digging but I can't seem to figure out if this an issue because I'm using a dictionary to pass the params, or if there's something else that I'm not able to understand. I'm fairly new to Python.
`response = requests.get(base_url, headers={"Accept": "application/vnd.github.v3+json", "Authorization": f"Bearer {PAT}"}, params=parameters)`
Your base URL should not include part of your query string (?phrase=).
Use this for your base URL:
https://api.cats.net/orgs/CatEmpire/audit-log
For your parameters, use this:
parameters = {
'phrase': 'action:stuck_on_tree+date_of_event:2022-01-11'
}
Update
Since you can't URL encode your parameters due to API constraints, you'll have to pass them as a string like so:
parameters = 'phrase=action:stuck_on_tree+date_of_event:2022-01-11'
have you tried ?
PAT = "asdasdhdhdhhd123123"
data = parameters
this is just an example of authorization request:
import requests
endpoint = ".../api/ip"
data = {"ip": "1.1.2.3"}
headers = {"Authorization": "Bearer MYREALLYLONGTOKENIGOT"}
response = requests.post(endpoint, data=data, headers=headers)
So I figured it out. I needed to create a separate key for each parameter like below:
params = {
'phrase': 'action:stuck_on_tree',
'date_of_event:': '2022-01-11'
}
I'm not sure why I couldn't fit everything into the 'phrase' key, but this works and is also what I was trying to do to begin with because I wanted to be able to pass things dynamically into the params dictionary, so having all of my parameters in one key was going to be an issue. I didn't need to encode or unencode anything. Basically the semi colon was my issue lol. Thanks for all your help #dimz & #john glenn!
I have been trying to make a POST request. My code is working properly if I put the "contestId" manually, but I want to make it dynamic.
payload = "{\"contestId\":\"dcaf641d-ff39-4bf9-b295-4eb13936410d\",\"contestType\": \"OverUnder\",\"direction\": \"moon\",\"wager\": \"1\"}"
Use some string concatenation to insert the variable holding the contestID into the right position.
Your payload is json, therefore use json:
contest_id = "dcaf641d-ff39-4bf9-b295-4eb13936410d"
payload = {"contestId": contest_id, "contestType": "OverUnder", "direction": "moon", "wager": "1"}
response = request.post(URL, json=payload, headers=headers, params=querystring)
I'm calling the google API myself instead of using their python Library because I'm behind an inconvenient corporate proxy which kills their library, so I have to do it all myself.
This works fine:
requests.get('https://www.googleapis.com/webmasters/v3/sites', params =
{'access_token':'my_access_token_here'})
This on the other hand, doesn't:
site = https://www.my_website_from_the_above_function.com
site = urllib.parse.quote_plus(site)
def get_website_info():
url = 'https://www.googleapis.com/webmasters/v3/sites/{}/searchAnalytics/query'.format(site)
params = {
"endDate": "2017-12-10",
"startDate": "2017-12-01",
"access_token": my_access_token
}
r = requests.post(url, params = params)
return r
x = get_website_info().json()
All I get is this error code:
{'error': {'code': 500,
'errors': [{'domain': 'global',
'message': 'Backend Error',
'reason': 'backendError'}],
'message': 'Backend Error'}}
Even with the reccomended 'Exponential backoff'
Using googles API explorer seems to work fine:
Aditionally: This also seems give similar errors:
r = requests.post(url, params = auth_params, data = json.dumps(params))
and finally:
r = requests.post(url, params = auth_params, data = params)
just gives
{'error': {'code': 400,
'errors': [{'domain': 'global',
'message': 'This API does not support parsing form-encoded input.',
'reason': 'parseError'}],
'message': 'This API does not support parsing form-encoded input.'}}
So, you can think of the contents of a request as just text, right? Not only text, but text that accepts a relatively limited number of characters.
With that in mind, it all boils down on how to serialize "complex" data structures into text. I recently answered another question about files that is kinddddaaa similar idea.
If you have a bunch of key=value parameters, you could use a simple "trick":
Control names and values are escaped. Space characters are replaced by
+, and then reserved characters are escaped as described in
[RFC1738], section 2.2: Non-alphanumeric characters are replaced by
%HH, a percent sign and two hexadecimal digits representing the
ASCII code of the character. Line breaks are represented as "CR LF"
pairs (i.e., %0D%0A).
The control names/values are listed in the
order they appear in the document. The name is separated from the
value by = and name/value pairs are separated from each other by
&.
So this data:
{a="foo", b="bar baz"}
Could be serialized into text following the specification above like: a=foo&b=bar+baz
That serialization format is identified as application/x-www-form-urlencoded in the Content-type request's header. That request's header is telling the server that receives it something like "Hey! The data that is coming in my body is serialized following that convention that separates keys from values using the = symbol and splits key/value pairs using &, changes whitespaces by +... and so on"
(!) Very important: That is the format used by the requests module on a POST unless told otherwise.
Another format, which allows more flexibility (such as maintaining basic types or nesting structures) is JSON. That is the format that the Google server "wants", and in order to tell servers that the "text" contained in the request's body follows the Json standard (or convention), the Content-Type header must be set to 'application/json'.
What appears that your Google server was doing upon receiving a request was checking the Content-type header and if it wasn't Json, it gave you a 400 error to indicate "Oh, I don't understand this format... I want Json!"
That's why you have to specify the Json header.
There's an example comparing both formats here.
You can also see it more clearly since the latest versions of requests module can do the JSON parsing for you. Since the JSON format has become so common, you can pass data provided in a Python structure (a dict, for instance) through the json= argument, and the module will do the json.dumps and set the header for you. This also allows you to "introspect" a little how the body will look like (to see the differences maybe more clearly).
Check this out:
from requests import Request
data = {
'a': 'foo-1 baz',
'b': 5,
'c': [1, 2, 3],
'd': '6'
}
req = Request('POST', 'http://foo.bar', data=data)
prepped = req.prepare()
print("Normal headers: %s" % prepped.headers)
print("Normal body: %s" % prepped.body)
req = Request('POST', 'http://foo.bar', json=data)
prepped = req.prepare()
print("Json headers: %s" % prepped.headers)
print("Json body: %s" % prepped.body)
Outputs:
Normal headers: {'Content-Length': '31', 'Content-Type': 'application/x-www-form-urlencoded'}
Normal body: d=6&a=foo-1+baz&c=1&c=2&c=3&b=5
Json headers: {'Content-Length': '52', 'Content-Type': 'application/json'}
Json body: b'{"d": "6", "a": "foo-1 baz", "c": [1, 2, 3], "b": 5}'
See the difference? JSON is capable of making a difference between the strings foo-1 or 6 (using ") as opposed to 5 being an integer, while the x-www-form can't (see how the form encoding doesn't differentiate between the integer 5 or the string 6). Same with the list. By using the character [, the server will be able to tell that c is a list (and of integers)
I got it! The solution:
was to pass in header information with:
headers = {'Content-type': 'application/json',
'Authorization' : 'Bearer %s' % access_token}
and make sure the json data was dumped to a string:
r = requests.post(url,data = json.dumps(params), headers = headers)
If someone could explain the reason behind my answer, that would be great.
Before downvoting/marking as duplicate, please note:
I have already tried out this, this, this, this,this, this - basically almost all the methods I could find pointed out by the Requests documentation but do not seem to find any solution.
Problem:
I want to make a POST request with a set of headers and form data.
There are no files to be uploaded. As per the request body in Postman, we set the parameters by selecting 'form-data' under the 'Body' section for the request.
Here is the code I have:
headers = {'authorization': token_string,
'content-type':'multipart/form-data; boundary=----WebKitFormBoundaryxxxxxXXXXX12345'} # I get 'unsupported application/x-www-form-url-encoded' error if I remove this line
body = {
'foo1':'bar1',
'foo2':'bar2',
#... and other form data, NO FILE UPLOADED
}
#I have also tried the below approach
payload = dict()
payload['foo1']='bar1'
payload['foo2']='bar2'
page = ''
page = requests.post(url, proxies=proxies, headers=headers,
json=body, files=json.dump(body)) # also tried data=body,data=payload,files={} when giving data values
Error
{"errorCode":404,"message":"Required String parameter 'foo1' is not
present"}
EDIT:
Adding a trace of the network console. I am defining it in the same way in the payload as mentioned on the request payload.
There isn't any gui at all? You could get the network data from chrome, although:
Try this:
headers = {'authorization': token_string}
Probably there is more authorization? Or smthng else?
You shouldn't add Content-Type as requests will handle it for you.
Important, you could see the content type as WebKitFormBoundary, so for the payload you must take, the data from the "name" variable.
Example:
(I know you won't upload any file, it just an example) -
So in this case, for my payload would look like this: payload = {'photo':'myphoto'} (yea there would be an open file etc etc, but I try to keep it simple)
So your payload would be this-> (So always use name from the WebKit)
payload = {'foo1':'foo1data',
'foo2':'foo2data'}
session.post(url,data = payload, proxies etc...)
Important! As I can see you use the method from requests library. Firstly you always should create a session like this
session = requests.session() -> it will handle cookies, headers, etc, and won't open a new session, or plain requests with every requests.get/post.