Contenu | Rechercher | Menus

Annonce

Si vous avez des soucis pour rester connecté, déconnectez-vous puis reconnectez-vous depuis ce lien en cochant la case
Me connecter automatiquement lors de mes prochaines visites.

À propos de l'équipe du forum.

#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 hmm
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 smile

Hors ligne