Facebook FQL Query with POST Request from a Python Script - python

I'm trying to make an FQL query with the following code:
def get_postData(to_post, access_token):
postData = {}
postData["method"] = "fql.query"
postData["query"] = to_post
postData["access_token"] = access_token
return postData
def make_request(url, to_post, access_token):
postData = get_postData(to_post, access_token)
return requests.post(url, data = postData).json()[u'data']
Using POST requests is not the best documented in the docs, and I'm unable to get this to work. With either "fql.query" or "fql" specified under method (taken from the Javascript specific example here: How can I execute a FQL query with Facebook Graph API), I get the response:
{u'error': {u'message': u'Unsupported method, fql.query', u'code': 100, u'type': u'GraphMethodException'}}
Which is, of course, not covered in the docs. Without that method specification, I get back:
{u'error': {u'message': u'Unsupported post request.', u'code': 100, u'type': u'GraphMethodException'}}
Which is also not covered in the docs. I'm not able to use a get request here (which is trivial), as I'm making a rather large query that at the moment doesn't overflow the get request limits but very well could in the near future.
Thanks for any help you may be able to give with regards to solving this problem.
EDIT: Should note I'm making the request to:
https://graph.facebook.com

First of all, what URL are you trying to access? I mean, why do you need POST request for FQL? FQL is for fetching data, not for posting.
According to docs (https://developers.facebook.com/docs/technical-guides/fql/) your request should look like that:
https://graph.facebook.com/fql?q=QUERY&access_token=TOKEN - where QUERY - is your urlencoded query to FQL, TOKEN - your valid access token.

All you need to do is understand how your requests are built, if you understand that, then the errors will make more sense to you.
postData = {}
postData["method"] = "fql.query"
postData["query"] = to_post
postData["access_token"] = access_token
requests.post(url, data = postData).json()[u'data']
Without even running this, I know the request looks like
POST https://graph.facebook.com/?method=fql.query&query=THE_QUERY&access_token=THE_TOKEN
Which is not the fql.method of method/fql.query as shown as the relative url in the doc https://developers.facebook.com/docs/reference/api/batch/ you presented.
Removing the specification (I don't know why you want to do this) will obviously result in an unknown error since this is now the request you are making
POST https://graph.facebook.com/?query=THE_QUERY&access_token=THE_TOKEN
The correct request will be
GET https://api-read.facebook.com/restserver.php?method=fql.query&query=THE_QUERY&access_token=THE_TOKEN
or
GET https://api.facebook.com/method/fql.query&query=THE_QUERY&access_token=THE_TOKEN
I'm not entire sure what endpoint the batch uses that allows an HTTP POST to method/fql.query so I wouldn't rely on it unless you are actually doing batch requests.
In the end using fql.query may not be the best way to go since it's on its way to deprecation.
I'm still unsure how your query could be so long that it exceeds the GET request limit. Consider re-evaluating how you structure your query as a multi-query or in batch.

Related

Python request gives 415 error while post data unless data = {'key':'value'}

I am doing a straight forward request as follows.
import requests
def user_transactions():
url = 'https://webapi.coinfloor.co.uk/v2/bist/XBT/GBP/user_transactions/'
data = {'key':'value'}
r = requests.post(url, data=data, auth=("some_username", "some_password") )
print(r.status_code)
print(r.text)
return
Even though data= is optional in the documents.
https://www.w3schools.com/python/ref_requests_post.asp
If i comment out the data variable then the routine returns a
status_code=415 error.
If i include in the data variable then the routine returns a status_code=200 success.
I have tried to look this up, for example here:
Python request gives 415 error while post data , but with no answer.
The question is: Why is it the case that [1] fails but [2] works ?
Yes, data is optional on the python side. The requests library will happily send a empty request to the server, as you can see. If the argument was not optional, the program would crash before sending a request so there would be no status code.
However, the server needs to be able to process the request. If it does not like what you sent for whatever reason, it might send back a 4xx status code, or otherwise not do what you expect.
In this case, it throws an error that the data is in invalid format. How can a empty request be in invalid format? Because the format is specified in a header. If you supply a data argumet requests will send data in urlencoded format, and specify in the header what format the data is in. If the data is empty, the request will be empty but the header will still be there. This site apparently requires the header to specify a data format it knows.
You can solve this in two ways, giving an empty object:
r = requests.post(url, data={}, auth=("some_username", "some_password") )
Or by explicitly specifying the header:
r = requests.post(url, auth=(...), headers={'Content-Type': 'application/x-www-form-urlencoded'})
Side note: You should not be using W3Schools as a source. It is frequently inaccurate and often recommends bad practices.
I think you are mistaking the documentation of the requests.post function signature with API documentation. It is saying that data is a keyword argument, not that the API optionally takes data.
It depends on the API endpoint you are trying to use. That endpoint must require data to be sent with the request. If you look at the documentation for the API you are using, it will mention what needs to be sent for a valid request.

How do I make this website recognise my arrays as part of a valid url query?

EDIT:
In a similar vein, when I now try to log into their account with a post request, what is returned is none of the errors they suggest on their site, but is in fact a "JSON exception". Is there any way to debug this, or is an error code 500 completely impossible to deal with?
I'm well aware this question has been asked before. Sadly, when trying the proposed answers, none worked. I have an extremely simple Python project with urllib, and I've never done web programming in Python before, nor am I even a regular Python user. My friend needs to get access to content from this site, but their user-friendly front-end is down and I learned that they have a public API to access their content. Not knowing what I'm doing, but glad to try to help and interested in the challenge, I have very slowly set out.
Note that it is necessary for me to only use standard Python libraries, so that any finished project could easily be emailed to their computer and just work.
The following works completely fine minus the "originalLanguage" query, but when using it, which the API has documented as an array value, no matter whether I comma-separate things, or write "originalLanguage[0]" or "originalLanguage0" or anything that I've seen online, this creates the error message from the server: "Array value expected but string detected" or something along those lines.
Is there any way for me to get this working? Because it clearly can work, otherwise the API wouldn't document it. Many thanks.
In case it helps, when using "[]" or "<>" or "{}" or any delimeter I could think of, my IDE didn't recognise it as part of the URL.
import urllib.request as request
import urllib.parse as parse
def make_query(url, params):
url += "?"
for i in range(len(params)):
url += list(params)[i]
url += '='
url += list(params.values())[i]
if i < len(params) - 1:
url += '&'
return url
base = "https://api.mangadex.org/manga"
params = {
"limit": "50",
"originalLanguage": "en"
}
url = make_query(base, params)
req = request.Request(url)
response = request.urlopen(req)

Why do I get this error - "missing token"? (playing with an API using Python)

So, I am playing around with Etilbudsavis' API (Danish directory containing offers from retail stores). My goal is to retrieve data based on a search query. the API acutally allows this, out of the box. However, when I try to do this, I end up with an error saying that my token is missing. Anyways, here is my code:
from urllib2 import urlopen
from json import load
import requests
body = {'api_key': 'secret_api_key'}
response = requests.post('https://api.etilbudsavis.dk/v2/sessions', data=body)
print response.text
new_body = {'_token:': 'token_obtained_from_POST_method', 'query:': 'coca-cola'}
new_response = requests.get('https://api.etilbudsavis.dk/v2/offers/search', data=new_body)
print new_response.text
Full error:
{"code":1107,"id":"00ilpgq7etum2ksrh4nr6y1jlu5ng8cj","message":"missing token","
details":"Missing token\nNo token found in request to an endpoint that requires
a valid token.","previous":null,"#note.1":"Hey! It looks like you found an error
. If you have any questions about this error, feel free to contact support with
the above error id."}
Since this is a GET request, you should use the params argument to pass the data in the URL.
new_response = requests.get('https://api.etilbudsavis.dk/v2/offers/search', params=new_body)
See the requests docs.
I managed to solve the problem with the help of Daniel Roseman who reminded me of the fact that playing with an API in the Python Shell is different from interacting with the API in the browser. The docs clearly stated that you'd have to sign the API token in order for it to work. I missed that tiny detail ... Never the less, Daniel helped me figure everything out. Thanks again, Dan.

How do I get notes info from posts with python/tumblr api?

I am so confused by all these levels of dicts I have to wade through it would be easier imo just to do it by scraping, however I guess it's a good excercise to learn dicts and will be quicker perhaps once I figure it out.
My code is as follows, where the assignment statement for cposts returns a 404:
import pytumblr
# Authenticate via OAuth
client = pytumblr.TumblrRestClient(
'xxxxxxxxxxxxxxxxxxxxxxxxxxxx'
)
f = client.followers('blog.tumblr.com')
users = f['users']
names = [b['name'] for b in f['users']]
print names
cposts = client.posts(names[0], 'notes_info=True')
print (cposts)
But the python api info says: client.posts('codingjester', **params) # get posts for a blog
and this SO post (Getting more than 50 notes with Tumblr API) says you should use notes_info to get the notes. But I don't know how to construct it in python rather than making a url.
I could use a request constructing a url but I figure there is a simpler way using the python/tumblr api I just haven't figured it out, if someone could illuminate please.
Remove the quotes around notes_info=True. You should be passing the value True to the notes_info argument of the client's posts() method. Instead, you're actually passing the string 'notes_info=True' as a positional argument, which is invalid and causes pytumblr to create an invalid URL, which is why you're getting a 404.

Performing a twitter search in python using Oauth

I'm just being a bit of an idiot here, I think, but I've figured out how to fetch my timeline, but not how to modify that into performing a search. I've currently got:
consumer = oauth.Consumer(key=CONSUMER_KEY, secret=CONSUMER_SECRET)
access_token = oauth.Token(key=ACCESS_KEY, secret=ACCESS_SECRET)
client = oauth.Client(consumer, access_token)
response, data = client.request(searchURL)
I'm guessing it's the last line that'll change to work with the search, but I'm not sure how to format it, if I change the searchURL to the one used for actually searching (it's currently on timeline) it says it's in the wrong format.
Can anyone help?
Thanks.
Turns out it's off the form:
searchURL = https://api.twitter.com/1.1/search/tweets.json?q=obama&count=2&tresult_type=popular
That's an example search using the keyword "obama", setting the count to 2, and filtering for popular results.
response, data = client.request(searchURL)
tweets = json.loads(data)
The format of the returned tweets is a bit...awkward, but understandable with a bit of playing around.

Categories

Resources