Parsing Post Requests in Python - python

I'm new to a lot of API work and I'm currently working with getting a bearer token from an API. After doing the proper POST request I'm able to get it but I'm getting it in a format that I'd rather not have to work around. I just get a big string of JSON data.
import requests
import os
import webbrowser
CLIENT_ID = [Client_ID]
CLIENT_SECRET = [Client_SECRET]
REDIRECT_URI = [REDIRECT_URI]
RESPONSE_TYPE = [RESPONSE_TPYE]
params = {
"client_id": CLIENT_ID,
"client_secret": CLIENT_SECRET,
"redirect_uri": REDIRECT_URI,
"response_type": RESPONSE_TYPE
}
endpoint = [this is the url endpoint]
webbrowser.open(endpoint)
code = input("Enter the Code: ")
print(code)
endpoint2 = "[endpoint without the code]" + code
token_endpoint = requests.post(endpoint2)
print(token_endpoint.text)
When executing this code and going through the steps I'm left with this:
{"access_token":"[bearer token here}","token_type":"Bearer","expires_in":7200,"refresh_token":"-[refresh token here]","scope":"read","created_at":[time created at]}
This is a full string object since I'm passing it as "text." I can't get anything to print if I don't do that but I'm willing to change that to get the access_token object to be it's own variable that I can work with.
Any tips are appreciated. Thanks.
(note: sensitive information is just put into brackets)

You can use token_endpoint.json() to get a dictionary instead of text, and then select whichever key-value you want.
If you ever get stuck on anything request based, your first stop should be their excellent documentation here, most of the times that would answer the question you had. Case in point, here is the section relevant to your question

I've never needed to use webbrowser. I think response = requests.post(url, data=payload_dict) and json_response.json() will provide everything you need (cf. requests documentation).
For extracting specific elements via xpath this answer might be helpful: parse html response

Related

Python - Spotify API returning Error 400 "Malformed JSON"

Heyo. I'm trying to make a small application in my spare time that uses the Spotify API . I have managed to get my program to use oAuth 2 to let a user authorize my app to manipulate their Spotify, but I have run into a problem with a certain endpoint on the Spotify API.
The endpoint I am having trouble with is https://api.spotify.com/v1/me/player/play (here's a link to their docs for the endpoint https://developer.spotify.com/console/put-play/). Whenever I try to make a put request to the endpoint I receive a 400 status code with the message "Malformed json" I get this message even when I copy/paste their own json from the docs, so I don't think it's a problem with how I am formatting my json, besides I have used json before to call other endpoints and they haven't had a problem with my formatting on those calls.
Here is my code:
headers = {"Authorization":"Bearer {}".format(access_token)}
url = 'https://api.spotify.com/v1/me/player/play'
payload = {"context_uri": "spotify:album:5ht7ItJgpBH7W6vJ5BqpPr"}
r = requests.put(url, headers=headers, data=payload)
print(r)
print(r.text)
To clarify, access_token is the access token that I have gotten from their authorization process, and I am using python-requests to make the http requests (Here is the docs for that: https://requests.kennethreitz.org/en/master/)
I am wondering if the problem is due to the fact that Spotify uses colons int their track IDs and colons are also used in JSON? I saw in another thread on here that I should try to add "Content-Type":"application/json" to my headers but that didn't change the outcome at all.
Any help is greatly appreciated, and if you need any more info please let me know. Thank you!
If your payload is a dict use json kwargs in requests lib. data works for string payload. Here you go:
r = requests.put(url, headers=headers, json=payload)

Requests gives 400 error when trying to Post Requests on Shopify

Im trying to create a requests python script that will add to cart and eventually checkout. I did a Post Requests to
(https://yeezysupply.com/cart/add.js) which is the add to cart endpoint I found in the networks chrome developer tools page. It has a json payload with 3 dictionaries. Id which is the variant ID from the product, properties which I don't know what it is so I left it blank, and quantity. I entered the data as a param when I did the Post requests. I received a 400 Response Error. When I printed the requests Text, nothing was added to my cart and i received this.
{
"status":"bad_request",
"message":"expected String to be a Hash: properties",
"description":"expected String to be a Hash: properties"
}
Im pretty new to requests so I'm not sure what the error means.
I was able to confirm nothing was added to my cart because I did a get requests to the shopify cart endpoint (https://yeezysupply.com/cart.json). When I print the get requests I get this.
{
"token":"cb67e6c53c63b930b4aca1eb3b5a7510",
"note":null,
"attributes":{
},
"original_total_price":0,
"total_price":0,
"total_discount":0,
"total_weight":0.0,
"item_count":0,
"items":[
],
"requires_shipping":false,
"currency":"USD",
"items_subtotal_price":0,
"cart_level_discount_applications":[
]
}
This confirmed nothing was added to my cart. Does anyone know what I'm doing wrong? The product I used for my testing is (https://yeezysupply.com/products/flannel-lined-canvas-jacket-medium-blue?c=%2Fcollections%2Fwomen)
I've tried creating a global requests session to see if I needed cookies. This didn't work either.
import requests
from bs4 import BeautifulSoup as soup
session = requests.Session()
atc_endpoint = 'https://yeezysupply.com/cart/add.js'
atc_info = {
"id": "1457089478675",
"properties": "{}",
"quantity": "1"
}
def add_to_cart():
pass
atc_post = session.post(atc_endpoint, data=atc_info)
atc_get = session.get('https://yeezysupply.com/cart.json')
print(atc_post.text)
I tried using headers, I used headers = {"Content-Type": "application/json"}
I received the following error:
{
"error":"822: unexpected token at 'id=1457089478675\u0026properties=%7B%7D\u0026quantity=1'"
}
Im not sure what token the api is asking for.
I expect to have the item in my cart and shown in the get requests text.
Try the following things-
Add {"Content-Type": "application/json"} as a header to your request. It would look like this-
headers {"Content-Type": "application/json"}
atc_post = session.post(atc_endpoint, data=atc_info, headers=headers)
This should do the trick. Your dictionary looks good to me but if this still gives errors, try to use json.loads on your dictionary before sending it.
Hope this helps. :)
So you're building a Bot to checkout products (it would seem anyway). No offence to your talents with Python, but your life would get absolutely better if you just used Javascript to make your bot do your bidding. Since is naturally built into browsers anyway, your efforts would be simplified.
If you wanted to run your Bot server-side with Python as your question kind of indicates, and a POST is giving you troubles, just wait till you script checkout! I am not sure you can even do that at this point, so you might want to put the brakes on your plans until you can demonstrably check out without issue. Did you look into that?

Requests works and URLFetch doesn't

I'm trying to make a request to the particle servers in python in a google app engine app.
In my terminal, I can complete the request simply and successfully with requests as:
res = requests.get('https://api.particle.io/v1/devices', params={"access_token": {ACCESS_TOKEN}})
But in my app, the same thing doesn't work with urlfetch, which keeps telling me it can't find the access token:
url = 'https://api.particle.io/v1/devices'
payload = {"access_token": {ACCESS_TOKEN}}
form_data = urllib.urlencode(payload)
res = urlfetch.fetch(
url=url,
payload=form_data,
method=urlfetch.GET,
headers={
'Content-Type':
'application/x-www-form-urlencoded'
},
follow_redirects=False
)
I have no idea what the problem is, and no way to debug. Thanks!
In a nutshell, your problem is that in your urlfetch sample you're embedding your access token into the request body, and since you're issuing a GET request -which cannot carry any request body with them- this information gets discarded.
Why does your first snippet work?
Because requests.get() takes that optional params argument that means: "take this dictionary I give you, convert all its key/value pairs into a query string and append it to the main URL"
So, behind the curtains, requests.get() is building a string like this:
https://api.particle.io/v1/devices?access_token=ACCESS_TOKEN
That's the correct endpoint you should point your GET requests to.
Why doesn't your second snippet work?
This time, urlfetch.fetch() uses a different syntax than requests.get() (but equivalent nonetheless). The important bit to note here is that payload argument doesn't mean the same as our params argument that you used before in requests.get().
urlfetch.fetch() expects our query string -if any- to be already urlencoded into the URL (that's why urllib.urlencode() comes into play here). On the other hand, payload is where you should put your request body in case you were issuing a POST, PUT or PATCH request, but particle.io's endpoint is not expecting your OAuth access token to be there.
Something like this should work (disclaimer: not tested):
auth = {"access_token": {ACCESS_TOKEN}}
url_params = urllib.urlencode(auth)
url = 'https://api.particle.io/v1/devices?%s' % url_params
res = urlfetch.fetch(
url=url,
method=urlfetch.GET,
follow_redirects=False
)
Notice how now we don't need your previous Content-type header anymore, since we aren't carrying any content after all. Hence, headers parameter can be removed from this example call.
For further reference, take a look at urlfetch.fetch() reference and this SO thread that will hopefully give you a better insight into HTTP methods, parameters and request bodies than my poor explanation here.
PS: If particle.io servers support it (they should), you should move away from this authentication schema and carry your tokens in a Authorization: Bearer <access_token> header instead. Carrying access tokens in URLs is not a good idea because they are much more visible that way and tend to stay logged in servers, hence posing a security risk. On the other hand, in a TLS session all request headers are always encrypted so your auth tokens are well hidden there.
Ok, so, as it turns out, one cannot include a payload for a GET request using Urlfetch. Instead, one has to include the parameters in the url using the '?' syntax as follows:
url = 'https://api.particle.io/v1/devices'
url = url + '?access_token=' + {ACCESS_TOKEN}
res = urlfetch.fetch(
url=url,
method=urlfetch.GET,
follow_redirects=False
)
this worked for me.

Retrieve access token for Yahoo API using OAuth 2.0 and Python requests

I am trying to retrieve the access token for the Yahoo API, using the explicit grant flow as described in this document:
https://developer.yahoo.com/oauth2/guide/flows_authcode
Everything is fine until Step 4: Exchange authorization code for Access Token
I wrote the following python script to retrieve the code:
import urllib2
import requests
import json
url = 'https://api.login.yahoo.com/oauth2/get_token'
body = "grant_type=authorization_code&redirect_uri=oob&code=************"
headers = {
'Authorization': 'Basic **************',
'Content-Type': 'application/json'
}
r = requests.post(url, data=body, headers=headers)
print r
Note: I replaced sensitive data with "****"
Now, when I execute the script, I only get the "401" error message.
I am 100% sure that the login credentials are fine, so it seems to be related to the way I make the request. It's also the first time that I am using "requests" in python.
Would be great, if you could give me some feedback on the code, and if I am passing the header and body information correctly. I am especially unsure about the passing of the body. The documentation only states the following:
Sample Request Body: grant_type=authorization_code&redirect_uri=https%3A%2F%2Fwww.example.com&code=abcdef
Change your body variable to a dict, i.e.,
body = {
'grant_type': 'authorization_code',
'redirect_uri': 'oob',
'code': '************',
}
No other changes are needed. Hope it helps.
Tough the problem already solved. But may be other user can still get the same 401 error even if they use correct dict as me. The problem is that the code generated in step 2 in the link can be only use ONCE. And this will get the same 401 error. This took me some time to figure it out. Hope this helps others.

Yggdrasil authentication with Python

I decided to try to make an automated login script for Minecraft. However, the new authentication API is stumping me. I can't find any mentions of the new functionality of the API on here. This is my code as it stands:
import requests
import json
data = json.dumps({"agent":{"name":"Minecraft","version":1},"username":"abcdef","password":"abcdef","clientToken":""})
headers = {'Content-Type': 'application/json'}
r = requests.post('https://authserver.mojang.com', data=data, headers=headers)
print (r.text)
Unfortunately, this returns:
{"error":"Method Not Allowed","errorMessage":"The method specified in the request is not allowed for the resource identified by the request URI"}
According to this resource on request format, this error means that I didn't correctly send a post request. However, I clearly declared requests.post(), so my first question is how am I incorrect, and what is the correct way to go about this?
My second question is, since I'm relatively new to Python and JSON, how would I replace the username and password fields with my own data, inside a variable?
You haven't specified an endpoint in your POST request, for example:
https://authserver.mojang.com/authenticate
The root of the website probably does not accept POST requests
http://wiki.vg/Authentication#Authenticate

Categories

Resources