Easy Facebook Scripting in Python

UPDATED: fbconsole Pypi Package and Github Repository

Sometimes you just want to write a little script using Facebook’s api that updates your status, or downloads all your photos, or deletes all those empty albums you accidentally created. In order to streamline my writing of one-off facebook scripts, I created a micro api client that implements the client-side authentication flow and has a few utility functions for accessing the graph api and fql.

To use this mini api client, all you have to do is put 4 lines of code at the top of your python script:

from urllib import urlretrieve
import imp
urlretrieve('https://raw.github.com/gist/1194123/fbconsole.py', '.fbconsole.py')
fb = imp.load_source('fb', '.fbconsole.py')

Now you can specify the permissions you’ll need for your script (from the list of available api permissions) and authenticate yourself:

fb.AUTH_SCOPE = ['publish_stream']

By default, the api client makes requests as the “fbconsole” app. You can use your own app by setting fb.APP_ID. When you authenticate, a browser window will open asking for whatever permissions were requested by your script. After you go through the permission dialog, the script will continue running. The access token used is stored in a local file when you authenticate so the next time around you won’t be presented with a dialog in your browser.

Once authenticated, you can make whatever calls to the graph api or fql that you want. For example:

Post a status update

status = fb.graph_post("/me/feed", {"message":"Hello from my awesome script"})

Fetch likes on a status update

likes = fb.graph("/"+status["id"]+"/likes")

Delete a status update


Upload a photo (why does python make this so hard?)

fb.graph_post("/me/photos", {"message":"My photo", "source":open("my-photo.jpg")})

Query FQL tables

friends = fb.fql("SELECT name FROM user WHERE uid IN "
                 "(SELECT uid2 FROM friend WHERE uid1 = me())")

If you download https://raw.github.com/gist/1194123/fbconsole.py and run it, you’ll be dropped into a python shell so you can just play around with api calls in an interactive environment. An IPython shell will be used if you have IPython installed.

The code is just in a gist on github at https://gist.github.com/1194123. Feel free to comment on this post or on the gist if you have questions.

  1. Rasheed said:

    Love it & so intresting

  2. Rahul N said:

    Interesting! Thanks :)

  3. Looks great, will have to give it a try :)

  4. While the urlretrieve() approach is a neat hack (with some rather interesting security implications), perhaps you would be willing to consider publishing this on the Python Package Index (http://pypi.python.org)?

    There’s a decent guide on how to do that here:

    (just replace the “towelstuff” package directory in the example with your “fbconsole.py” file and update the metadata appropriately)

  5. Great work!

    I am working on a similar concept as yours, but it would use huge javascript and would be on a client! Looking forward to having your inputs and thoughts!!

  6. pcardune said:

    Agreed. Given how much attention this is now getting, making a proper pypi package is definitely on my list. I’ll see if I can get to it tomorrow. My primary reason for not making a package in the first place was to lower the barrier to entry to people who don’t have much programming experience or knowledge of python. Explaining how to use a package management system always seems to be more complicated than just giving a few lines to copy/paste.

  7. can we have this kind of program in PHP, i would like to work in PHP command line code

  8. Anonymous said:

    This is incredible, thanks sir.

  9. George Paci said:

    Hey, Paul. Good post, and congratulations on cracking the top 10 over on Hacker News.

  10. This is a nice little client and I will be using it, but you are crazy if you think I’m putting those four lines of code that download a python script and do an eval on it, executing potentially malicious code. Big security issue. Do the right thing for yourself and your readers and create a proper github repository and set it up with setuptools. See this link: http://packages.python.org/an_example_pypi_project/setuptools.html. It basically means put your file in a subdirectory along with a blank __init__.py file and then creating a simple setup.py file that declares the dependencies in the directory above.

    Once you have that done, all you can have your readers install it with `pip install https://github.com/YOURGITHUBUSERNAME/YOURFBPROJECT/tarball/master` and then they can import it in their code.

    If you are not used to using github, they have the new Mac client that makes it drop dead simple.

    Good luck!

  11. Nice work. Ive been doing some facebook hacks on free time using scrapy. I think i have a good idea using this and scrapy and gui to build suttin for me ;)

  12. Dave said:

    What are your facebook app settings? I keep getting the following error when trying to use my own application:

    API Error Code: 191
    API Error Description: The specified URL is not owned by the application
    Error Message: Invalid redirect_uri: Given URL is not allowed by the Application configuration.


  13. Pretty sweet. Just tried it out now with a couple of posts.

  14. good job, I’ll be using this!
    +1 on a github repo

  15. dhananjay mishrra said:

    wat d hel python z,sm one tell me

  16. Nice! Thanks for the repo and setuptools!

  17. r3c4ll said:

    Hi pcardune, thank you for te fbconsole, good work, how i can get emails of my friends? i do the:

    friends = fb.fql(“SELECT name FROM user WHERE uid IN ”
    “(SELECT uid2 FROM friend WHERE uid1 = me())”)

    And it gets their names, what SELECT gets their emails and what other information i could get?

    Thank you again.

  18. bpgergo said:

    @r3c4ll friends = fb.fql(“SELECT uid, name, email, contact_email, proxied_email FROM user WHERE uid IN (SELECT uid2 FROM friend WHERE uid1 = me())”)

  19. pcardune said:

    @bgpergo, You can set the ACCESS_TOKEN variable in fbconsole and skip the authentication altogether if you want. I’m updating the README on github to mention that.

  20. bpgergo said:

    @pcardune this is a follow-up of my first comment about the authentication. I just got an error:
    “Error validating access token: Session has expired”
    It seems that the access_token I acquired from the graph api page example expires quickly, but obviously, you store the access_token in a local file to save unnecessary oauth request, so my questions are:
    Does the access_token acquired from oauth request expires too?
    If it does, you need to delete the local file manually to be able to authenticate again, don’t you?

  21. pcardune said:

    @bgpergo, That’s correct. I’m fixing that in an upcoming diff. Just haven’t gotten to it yet.

  22. bpgergo said:

    @pcardune, I’m trying to use my app_id and getting this error while authenticating:

    An error occurred with $appname. Please try again later.

    API Error Code: 191
    API Error Description: The specified URL is not owned by the application
    Error Message: Invalid redirect_uri: Given URL is not allowed by the Application configuration.

    I’m new to facebook apps, could you please help me, what should I configure on my app page? I suspect I have to set redirect uri ( into a certain field, but which field?

    Thanks for your help!

  23. bpgergo said:

    hm… very strange, I’m getting this same error
    An error occurred with foo. Please try again later.

    API Error Code: 191
    API Error Description: The specified URL is not owned by the application
    Error Message: Invalid redirect_uri: Given URL is not allowed by the Application configuration.

    When trying to generate a new access_token on the Graph API Explorer page

    Is this some kind of bug or am I missing something?

  24. light said:

    Is it possible to get all the url of images of all my friends using FQL?

  25. redog said:

    How do you add/delete a friend?

  26. When I try fb.graph(‘A_PROFILE/picture’) it doesn’t work:
    Traceback (most recent call last):
    File “”, line 1, in
    File “.fbconsole.py”, line 174, in graph
    return json.load(urllib2.urlopen(_get_url(path, args=params)))
    File “/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/json/__init__.py”, line 278, in load
    File “/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/json/__init__.py”, line 326, in loads
    File “/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/json/decoder.py”, line 360, in decode
    File “/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/json/decoder.py”, line 378, in raw_decode
    ValueError: No JSON object could be decoded

    is it expected?


  27. pcardune said:

    That’s because //picture returns a jpeg file, not a json response. What are you trying to do exactly? If you are looking for some other handling for images from graph api, you might want to open an issue on the github project: https://github.com/facebook/fbconsole

  28. I’d like to grab the picture of a profile and show on my application… how could I do that using fb.graph?


  29. k said:

    Hi. I have a stupid question. Can we fetch the links of all updates of a page, a wall, or a group?

  30. Thorsten Lindmeier said:

    Hi, I just found your script to update my status on facebook. When I tryout the >>> print “Hello”,graph(‘/me’)[‘name’] the console drops a Traceback

    File “C:\Python27\lib\urllib2.py”, line 521, in http_error_default
    raise HTTPError(req.get_full_url(), code, msg, hdrs, fp)
    HTTPError: HTTP Error 400: Bad Request

    Is there a change in the FB API ?

  31. rene said:

    how can i @tag someone using the status update? i tried something i saw on some other page in which they said to use this format: @[{UID}:1:{UserName}] but it just writes that to the status instead of tagging my friend, any hints?

  32. Secura said:

    Wow! awesome !. A question for you , do you have a Interface implemented to post to Facebook groups , or help me with pointers to get started on this ? I have a simple task to upload a Trance group I own with my latest track findings , so I am looking to cook up something like a Batch script which could read from a Txt File , Youtube links and post them in my group daily.
    I know there are concerns with this about spamming a group , but this is an interesting use-case as well.

  33. firesofmay said:

    I have tried this before i saw this post, and i must say, its Awesomeeeee!! :)
    Thank you so much for taking the pain to code it and release it and giving out a nice simple doc which is to the point.!!

  34. hucheshj said:

    Thanks a lot..!!!!!!!!!!!!!!!!11

  35. frog23 said:

    What’s the minimum Python version this will run on? It’s not running on 2.5. (json isn’t included…I tried importing simplejson as json but then also got the error “from urlparse import urlparse, parse_qs
    ImportError: cannot import name parse_qs”

    Will this run with Python 2.6?

  36. This has only been tested with python 2.6 and 2.7. I’ll see how easy it is to add support for python2.5 to the fbconsole python package, the code for which can be found here: https://github.com/facebook/fbconsole

  37. frog23 said:

    I got it to run on Python 2.5 by making just two simple changes. import json is now import simplejson as json, as I said. And I import parse_qs from the cgi module. And it runs.

    But I am unable to upload a photo. When I use this code:

    graph_post(“/me/photos”, {“message”:”My photo”, “source”:open(“python.png”)})

    I get this back in the console: “HTTPError: HTTP Error 400: Bad Request”. It *does*, however, allow me to post an update message (“Hello from my awesome script”) just fine.

    Any ideas?

  38. jarshvor said:

    Hi, thank you for ur script, but I have some problem, it seems to only work sporadically and I get socket urlopen Error 104: Connection reset by peer.

    Output is as following:
    (any help would be much appreciated, cheers ;)
    (fbconsole has been imported and session authenticated)

    >>> status = fbconsole.post(‘/me/feed’, {‘test’:’1100′})
    Traceback (most recent call last):
    File “/usr/lib/python3.2/urllib/request.py”, line 1136, in do_open
    h.request(req.get_method(), req.selector, req.data, headers)
    File “/usr/lib/python3.2/http/client.py”, line 964, in request
    self._send_request(method, url, body, headers)
    File “/usr/lib/python3.2/http/client.py”, line 1002, in _send_request
    File “/usr/lib/python3.2/http/client.py”, line 960, in endheaders
    File “/usr/lib/python3.2/http/client.py”, line 805, in _send_output
    File “/usr/lib/python3.2/http/client.py”, line 743, in send
    File “/usr/lib/python3.2/http/client.py”, line 1105, in connect
    File “/usr/lib/python3.2/ssl.py”, line 181, in wrap_socket
    File “/usr/lib/python3.2/ssl.py”, line 268, in __init__
    raise x
    File “/usr/lib/python3.2/ssl.py”, line 264, in __init__
    File “/usr/lib/python3.2/ssl.py”, line 443, in do_handshake
    socket.error: [Errno 104] Connection reset by peer

    During handling of the above exception, another exception occurred:

    Traceback (most recent call last):
    File “”, line 1, in
    File “/usr/lib/python3.2/site-packages/fbconsole.py”, line 628, in post
    return _get_client().post(path, params=params)
    File “/usr/lib/python3.2/site-packages/fbconsole.py”, line 541, in post
    return json.loads(opener.open(self.__get_url(path), params).read().decode(‘utf-8’))
    File “/usr/lib/python3.2/urllib/request.py”, line 369, in open
    response = self._open(req, data)
    File “/usr/lib/python3.2/urllib/request.py”, line 387, in _open
    ‘_open’, req)
    File “/usr/lib/python3.2/urllib/request.py”, line 347, in _call_chain
    result = func(*args)
    File “/usr/lib/python3.2/urllib/request.py”, line 1172, in https_open
    context=self._context, check_hostname=self._check_hostname)
    File “/usr/lib/python3.2/urllib/request.py”, line 1139, in do_open
    raise URLError(err)

  39. asking said:

    Great work, thanks for the contribution!

    I was wondering if I could use fbconsole to automate writing some settings information for application development purposes. The information is available via a url at my application, but I’m not certain if fbconsole will allow me to access and return that information in html. It’s not exactly graph data, but I was trying to do this:

    settings = fbconsole.get(‘/my-app/admin/controller/settings’)


    settings = fbconsole.get(‘http://apps.facebook.com/my-app/admin/controller/settings’)

    …both return errors, the first, bad url, the second, invalid port (I suppose fbconsole is wrapping HTTPConnection, so passing the url is an argument error, etc)…

    Anyway to do something like this via fbconsole?

    Thanks, adq

  40. Are you including this migration option? I can’t retrieve Recent Activity Posts :(

    Text of stories not intentionally generated by users, such as those generated when two users become friends; you must have the “Include recent activity stories” migration enabled in your app to retrieve these stories

  41. Rafael Louback Ferraz said:

    Traceback (most recent call last):
    File “./main.py”, line 4, in
    File “/home/louback/FacebookPublisher/fbconsole.py”, line 294, in authenticate
    data = json.loads(open(ACCESS_TOKEN_FILE).read())
    File “/usr/lib/python2.7/site-packages/anyjson/__init__.py”, line 130, in
    deserialize = lambda value: implementation.deserialize(value)
    File “/usr/lib/python2.7/site-packages/anyjson/__init__.py”, line 99, in deserialize
    raise ValueError(*exc.args)
    ValueError: No JSON object could be decoded: line 1 column 0 (char 0)

    Why is that?

  42. Rafael Louback Ferraz said:

    forget about it, I found the problem, thanks man

  43. Rafael Louback Ferraz said:

    Traceback (most recent call last):
    File “./main.py”, line 6, in
    status = fbconsole.post(‘me/feed’, {‘message’:’Testing Wall’})
    File “/usr/lib/python2.7/site-packages/fbconsole.py”, line 286, in post
    return json.load(urllib2.urlopen(request))
    File “/usr/lib64/python2.7/urllib2.py”, line 126, in urlopen
    return _opener.open(url, data, timeout)
    File “/usr/lib64/python2.7/urllib2.py”, line 400, in open
    response = self._open(req, data)
    File “/usr/lib64/python2.7/urllib2.py”, line 418, in _open
    ‘_open’, req)
    File “/usr/lib64/python2.7/urllib2.py”, line 378, in _call_chain
    result = func(*args)
    File “/usr/lib/python2.7/site-packages/poster/streaminghttp.py”, line 170, in https_open
    return self.do_open(StreamingHTTPSConnection, req)
    File “/usr/lib64/python2.7/urllib2.py”, line 1177, in do_open
    raise URLError(err)

    and that? is a bug?

  44. Louback said:

    How can I publish a picture on group feed? Im trying like that

    fbconsole.post(‘/257042030978195/feed’, {‘message’:’picture info’, ‘picture’:open(‘pic.jpg’)})

    this number is the group id.

  45. NJ said:

    I am trying to use GRAPH API to search for ‘Programming’ groups using ‘Request’ method as follows:

    LIMIT = 100
    while True:

    results = gapi.request(“search”,{“q”: “programming”,”type”: “group”,”limit”: LIMIT,”offset”: LIMIT *i})

    if not results[‘data’]:

    ids = [group[‘id’] for group in results[‘data’] if group[‘name’
    ].lower().find(‘programming’) > -1]

    # once groups stop containing the term we are looking for in their name, bail out

    if len(ids) == 0:
    group_ids += ids

    i += 1

    BUT I get the following error, do you know how I could resolve this. I appreciate your help.

    File “C:\Python27\Lib\SITE-P~1\PYTHON~2\pywin\framework\scriptutils.py”, line 325, in RunScript
    exec codeObject in __main__.__dict__

    File “C:\FacebookApps\facebook__graph_query.py”, line 39, in
    results = gapi.request(“search”,{“q”: “programming”,”type”: “group”,”limit”: LIMIT,”offset”: LIMIT *i})

    TypeError: __call__() takes exactly 1 argument (3 given)

  46. Please help, when I import fbconsole, I got this error
    Internal Server Error
    import_string() failed for ‘myapp.views.index’. Possible reasons are: – missing __init__.py in a package; – package or module path not included in sys.path; – duplicated package or module name taking precedence in sys.path; – missing module, class, function or variable; Debugged import: – ‘myapp’ found in ‘D:\\PythonProj\\LLL\\myapp\\__init__.pyc’. – ‘myapp.views’ not found. Original exception: ImportError: No module named fbconsole

    I installed fbconsole using pip install fbconsole

  47. mike said:

    Thanks this is amazing sir!

  48. mike said:

    how do i reset the access token?
    {u’error_subcode’: 463, u’error_code’: 190, u’error_msg’: u’Error validating access token: Session has expired at unix time 1361746800. The current unix time is 1361837574.’, u’request_args’: [{u’value’: u’fql.query’, u’key’: u’method’}, {u’value’: u’AAACjeiZB6FgIBACqHZCUunAzdQIuWN15nB01ypZBrp4Qr4QQM0mayDdw5ZBkq895m4LZC65ZBZC797m9KxrQOZAeFwX0v9AuHd9SFU4R6luy2kiLfZAOFU1jl’, u’key’: u’access_token’}, {u’value’: u’SELECT name FROM user WHERE uid IN (SELECT uid2 FROM friend WHERE uid1 = me())’, u’key’: u’query’}, {u’value’: u’json’, u’key’: u’format’}]}

  49. mike said:

    rm .fb_access_token

  50. avi said:

    This is just wonderful. Is it possible to get my wall data in JSON ?

  51. BlahBlah said:

    Dosnt work.
    Sham, was just what I was looking for

  52. Howdy, i read your blog occasionally and i own a similar one and i was
    just curious if you get a lot of spam comments?
    If so how do you reduce it, any plugin or anything you can recommend?
    I get so much lately it’s driving me mad so
    any help is very much appreciated.

  53. Others think the habit is morre likely connected
    to their checking the ground for the scent of its enemies, since the dog
    has its nose to the ground during the turning around. They may also
    thump to get attention, which might mean tuey want out off the cage to
    play and be wth the family. Well, veryone with dogs wants tto be like Amtrak.

  54. I think everything typed made a bunch of sense.But, what about this?
    suppose you were to create a killer post title? I aam not saying your information
    is not solid., but what if you added a title to maybe grab
    people’s attention? Imean Easy Facebook Scripting
    in Python | Heterogeneous Mixture is a little boring. You
    could glance at Yahoo’s front page and watch how they create
    news headlines to get viewers to open the links. You might try adding a video or a pic oor two to grab people interested about
    what you’ve got to say. Just my opinion, it would bring your blog a little livelier.

  55. WHY said:


  56. Sanford said:

    From left to right they are: a Camera (for choosing
    a photo to edit or taking a photo within the app), the Save icon (with a downward pointing arrow to save your labeled photo when finished), an
    Upload icon (with an upward pointing arrow) for sharing photos on Stepcase’s Steply social network, Facebook, Twitter,
    or Tumblr; and finally an S which, strangely, does the same function as the Upload icon.

    Best of all, you can write notes even without wifi
    connection. And this article isn’t written for the famous author or the
    next Jackson Pollack.

  57. Hello, Neat post. There is an issue with your website in internet explorer, could check this?
    IE nonetheless is the market leader and a big portion of other folks will omit your fantastic writing due to this problem.

  58. This piece of writing presents clear idea for the new visitors of blogging, that in fact how to do running a blog.

  59. Why viewers still use to read news papers when in this technological
    world the whole thing is presented on web?

  60. Wow, this piece of writing is nice, my younger sister is analyzing
    such things, thus I am going to let know her.

  61. Hi there, after reading this awesome paragraph i am as well glad to share my experience here with colleagues.

  62. Dotty said:

    This is my first time pay a visit at here and i am truly
    happy to read everthing at alone place.

  63. If you are going for finest contents like myself, only pay a quick visit this website all
    the time for the reason that it provides feature contents, thanks

  64. Whoa! This blog looks just like my old one! It’s on a entirely different topic but it
    has pretty much the same page layout and design.
    Wonderful choice of colors!

  65. Excellent goods from you, man. I have understand your stuff
    previous to and you are just too wonderful. I really like what you’ve acquired here, certainly like what you’re saying and the
    way in which you say it. You make it enjoyable and you still care for
    to keep it sensible. I can’t wait to read far more from you.
    This is really a tremendous website.

  66. whoah this blog is magnificent i love reading your posts.
    Stay up the great work! You realize, many individuals are searching around
    for this info, you can help them greatly.

  67. Kelsey said:

    It’s in reality a great aand useful piece of information. I am hqppy that you simply sharred this useful info with us.
    Please stay us informed like this. Thank you for sharing.

  68. Adolph said:

    I visited various web sites except the audio quality for audio songs present
    at this website is really fabulous.

  69. It’s amazing to pay a visit this web site and reading the views
    of all mates regarding this piece of writing, while I am also eager of getting familiarity.

  70. Thank you for any other excellent post. The place else may anyone get
    that type of info in such a perfect approach of writing?
    I’ve a presentation subsequent week, and I am on the search for such info.

  71. These are in fact impressive ideas in about blogging.

    You have touched some nice points here. Any way keep
    up wrinting.

  72. Hi there very nice site!! Guy .. Excellent .. Amazing ..
    I will bookmark your blog and take the feeds also? I’m glad
    to seek out so many useful information here in the post, we want work out extra strategies in this regard, thanks
    for sharing. . . . . .

  73. Elena said:

    Hello webmaster do you need unlimited articles for your blog ?

    What if you could copy article from other websites, make it
    unique and publish on your site – i know the right tool
    for you, just search in google:
    Loimqua’s article tool

  74. Hi there very cool web site!! Guy .. Excellent ..
    Superb .. I will bookmark your blog and take the feeds
    also? I am satisfied to search out so many useful info here in the
    publish, we want work out more techniques on this regard, thanks
    for sharing. . . . . .

  75. Hunter said:

    Very descriptive article, I liked that a lot.
    Will there bbe a part 2?

  76. Do you mind if I quote a couple of your articles as long as I
    progide credit and sources back to your weblog?
    My blog is in the exact sake niche as yours and mmy visitors would definitely benefit
    from some of thee information you provide
    here. Please let me know if this okay with you. Many thanks!

  77. Chau said:

    Wonderful article! We are linking to this particularly great content
    on our site. Keep uup the good writing.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s


Get every new post delivered to your Inbox.

Join 74 other followers

%d bloggers like this: