Java: Facebook "Crawler" Part 2/2 - Videos [& Bilder Update!]

Einführung

Heute beschäftige wir uns mit den Videos auf Facebook. Im ersten Teil dieses "Tutorials" habe ich über den HTML-Source der Facebook Seite mir die Bilder extrahiert.
Das ist über etwas längere Zeit sehr mühselig, deshalb habe ich mir einen anderen Weg gesucht - Die API.

API - Erklärung

Die API erzeugt mir sogenannte JSON-Objekte wie bereits bei den YouTube-Videos erwähnt. Da dies aber das "Crawlen" um soviele Dinge erleichtern benutze ich es und werde im folgenden dies genauer erklären.

Als Facebook "User" nutze ich hier "WhatsApp" - http://facebook.com/whatspp


Bilder mit der Facebook API beziehen:

Da mein Ziel es war, einen kompletten Alben-Crawler zu schreiben musste ich nach kurzer Zeit feststellen es werden nur 25 von allen Bilder von der Webseite bezogen, da ein JavaScript dafür sorgt den Rest nach zu laden.
Da dies viel zu umständlich wurde, suchte ich nach einer simpleren Methode die auch schöner und dynamischer funktioniert. Also entschloß ich mich wie bei den YouTube Videos auf die API zurück zugreifen.

Also musste ich erst einmal verstehen was alles benötigt wird:
  • UserID in unserem Fall reicht: WhatsApp
  • Einen entsprechenden Request an die API
Und diesen benötigten Request sehen wir uns nun etwas genauer an.

Der Request 

Zunächst möchten wir alle Foto-Alben "bekommen" von unserem Profil (facebook.com/WhatsApp). Hierzu haben wir folgenden Request:



https://graph.facebook.com/WhatsApp/albums?fields=id
 
Nun zur Erklärung dazu:
Das Grundgerüst des Request wäre folgendes:
 
https://graph.facebook.com/[USERID/NAME]/{MedienTyp}?fields={id,title,link} 

Damit können wir nun von jedem beliebigen Profil die Alben einsehen. Voraussetzung dafür ist, 
dass die Alben "Public" also frei zugänglich sind.

Wenn wir jetzt allerdings alle Videos haben wollen würden, müsste der Request wie folgt aussehen:
 
https://graph.facebook.com/WhatsApp/videos?fields=source
 
Da auf der Facebook-Seite von
WhatsApp keine Videos zu finden sind,
bekommen wir ein leeres Array zurück.
 
Anders sieht es auf der Facebook-Seite von Facebook aus:
  
  Nun besitzen wir die direkten Video Links aber bei den Bildern nur die IDs der Foto-Alben.
D.h. wir brauchen nun einen Befehl, der uns die Bilder-Alben IDs aufdröselt und uns Facebook Bilder URLs zurück liefert. Dieser sieht wie folgt aus:

 https://graph.facebook.com/{ALBUM_ID}/photos?fields=source

Nun zum spannenden Teil der Java Klasse, die uns all das automatisch macht.
Das Update zum MediaDownloader folgt in kürze. Viel Spaß mit dem Code :)

DER CODE:

 
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

import java.io.*;
import java.net.URL;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Stream;

/**
 * Created by R3DST0RM on 23.04.2015.
 */
public class FacebookDownloader {
    private String fbLink;
    private String savePath;
    private String fbID;
    private boolean isAlbum;
    private boolean isVideo;

    public FacebookDownloader(String fbLink, String savePath, boolean isVideo){
        // determine if link is a album link
        // or complete profile (like: facebook.com/whatsapp)
        this.isVideo = isVideo;

        if(fbLink.contains("/media/")) { // just an album ...
            // id needed for processing json
            String[] URLArr = fbLink.split("/");
            String[] IDArr = URLArr[URLArr.length - 1].split("\\.");

            this.fbID = (IDArr[1].split("&"))[0];
            isAlbum = true;
        }
// complete profile
        else {
            String[] URLArr = fbLink.split("/");

            this.fbID = URLArr[URLArr.length - 1];
            isAlbum = false;
        }

        this.fbLink = fbLink;
    }

// Extrahiert alle Downloadlinks und gibt diese als Array zurück um diese dann herunterzuladen
    public String[] GetDownloadLinks(){
        if(isAlbum && isVideo){
            return GetLinksFromAlbum("https://graph.facebook.com/v1.0/" + fbID + "/videos?fields=source");
        }
        else if(isAlbum && !isVideo){
            return GetLinksFromAlbum("https://graph.facebook.com/v1.0/" + fbID + "/photos?fields=source");
        }
        else if(!isAlbum){
            String[] album_id = GetAlbumsFromProfile("https://graph.facebook.com/" + fbID + "/albums?fields=id");

            List links = new ArrayList<>();

            for (int i = 0; i < album_id.length; i++) {
                String[] tmp = GetLinksFromAlbum("https://graph.facebook.com/v1.0/" + album_id[i] + "/photos?fields=source");

                for (int j = 0; j < tmp.length; j++) {
                    links.add(tmp[j]);
                }
            }

            String[] allPictures = new String[links.size()];
            for (int i = 0; i < links.size(); i++) {
                allPictures[i] = links.get(i);
            }
            // is not videos is selected no videos will be selected:
            if(!isVideo)
                return allPictures;

            // if isVideo == true select all videos
            String[] videos = GetLinksFromAlbum("https://graph.facebook.com/v1.0/" + fbID + "/videos?fields=source");
            return Stream.concat(Arrays.stream(allPictures), Arrays.stream(videos))
                    .toArray(String[]::new);
        }
        else
            return null;
    }

// Hier holen wir uns alle verfügbaren Alben eines Profils
    private String[] GetAlbumsFromProfile(String url){
        try {
            JSONObject obj = readJsonFromUrl(url);
            String nextPage;
            try {
                nextPage = obj.getJSONObject("paging").getString("next");
            }catch (Exception ex){
                nextPage = "";
            }

            JSONArray arr = obj.getJSONArray("data");
            List itemlist = new ArrayList();

            for (int i = 0; i < arr.length(); i++) {
                try {
                    itemlist.add(arr.getJSONObject(i).getString("id"));
                }
                catch (Exception ex){
                    // ignore because if no video id is found move on
                }
            }

            String[] items = new String[itemlist.size()];
            for (int i = 0; i < itemlist.size(); i++) {
                items[i] = itemlist.get(i);
            }

            if(nextPage.equals(""))
                return items;
            else
                return Stream.concat(Arrays.stream(items), Arrays.stream(GetLinksFromAlbum(nextPage)))
                        .toArray(String[]::new);
        }catch (IOException ex){
            ex.printStackTrace();
            return null;
        }
    }

// Hier besorgen wir uns die Links eines Albums
    private String[] GetLinksFromAlbum(String url){
        String requestURL = url;

        try {
            JSONObject obj = readJsonFromUrl(requestURL);
            String nextPage;
            try {
                nextPage = obj.getJSONObject("paging").getString("next");
            }catch (Exception ex){
                nextPage = "";
            }

            JSONArray arr = obj.getJSONArray("data");
            List itemlist = new ArrayList();

            for (int i = 0; i < arr.length(); i++) {
                try {
                    itemlist.add(arr.getJSONObject(i).getString("source"));
                }
                catch (Exception ex){
                    // ignore because nothing sources are found
                }
            }

            String[] items = new String[itemlist.size()];
            for (int i = 0; i < itemlist.size(); i++) {
                items[i] = itemlist.get(i);
            }

            if(nextPage.equals("")) // abbruch bedingung
                return items;
            else
                return Stream.concat(Arrays.stream(items), Arrays.stream(GetLinksFromAlbum(nextPage)))
                        .toArray(String[]::new);
        }catch (IOException ex){
            ex.printStackTrace();
            return null;
        }
    }

    public JSONObject readJsonFromUrl(String url) throws IOException, JSONException {
        InputStream is = new URL(url).openStream();
        try {
            BufferedReader rd = new BufferedReader(new InputStreamReader(is, Charset.forName("UTF-8")));
            String jsonText = readAll(rd);
            JSONObject json = new JSONObject(jsonText);
            return json;
        } finally {
            is.close();
        }
    }

    private String readAll(Reader rd) throws IOException {
        StringBuilder sb = new StringBuilder();
        int cp;
        while ((cp = rd.read()) != -1) {
            sb.append((char) cp);
        }
        return sb.toString();
    }
}
Viel Spaß. Wenns euch gefällt könnt ihr mir dort einen Kaffee spendieren:


Grüße, R3DST0RM aka Dominik

Kommentare

Beliebte Posts aus diesem Blog

[ENGLISH] Capture the Flag at UCF - Write Up - Crypto - XORLY

Dr. Evil's Bombe (Binary Bomb Lab) | Teil 1