2010-05-05 3 views
2

Je consomme (via urllib/urllib2) une API qui renvoie des résultats XML. L'API retourne toujours le total_hit_count pour ma requête, mais me permet seulement de récupérer les résultats par lots de, disons, 100 ou 1000. L'API stipule que j'ai besoin de spécifier start_pos et end_pos pour compenser ceci, afin de parcourir les résultats.Pagination de requêtes vers une API

Dites que la requête urllib ressemble à http://someservice?query='test'&start_pos=X&end_pos=Y.

Si j'envoie une requête initiale de 'taster' avec le transfert de données le plus bas tel que http://someservice?query='test'&start_pos=1&end_pos=1 afin de récupérer un résultat de, pour conjecture, total_hits = 1234, je voudrais élaborer une approche pour demander plus proprement ces 1234 résultats en lots de, disons encore, 100 ou 1000 ou ...

C'est ce que j'ai trouvé jusqu'à présent, et cela semble fonctionner, mais j'aimerais savoir si vous auriez fait les choses différemment ou si Je pourrais améliorer à ce sujet:

hits_per_page=100 # or 1000 or 200 or whatever, adjustable 
total_hits = 1234 # retreived with BSoup from 'taster query' 
base_url = "http://someservice?query='test'" 
startdoc_positions = [n for n in range(1, total_hits, hits_per_page)] 
enddoc_positions = [startdoc_position + hits_per_page - 1 for startdoc_position in startdoc_positions] 
for start, end in zip(startdoc_positions, enddoc_positions): 
    if end > total_hits: 
     end = total_hits 
    print "url to request is:\n ", 
    print "%s&start_pos=%s&end_pos=%s" % (base_url, start, end) 

ps Je suis un consommateur de longue date de StackOverflow, en particulier les questions Python, mais c'est ma première question postée. Vous êtes génial.

Répondre

1

Je suggère d'utiliser

positions = ((n, n + hits_per_page - 1) for n in xrange(1, total_hits, hits_per_page)) 
for start, end in positions: 

puis vous inquiétez pas de savoir si end dépasse hits_per_page à moins que l'API que vous utilisez se soucie vraiment si vous demandez quelque chose hors de portée; la plupart vont gérer ce cas avec élégance.

P.S. Découvrez httplib2 en remplacement du combo urllib/urllib2.

+0

Une tranche d'or frit, merci. Je retire mon chapeau. Maintenant, comment puis-je "virtuellement" enlever mon chapeau à votre excellente contribution? – craigs

+0

L'upvote était un bon début ;-) –

1

Il peut être intéressant d'utiliser une sorte de générateur pour ce scénario pour itérer sur la liste.

def getitems(base_url, per_page=100): 
    content = ...urllib... 
    total_hits = get_total_hits(content) 
    sofar = 0 
    while sofar < total_hits: 
     items_from_next_query = ...urllib... 
     for item in items_from_next_query: 
      sofar += 1 
      yield item 

Code La plupart du temps juste pseudo, mais il pourrait se révéler très utile si vous avez besoin de faire cela plusieurs fois en simplifiant la logique qu'il faut pour obtenir les éléments qu'il retourne uniquement une liste qui est tout à fait naturel en python.

Épargnez-vous également un peu de code en double.

Questions connexes