[python]upload de fichiers via requête POST

Bonjour!
Je suis en train d’écrire un script permettant d’uploader plus facilement mes videos sur dailymotion, et plus ensuite si ça marche.
J’ai donc récupérer une clé API et tout le blabla.
Je suis ce qui est dit là :
dailymotion.com/doc/api/gett … ing-videos
Cependant, je bloque au Deuxième 2. J’ai ce message d’erreur par python :

Bon, je dois mal m’y prendre, déja que c’est pas propre pour obtenir l’autorisation…
Donc voici deux questions :

  • Comment envoyer mon fichier par POST avec python?
  • Si possible, comment éviter d’ouvrir la page web pour autoriser l’authentification?

Bien sûr, voici le code pour tester. Il suffit de changer les variables dans la fonction main avec votre pseudo et mot de passe dailymotion.

[code]#!/usr/bin/env python

-- coding:Utf-8 --

Fichier: dailymopyup.py

Cree le 08 juin 2011 12:13:39

Derniere modification: 08 juin 2011 12:13:39

“”"

Auteur : thuban (thuban@singularity.fr)
licence : GNU General Public Licence

Description :
Script permettant d’uploader des videos sur Dailymotion

TODO :
Ajout d’un fichier de configuration, ou une meilleure présentation du
script afin de permettre de préciser :
le nom d’utilisateur
le mot de passe
le navigateur à utiliser
"""

try:
import sys
import urllib.request, urllib.parse
import os

except ImportError as err:
print (“Couldn’t load module. {0}”.format(err))
sys.exit(2)

def authentify(username,password):
’’’ Fonction pour s’authentifier sur dailymotion
prend pour arguments le login username et le mot de passe password
’’’

clientId = '3224716f65ec913ee931'
clientPassword = '85fe767252de62b4d3d16b489acaa92651bfc175'
p = urllib.parse.urlencode({'grant_type' : 'password',\
                            'client_id' : clientId, \
                            'client_secret' : clientPassword, \
                            'username' : username,\
                            'password' : password})
p = p.encode('utf-8')
resp = urllib.request.urlopen('https://api.dailymotion.com/oauth/token', p)
resp = resp.read().decode('utf-8')
resp = resp.split('"')
accessToken = resp[3]

# now we use the access token
urllib.request.urlopen('https://api.dailymotion.com/videos?'+'access_token='+accessToken )

# asking for rights

p = urllib.parse.urlencode({‘response_type’ : ‘code’, \

‘client_id’ : clientId, \

‘redirect_uri’ :

http://www.example.com/callback’, \

‘scope’ : ‘read write’})

p = p.encode(‘utf-8’)

#r = urllib.request.urlopen('https://api.dailymotion.com/oauth/authorize?', p)
#print(r.read().decode('utf-8'))

# Ce qui est ci-dessus de fonctionne pas, je me rabat sur une solution
# hyper moche
os.system('/usr/bin/x-www-browser https://api.dailymotion.com/oauth/authorize?response_type=code\&client_id=3224716f65ec913ee931\&redirect_uri=http://www.example.com/callback\&scope=read+write')



return accessToken

def upload(accessToken, video):
# asking a file url
p = urllib.parse.urlencode({‘access_token’ : accessToken})
r = urllib.request.urlopen(‘https://api.dailymotion.com/file/upload?%s’ % p)
r = r.read().decode(‘utf-8’).replace(’\’, ‘’)
r = r.split(’"’)
print®
uploadUrl = r[3]
# now we have the url
# let’s upload
with open(video, ‘r’) as v:
p = urllib.parse.urlencode({‘access_token’ : accessToken, ‘file’ : v})
p = p.encode(‘utf-8’)
r = urllib.request.urlopen(uploadUrl, p)
r = r.read().decode(‘utf-8’)
print®

def main():
username = 'LOGIN’
passwd = '****
video = ‘/home/xavier/out.ogv’

try:
     accessToken = authentify(username, passwd)
except:
     print('Impossible de s\'authentifier')
     sys.exit(2)

upload(accessToken, video)


return 0

if name == ‘main’:
main()

vim: tabstop=4 expandtab shiftwidth=4 softtabstop=4

[/code]

Ben, je suis pas spécialiste de ce genre de chose, mais tu sembles utiliser les bons trucs pour envoyer ton fichier en POST.

Ce serait intéressant de savoir d’où exactement provient cette réponse avec ce code d’erreur (très probablement la réponse à r = urllib.request.urlopen(uploadUrl, p) ?).

En fait, dailymotion attend un envoi du fichier selon le format “formulaire” (multipart/form-data)… Je n’ai pas le temps de creuser la question, mais j’ai trouvé cette page, qui devrait pouvoir t’aider, je pense (même s’il faudra adapter de httplib à urllib :wink: ) :

code.activestate.com/recipes/146 … form-data/

(Ou bien, fouille le net avec ces mots clé : http post multipart/form-data ).

ouais, j’ai pas mal fouillé, mais il n’y a que des trucs vieux, et comme je fais l’effort d’utiliser du python3… Le serveur refuse le fichier car il n’est pas transféré en tant que video, mais du texte ou un truc incohérent en tout cas… C’est pas tout simple ma foi!

Non, je crois que tu ne m’as pas compris… Le serveur n’attend pas un transfert POST “simple” du fichier, il le veut “inclus” dans un “enrobage” qui respecte la norme des formulaires sur le WEB – autrement dit, il attend un flux de type multipart/form-data, dans lequel est contenu ton fichier vidéo…

Le lien que je t’ai donné (code.activestate.com/recipes/146 … form-data/) illustre comment générer des données au format multipart/form-data contenant des fichiers – il te reste à l’adapter (urllib te simplifie un peu la vie, utilise deux fields access_token et file, etc.) – ce qui ne devrait pas être bien difficile :wink:

Effectivement je ne comprend pas tout, et c’est bien là le problème. En tout cas merci d’accorder de ton temps pour me renseigner :wink: .

En fait je suis tombé souvent sur le lien que tu m’as donné. Après avoir laissé passer un peu de temps je suis revenu dessus ce soir et c’est un peu plus clair.
Alors, tu me dis si je me trompe :
Les fields, c’est les champs que l’on passe en général dans l’adresse url lorsque l’on fait une POST. Par exemple :
api.dailymotion.com/video?name= … er=out.ogv
où name est un champ et nomdemavideo sa valeur.

Ensuite, viennent les files dans le code du lien donné. Ils sont définis comme ça :

Alors, le nom du fichier, on met ce que l’on veut? filename, c’est quoi alors? et value? Je me perd à ce niveau là, car dans mon cas, je veux juste envoyer une vidéo :
Donc du coup, son nom c’est out.ogv, le filename (par traduction), c’est aussi out.ogv et value aucune idée…

[quote=“thuban”]Les fields, c’est les champs que l’on passe en général dans l’adresse url lorsque l’on fait une POST. Par exemple :
api.dailymotion.com/video?name= … er=out.ogv
où name est un champ et nomdemavideo sa valeur.[/quote]

C’est presque ça :slightly_smiling:

En fait, l’idée est de simuler le retour de données générées par un formulaire web classique – les fields sont donc les champs d’un “formulaire virtuel”, tu ne les verras jamais dans l’addresse, car cette forme de requête est réservée au body d’un POST…

En fouillant un peu sur le net, on se rend compte que l’encodage multipart/form-data est un standard pour l’upload de fichier… et que c’est une lacune de la bibliothèque standard de python actuellement (avec un peu de chance, ça pourrait changer d’ici la 3.3, cf google.com/url?sa=t&source=w … Sg&cad=rja ).

En attendant, la solution précédente ne marcherait qu’avec http.client. Pour utiliser urllib, j’ai trouvé ça : atlee.ca/software/poster/index.html.

Voici un exemple de ton code utilisant cette bibliothèque, malheureusement en python2 car la lib ne supporte pas py3 – ça ne devrait pas être très difficile de la convertir, ceci dit, elle n’est pas bien grosse :wink: (code pas testé, mais j’ai bon espoir que ça marche :033 ) :

[code]#!/usr/bin/env python

-- coding:Utf-8 --

Fichier: dailymopyup.py

Cree le 08 juin 2011 12:13:39

Derniere modification: 08 juin 2011 12:13:39

“”"

Auteur : thuban (thuban@singularity.fr)
licence : GNU General Public Licence

Description :
Script permettant d’uploader des videos sur Dailymotion

TODO :
Ajout d’un fichier de configuration, ou une meilleure présentation du
script afin de permettre de préciser :
le nom d’utilisateur
le mot de passe
le navigateur à utiliser
“”"

try:
import sys
import urllib2.request, urllib2.parse
import os
import poster.encode
import poster.streaminghttp

# Register the streaming http handlers with urllib2
poster.streaminghttp.register_openers()

except ImportError as err:
print(“Couldn’t load module. {0}”.format(err))
sys.exit(2)

def authentify(username,password):
‘’’ Fonction pour s’authentifier sur dailymotion
prend pour arguments le login username et le mot de passe password
‘’’

clientId = u'3224716f65ec913ee931'
clientPassword = u'85fe767252de62b4d3d16b489acaa92651bfc175'
p = urllib2.parse.urlencode({'grant_type' : u'password',
                             'client_id' : clientId,
                             'client_secret' : clientPassword,
                             'username' : username,
                             'password' : password})
p = p.encode('utf-8')
resp = urllib2.request.urlopen('https://api.dailymotion.com/oauth/token', p)
resp = resp.read().decode('utf-8')
resp = resp.split('"')
accessToken = resp[3]

# now we use the access token
urllib2.request.urlopen('https://api.dailymotion.com/videos?'+'access_token='+accessToken )

# asking for rights

p = urllib2.parse.urlencode({‘response_type’ : ‘code’, \

‘client_id’ : clientId, \

‘redirect_uri’ :

http://www.example.com/callback’, \

‘scope’ : ‘read write’})

p = p.encode(‘utf-8’)

#r = urllib2.request.urlopen('https://api.dailymotion.com/oauth/authorize?', p)
#print(r.read().decode('utf-8'))

# Ce qui est ci-dessus de fonctionne pas, je me rabat sur une solution
# hyper moche
os.system('/usr/bin/x-www-browser https://api.dailymotion.com/oauth/authorize?response_type=code\&client_id=3224716f65ec913ee931\&redirect_uri=http://www.example.com/callback\&scope=read+write')

return accessToken

def upload(accessToken, video):
# asking a file url
p = urllib2.parse.urlencode({‘access_token’ : accessToken})
r = urllib2.request.urlopen(‘https://api.dailymotion.com/file/upload?%s’ % p)
r = r.read().decode(‘utf-8’).replace(’\’, ‘’)
r = r.split(’"’)
print®
uploadUrl = r[3]
# now we have the url
# let’s upload
with open(video, ‘r’) as v:
p, h = poster.encode.multipart_encode({‘access_token’: accessToken, ‘file’: v})
p = p.encode(‘utf-8’)
# XXX Not sure this would work, so rather using a plain Request object…
#r = urllib2.request.urlopen(uploadUrl, p, h)
r = urllib2.Request(uploadUrl, p, h)
r = urllib2.urlopen®.read().decode(‘utf-8’)
print®

def main():
username = u’LOGIN’
passwd = u’****
video = ‘/home/xavier/out.ogv’

try:
     accessToken = authentify(username, passwd)
except:
     print('Impossible de s\'authentifier')
     sys.exit(2)

upload(accessToken, video)

return 0

if name == ‘main’:
main()

vim: tabstop=4 expandtab shiftwidth=4 softtabstop=4

[/code]

Houla! Merci beaucoup je vais étudier ça! Ça m’embête un peu de repasser vers le python 2, mais si je n’ai pas le choix… Ce matin j’ai essayé de convertir ceci à python 3 : peerit.blogspot.com/2007/07/mult … k-for.html . Là je teste, car j’ai du supprimer pas mal de choses.

Une question

Merci pour tout, j’ai du pain sur la planche!

Bon, trop de galère, python 3 n’est finalement pas prêt pour ça! J’ai réutilisé ta proposition, après quelques modifications pour adapter ça à urllib et urllib2 et tout et tout, et là, l’upload fonctionne! MErci pour tes conseils! En plus, le module poster est dans les dépots debian :slightly_smiling: .
Je vais enfin pouvoir avancer! Vivement que la biblio standard de python3 s’améliore!

[quote=“thuban”]Bon, trop de galère, python 3 n’est finalement pas prêt pour ça! J’ai réutilisé ta proposition, après quelques modifications pour adapter ça à urllib et urllib2 et tout et tout, et là, l’upload fonctionne! MErci pour tes conseils! En plus, le module poster est dans les dépots debian :slightly_smiling: .
Je vais enfin pouvoir avancer! Vivement que la biblio standard de python3 s’améliore![/quote]
Et tu publie pas ? :slightly_smiling:

Ça vient ça vient! :slightly_smiling: .
Je vais pas publier un brouillon comme ça, faut encore que je paufine, que je teste…
De plus, ce n’est pas fini, dailymotion ne simplifie pas les choses. L’upload fonctionne, mais ensuite, il faut activer la vidéo, et pour ça il me faut acquérir des droits d’écriture sur le compte… Et comme j’aimerais éviter d’ouvrir un navigateur web pour faire ça (seule méthode documentée), j’attend leur réponse à ma question.
Sinon, c’est presque fini :slightly_smiling: .

ps : en attendant, je peaufine le script d’upload d’image sur pix.toile-libre, là je galère avec les regexp pour récupérer les liens :s

Miam miam ! Tu veux pas de mon aide ? J’adore les regex :007 , j’en mange à tous les repas :033

Désolé, je m’en suis sorti :slightly_smiling: . Je ne sais pas comment tu fais, c’est imbuvable ce genre de trucs :smiley:

Bon, ça m’agace, dailymotion de réponds pas… Leur méthode est censée marcher, ils donnent même des exemples utilisant curl, sauf que derrière tout ça il semble que leur système ne fonctionne pas…
Il va falloir attendre quelque temps on dirais :s (pour une fois que c’était bien parti! :013 )