Search code examples
pythongoogle-app-enginegetflickr

Error while importing Flickr api using Python on Google App Engine


I'm trying to do a really simple Python webservice. It makes a 'photo.search' using the Flickr API and returns the titles and photos' url.

This webservice will be hosted on Google App Engine.

This is what I actually have right now :

import webapp2
from urllib import urlencode, urlopen
from xml.dom import minidom
from google.appengine.api import urlfetch

class MainPage(webapp2.RequestHandler):

  def get(self):
    self.response.headers['Content-Type'] = 'text/plain'

    data = _doget('flickr.photos.search', text='to_search', per_page='2')
    self.response.write('Ok')

  def _prepare_params(params):
    for (key, value) in params.items():
        if isinstance(value, list):
            params[key] = ','.join([item for item in value])
    return params

  def _doget(method, auth=False, **params):

    params = _prepare_params(params)
    url = 'http://flickr.com/services/rest/?api_key=%s&method=%s&%s%s'% \
          ('stackoverflow_key', method, urlencode(params),
                  _get_auth_url_suffix(method, auth, params))

    result = urlfetch.fetch(url)
    minidom.parse(result.content)
    return result

application = webapp2.WSGIApplication([
    ('/', MainPage),
], debug=True)

I'm a beginner at Python, so I apologize if I did huge mistakes :) I tried several tutorials and sample codes that didn't work.

The imports are making a 500 server error

Error: Server Error

The server encountered an error and could not complete your request.
If the problem persists, please report your problem and mention this error message and the query that caused it.

Does anyone can tell me what's wrong with it ?

If anyone have samples code that did the trick, could be nice.

Thanks a lot in advance for your time!! :D

EDIT :

All right, I changed my code, it's way simplier than before, for testing :

import webapp2
from urllib import urlencode, urlopen
from xml.dom import minidom
from google.appengine.ext.webapp.util import run_wsgi_app
import hashlib
import os


HOST = 'http://api.flickr.com'
API = '/services/rest'
API_KEY = 'my_key'


class MainPage(webapp2.RequestHandler):

     def get(self):
        self.response.headers['Content-Type'] = 'text/html'

        data = _doget('flickr.photos.search', auth=False, text='to_search', per_page='1')
        if data:
           self.response.write(data)
        else:
            self.response.write('Error')

 def _doget(method, **params):

    url = '%s%s/?api_key=%s&method=%s&%s&format=json'% \
      (HOST, API, API_KEY, method, urlencode(params))

    res = urlfetch.fetch(url).content

    # Flickr JSON api returns not valid JSON, which wrapped with "jsonFlickrApi(...)", so we get rid of it.
    if 'jsonFlickrApi(' in res:
        return res[14:-1]

    return json.loads(res)

application = webapp2.WSGIApplication([
    ('/', MainPage),
], debug=True)

When I copy/paste this url, it works perfectly. My aim is to return the data as flickr returns it. But still not working. The print isn't even shown :(


Solution

  • At the first glance your app has several issues:

    1. I suppose HOST should be 'http://api.flickr.com'
    2. Indentation and formatting (: after if and else) in if-else statement in MainPage class
    3. Undefined varibale "photos" in self.response.write(photos)
    4. Undefined functions "_prepare_params", "_get_auth_url_suffix", "_get_data" and variable "debug" in _doget function.
    5. You should call read() method of urlopen result
    6. You should use minidom.parseString
    7. You can use run_wsgi_app to run your app

    So here is the working example:

    from google.appengine.ext.webapp.util import run_wsgi_app
    import webapp2
    from urllib import urlencode, urlopen
    from xml.dom import minidom
    import hashlib
    import os
    
    HOST = 'http://api.flickr.com'
    API = '/services/rest'
    API_KEY = 'my_key'
    
    debug = False
    
    class MainPage(webapp2.RequestHandler):
    
        def get(self):
            self.response.headers['Content-Type'] = 'text/html'
    
            data = _doget('flickr.photos.search', auth=False, text='boston', per_page='2')
    
            if data:
                photos = data.getElementsByTagName("photo")
                for photo in photos:
                    farm_id = 1 # ???
                    server_id = photo.attributes['server'].value
                    photo_id = photo.attributes['id'].value
                    secret = photo.attributes['secret'].value
                    photo_url = 'http://farm{farm_id}.staticflickr.com/{server_id}/{photo_id}_{secret}.jpg'.format(farm_id=farm_id,                                                                                                         server_id=server_id,                                                                                                         photo_id=photo_id,                                                                                                         secret=secret)
                    self.response.write('<img src="{0}">'.format(photo_url))
            else:
                self.response.write('Error')
    
    
    def _doget(method, auth=False, **params):
        #print "***** do get %s" % method
    
        params = params
        url = '%s%s/?api_key=%s&method=%s&%s'% \
          (HOST, API, API_KEY, method, urlencode(params))
    
        #another useful debug print statement
        if debug:
            print "_doget", url
    
        res = urlopen(url)
        res = res.read()
    
        return minidom.parseString(res)
    
    
    application = webapp2.WSGIApplication([('/', MainPage),], debug=True)
    
    def main():
        run_wsgi_app(application)
    
    if __name__ == "__main__":
        main()
    

    To format flickr photo url I used http://www.flickr.com/services/api/misc.urls.html, but I havent found where to get farm_id parameter, I hope you'll manage it by yourself )


    Furthermore, it can be easier to use json format by passing 'format=json' to the API request URL and a bit more properly to use GAE urlfetch service:

    import json
    from google.appengine.api import urlfetch
    
    # ...
    
    class MainPage(webapp2.RequestHandler):
        def get(self):
            # ...
            for photo in data['photos']['photo']:
                farm_id = 1 # ???
                server_id = photo['server']
                photo_id = photo['id']
                secret = photo['secret']
                # ...
    
    def _doget(method, auth=False, **params):
        # ...
        url = '%s%s/?api_key=%s&method=%s&%s&format=json'% \
          (HOST, API, API_KEY, method, urlencode(params))
    
        res = urlfetch.fetch(url).content
    
        # Flickr JSON api returns not valid JSON, which wrapped with "jsonFlickrApi(...)", so we get rid of it.
        if 'jsonFlickrApi(' in res:
            return res[14:-1]
    
        return json.loads(res)