Pages : 1
#1 Le 02/06/2012, à 16:20
- chaoswizard
Récupérer un album photo Facebook
Bonjour,
J'ai eu le malheur d'avoir à récupérer un album photo public sur Facebook
J'ai donc fait un programme en Python pour récupérer automatiquement le contenu d'un album.
Je ne compte pas en faire plus avec ce programme (j'ai récupéré mes albums et ça me va !) mais si quelqu'un veut maintenir/packager/... le code, ça pourrait être une bonne chose.
Il y a aussi un certains nombre d'amélioration à faire (du genre permettre de récupérer un album privé en loggant l'utilisateur).
L'utilisation est relativement simple :
- copier tout le code dans un fichier facebookdl.py
- enregistrer
- ouvrir un terminal et faire :
python facebookdl.py "urlGallerie"
En espérant que ça serve !
++
#!/usr/bin/env python
# -*- coding:Utf-8 -*-
#
# facebookdl.py : a tool to download Facebook pictures galleries
# example : python facebookdl.py "http://www.facebook.com/media/set/?set=a.10150776873218018.502767.393450018017"
#
#
# Infos
#
__author__ = "Chaoswizard"
__license__ = "GPL 2"
#
# Modules
#
import argparse
import BeautifulSoup
import collections
import cookielib
import logging
import os
import random
import re
import sys
import threading
import urllib2
import logging
logger = logging.getLogger( __name__ )
console = logging.StreamHandler( sys.stdout )
logger.setLevel( logging.DEBUG )
console.setLevel( logging.DEBUG )
logger.addHandler( console )
#
# Main function
#
def galleryDL( galleryLink, maxThread = 20 ):
browser = Browser( maxThread )
nextPage = galleryLink
pictureNumber = 1
while( nextPage is not None ):
# Get current gallery page
currentGalleryPage = BeautifulSoup.BeautifulSoup( browser.getFile( nextPage ) )
# Extract HTML comment block which contains links (to pages which contain pictures links)
linksBlock = BeautifulSoup.BeautifulSoup( currentGalleryPage.find( text = re.compile( "uiGrid fbPhotosGrid" ) ) )
# Extract links of pages which contains picture link
pagePictureLinksData = linksBlock.findAll( "a", { "class" : "uiMediaThumb uiScrollableThumb uiMediaThumbLarge" } )
pagePictureLinks = collections.OrderedDict( zip( map( lambda x : x[ "name" ], pagePictureLinksData ), map( lambda x : x[ "href" ], pagePictureLinksData ) ) )
# Retrieve pictures maxThread by maxThread
index = 0
while( index < len( pagePictureLinks ) ):
# Get pages which contain picture link
pagesPicture = browser.getFiles( pagePictureLinks.values()[ index : index + maxThread ] )
# Extract pictures links (and ordonate them)
picturesLinks = []
for pictureName, pictureLinkPage in pagePictureLinks.items()[ index : index + maxThread ]:
pagePicture = BeautifulSoup.BeautifulSoup( pagesPicture[ pictureLinkPage ] )
pictureLink = pagePicture.findAll( "img", { "class" : "fbPhotoImage img" } )[ 0 ][ "src" ]
picturesLinks.append( pictureLink.replace( "s720x720/", "" ) ) # Remove "s720x720/" to get the best resolution
# Download pictures
pictures = browser.getFiles( picturesLinks )
# Save pictures(and ordinate them)
for pictureLink in picturesLinks:
extension = os.path.splitext( pictureLink )[ 1 ]
with open( "img/%d%s" %( pictureNumber, extension ), "wb" ) as file:
file.write( pictures[ pictureLink ] )
pictureNumber += 1
index += maxThread
# Find if a next gallery page exists
try:
nextPageData = linksBlock.findAll( "a", { "class" : "pam uiBoxLightblue uiMorePagerPrimary" } )
nextPage = None
for nextPageBlock in nextPageData:
if( nextPageBlock.contents[ 1 ][ "class" ] == "mts mls arrow img sp_7xy8us sx_807777" ):
nextPage = nextPageBlock[ "href" ]
break
except:
nextPage = None
#
# Other classes
#
class Browser( object ):
timeOut = 60
userAgentsList = [ 'Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_5_5; fr-fr) AppleWebKit/525.18 (KHTML, like Gecko) Version/3.1.2 Safari/525.20.1',
'Mozilla/5.0 (Windows NT 6.1) AppleWebKit/535.1 (KHTML, like Gecko) Chrome/14.0.835.186 Safari/535.1',
'Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US) AppleWebKit/525.13 (KHTML, like Gecko) Chrome/0.2.149.27 Safari/525.13',
'Mozilla/5.0 (X11; U; Linux x86_64; en-us) AppleWebKit/528.5+ (KHTML, like Gecko, Safari/528.5+) midori',
'Mozilla/5.0 (Windows NT 6.0) AppleWebKit/535.1 (KHTML, like Gecko) Chrome/13.0.782.107 Safari/535.1',
'Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en-us) AppleWebKit/312.1 (KHTML, like Gecko) Safari/312',
'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/535.11 (KHTML, like Gecko) Chrome/17.0.963.12 Safari/535.11',
'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/535.8 (KHTML, like Gecko) Chrome/17.0.940.0 Safari/535.8' ]
def __init__( self, maxThread = 20 ):
self.maxThread = maxThread
# Cookiejar + urlopener
self.cookiejar = cookielib.CookieJar()
self.urlOpener = urllib2.build_opener( urllib2.HTTPCookieProcessor( self.cookiejar ) )
# User-agent
self.urlOpener.addheaders = [ ( 'User-agent', random.choice( self.userAgentsList ) ) ]
# Lock for threads
self.lock = threading.Lock()
# Semaphore
self.semaphore = threading.Semaphore( self.maxThread )
# Condition "no thread running"
self.noThreadRunning = threading.Condition()
# Number of running threads
self.runningThreads = 0
def getFile( self, url ):
try:
logger.debug( "GET %s" %( url ) )
request = urllib2.Request( url )
page = self.urlOpener.open( request, timeout = self.timeOut )
data = page.read()
return data
except urllib2.URLError, e :
if( hasattr( e, 'reason' ) ):
logger.debug( e.reason )
elif( hasattr( e, 'code' ) ):
logger.debug( "Erreur %d" %( e.code ) )
raise
except:
raise
## Use threads to download several files
# @param urlList URL list [ url1, url2, ... ]
# @return dictionnary { url1 : data1, url2 : data2, ... }
def getFiles( self, urlList ):
def threadGetFile( self, url, filesData ):
# Thread += 1
with self.lock:
self.runningThreads += 1
# Get data
data = self.getFile( url )
# Save data and thread -= 1
with self.lock:
filesData[ url ] = data
self.runningThreads -= 1
with self.noThreadRunning:
if( self.runningThreads == 0 ):
self.noThreadRunning.notify()
self.semaphore.release()
filesData = {}
currentFile = 0
if( len( urlList ) == 0 ):
return filesData
# Launch threads
while( currentFile < len( urlList ) ):
self.semaphore.acquire()
threading.Thread( target = threadGetFile,
args = ( self, urlList[ currentFile ], filesData )
).start()
currentFile += 1
# Wait the end of all threads
with self.noThreadRunning:
self.noThreadRunning.wait()
return filesData
if( __name__ == "__main__" ):
# Args
usage = "facebookdl galleryURL"
parser = argparse.ArgumentParser( usage = usage, description = "Download Facebook pictures galleries" )
parser.add_argument( "galleryURL", action = "store", help = "Facebook gallery URL" )
args = parser.parse_args()
# Check output folder
if( not os.path.isdir( "img" ) ):
os.makedirs( "img" )
galleryDL( args.galleryURL )
Ubuntu ==> Debian ==> Archlinux
Hors ligne
#2 Le 02/06/2012, à 17:19
- Diaxenne
Re : Récupérer un album photo Facebook
Facebook propose déjà de télécharger ces données sur la page : https://www.facebook.com/settings
Hors ligne
#3 Le 02/06/2012, à 17:37
- chaoswizard
Re : Récupérer un album photo Facebook
Et si on n'a pas de compte ?
Ubuntu ==> Debian ==> Archlinux
Hors ligne
#4 Le 02/06/2012, à 17:52
- Diaxenne
Re : Récupérer un album photo Facebook
J'aurai tendance à dire que si l'on n'a pas de compte l'on n'a pas à récupérer des images dont l'on n'est pas le propriétaire sauf dans 2 cas :
- L'image était libre de droit avant d'arriver sur Facebook (car quand elle arrive sur fb elle a perdu ces droits) et donc l'image doit être hébergées autres part.
- soit c'est pour un travail journalistique que l'on s'appuie sur le droit de citation et dans ce cas faire une capture d'écran me semble le plus judicieux.
Hors ligne
#5 Le 02/06/2012, à 18:04
- chaoswizard
Re : Récupérer un album photo Facebook
La en occurrence, c'est juste pour récupérer les photos d'une galerie publique...
Ubuntu ==> Debian ==> Archlinux
Hors ligne
#6 Le 15/09/2012, à 10:11
- U-topic
Re : Récupérer un album photo Facebook
Tombé par hasard sur ce sujet mais si ça t'intéresse ça se fait
Hors ligne
Pages : 1