Proszę o przekazywanie wsparcia w ramach 1 proc. podatku dla Krzysia Bulczaka, największego bohatera, jakiego znam. KRS 0000037904 z dopiskiem 20374 Bulczak Krzysztof

Łatwe pozyskiwanie danych z Facebooka w R i Pythonie

Niedawno w Katowicach, w ramach konferencji Kultura w danych, prowadziłem warsztat wprowadzający do R. Niestety nie starczyło nam czasu na przećwiczenie wyciągania danych z mediów społecznościowych (Facebooka i Twittera). Chciałbym nadrobić to dwiema notkami przedstawiającymi sposób pracy z pakietami Rfacebook (pierwsza notka) i TwitteR (notka druga, wkrótce). Po warsztacie organizowanym w ramach Toruńskich Konfrontacji Archiwalnych postanowiłem dodać do tego krótki przewodnik po podobnych, prostych narzędziach do Pythona, których przewaga polega na tym, że można z nich korzystać właściwie bez znajomości języka (z pakietami w R nie jest już tak łatwo).

Po co ściągać dane z mediów społecznościowych?

  • mogą być podstawą analiz w dziennikarstwie danych;
  • do celów naukowych w badaniach medioznawczych, językowych, w socjologii czy nawet historii najnowszej;
  • w celu wyciągnięcia z komercyjnych i zamkniętych platform danych i zasobów publikowanych przez instytucje publiczne (polskie instytucje wciąż nie publikują swoich archiwów, chociaż da się to robić np. w Wielkiej Brytanii);
  • do aktywnego śledzenia wojny informacyjnej; przykładowo, w metadanych pojedynczego tweeta znajdują się informacje o użytkowniku, w tym dacie założenia konta – jesteśmy więc w stanie, pozyskując tweety dla wybranego hashtagu sprawdzić, jaka część spośród wypowiadających się pod nim użytkowników to niedawno założone, a może opłacone i trollowe konta;
  • archiwa mediów społecznościowych mogą być częścią archiwów Webu, zwłaszcza tych budowanych w celu dokumentowania ważnych wydarzeń (event harvesting);
  • pracę z danymi z mediów społecznościowych można wykorzystać w edukacji medialnej, np. do upowszechniania wiedzy o zagrożeniach wobec prywatności w Internecie.

Pobieranie danych przez Rfacebook

Opisując wybrane metody pakietu Rfacebook pomijam podstawy – instalację R i instalację RStudio oraz instalację i uruchamianie pakietów.

Pakiet Rfacebook posiada dwie metody łączenia się z API Facebooka:

  • wygenerowanego za pomocą danych aplikacji tokena (funkcja fbOAuth, metoda niedziałająca już w API 2.11);
  • tymczasowego tokena (do wygenerowania i pobrania na stronie developers.facebook.com/tools/explorer/

1. Instalujemy i uruchamiamy pakiet Rfacebook oraz dplyr (wraz z zależnościami)

install.packages('Rfacebook')
library(Rfacebook)

2. Do wektoru wpisujemy token:

token <- "XXXXXXXXXXXXXXXXXXXXXXXXXXX"

3. Możemy teraz skorzystać z funkcji z pakietu Rfacebook.

  • Pobranie postów i ich metadanych z publicznej strony: korzystamy z funkcji getPage, do której podać musimy id lub nazwę interesującej nas strony (np. kancelaria.premiera) oraz token (będzie aktywny 1-2 godziny, więc w czasie pracy może pojawić się potrzeba jego odświeżenia).
    
    # składnia funkcji
    
    getPage(page, token, n = 25, since = NULL, until = NULL, feed = FALSE,
      reactions = FALSE, verbose = TRUE, api = NULL)
    
    # ściągamy 2000 najnowszych postów ze strony Kancelarii Premiera
    
    p <- getPage('kancelaria.premiera', token, n = 2000)
    
    # 25 posts 50 posts 75 posts 100 posts 125 posts 150 posts 175 posts 200 posts 225 posts 250 posts 275 posts 300 posts 325 posts 350 posts 375 posts 400 posts 425 posts 450  
    # posts 475 posts 500 posts 525 posts 550 posts 575 posts 600 posts 625 posts 650 posts 675 posts 700 posts 725 posts 750 posts 775 posts 800 posts 825 posts 850 posts...
    
    # p to zwykła data.frame, możemy łatwo policzyć kilka podstawowych statystyk
    # np: średnia i mediana lajków
    
    mean(p$likes_count)
    # [1] 349.2405
    
    median(p$likes_count)
    # [1] 255
    
    # lub sprawdzić, jakiego typu treści były publikowane na tej stronie i jak często
    
    print(as.data.frame(table(p$type)))
    #     Var1 Freq
    # 1  event    6
    # 2   link  105
    # 3  photo 1325
    # 4 status    4
    # 5  video  560
    
    
  • pobranie postów i ich metadanych z publicznej grupy: robimy to za pomocą funkcji getGroup:
    
    # składnia funkcji
    
    getGroup(group_id, token, n = 25, since = NULL, until = NULL,
      feed = TRUE, api = NULL)
    
    
  • Aby pobrać komentarze, korzystamy z funkcji getPost. Aby zebrać komentarze dla grupy postów, musimy tę funkcję uruchomić w pętli. Można to zrobić definiując sobie własną funkcję, która przyjmuje trzy argumenty:
    getFbComments <- function(id,z,token){
      # id - zestaw ID postów
      # z - maksymalna liczba komentarzy zwracanych dla każdego postu
      # token: https://developers.facebook.com/tools/explorer/
      c <- as.data.frame(NULL)
      for(i in id){
        u <- getPost(i,token,n=z)
        # u = a list with 3 dataframes
        c <- rbind(u$comments,c)
      }
      # return: df
      return(c)  
    }
    
    # komentarze dla 2k postów z kancelaria.premiera
    # z limitem max 50 komentarzy dla jednego postu
    
    komentarze <- getFbComments(p$id,token,50)
    
    # otrzymujemy data.frame
    
    

    Aby pozyskać komentarze do komentarzy, potrzebujemy informacji o id każdego nadrzędnego komentarza. Korzystamy z funkcji getCommentReplies:

     
    
    getCommentReplies(comment_id, token, n = 500, replies = TRUE,
      likes = FALSE, n.likes = n, n.replies = n, api = NULL)
    
    

Zainteresowałem się tym pakietem chcąc testować możliwości łatwego pozyskiwania stron facebookowych instytucji publicznych (także w celu ich archiwizacji). Wydaje się, że pełna archiwizacja publicznej strony facebookowej powinna obejmować:

  • archiwizację postów i ich metadanych (getPage);
  • archiwizację komentarzy do tych postów (getPost,getCommentReplies);
  • pobranie plików multimedialnych z postów (dzięki getPage mamy bezpośrednie URLe postów, ale to na razie za mało)
  • zabezpieczenie stron zewnętrznych, które embedowane są w postach Facebookowych (w tabeli wygenerowanej przez getPage znajdziemy je filtrując po kolumnie type=link)

Przy archiwizacji takich danych i zasobów, obok problemu skali przyrastających nieustannie zbiorów i ich zróżnicowania dużym wyzwaniem jest prywatność użytkowników i prawo autorskie. Warto zwrócić uwagę, że ramka danych z komentarzami, zwracana przez funkcje getPostgetCommentReplies, zawiera kolumnę z imionami i nazwiskami komentujących użytkowników. Być może taki zestaw danych należałoby zanonimizować.

Ściąganie danych z Facebooka w Pythonie

Jeśli zależy nam wyłącznie na szybkim pozyskaniu danych z Facebooka, a nie pracujemy w R, możemy skorzystać z łatwych w użyciu skryptów pod Pythona, które pozwolą nam ściągnąć wybrane dane do plików csv. Podczas toruńskich warsztatów pracowaliśmy z tymi narzędziami. Przygotowanie ich do pobierania danych polegało na:

  • instalacji Pythona i konfiguracji globalnej ścieżki dostępu. Jeśli (w Windowsie) polecenie python nie chce uruchamiać się w terminalu w dowolnym miejscu na dysku to należy ustawić ścieżki, wklejając do terminala:

    dla Pythona 3.6.*

    set PATH=%PATH%;c:\Python36\;c:\Python36\Scripts\
    

    dla Pythona 2.7.*

    set PATH=%PATH%;c:\Python27\;c:\Python27\Scripts\
    
  • założenie aplikacji na developers.facebook.com, zanotowanie wartości App ID i App Secret;

  • uzupełnienie nagłówków w kodzie poszczególnych plików (wpisanie App ID i App Secret, id lub nazwy interesującej nas strony oraz zakresu czasowego, z którego chcemy pozyskać posty): np. dla pliku get_fb_posts_fb_page.py pozwalającego na ściąganie postów i ich metadanych z publicznej strony:
    
    app_id = "XXXXXXXXXXX"
    app_secret = "XXXXXX"  # DO NOT SHARE WITH ANYONE!
    page_id = "kancelaria.premiera"
    
    # input date formatted as YYYY-MM-DD
    since_date = "2006-01-01"
    until_date = "2017-12-13"
    
    

    Do tego testu ustawiłem radykalnie wczesną since_date żeby wyciągnąć wszystkie posty opublikowane na stronie Kancelarii Premiera od początku jej powstania.

  • Następnie w terminalu wpisujemy polecenie:

     
     python get_fb_posts_fb_page.py
     
    

    I w rezultacie:

    Scraping kancelaria.premiera Facebook Page: 2017-12-14 21:36:31.518821
    
    100 Statuses Processed: 2017-12-14 21:36:36.253140
    200 Statuses Processed: 2017-12-14 21:36:41.078512
    300 Statuses Processed: 2017-12-14 21:36:45.594180
    400 Statuses Processed: 2017-12-14 21:36:50.000518
    500 Statuses Processed: 2017-12-14 21:36:54.265567
    600 Statuses Processed: 2017-12-14 21:36:58.243678
    700 Statuses Processed: 2017-12-14 21:37:02.594908
    800 Statuses Processed: 2017-12-14 21:37:07.459451
    900 Statuses Processed: 2017-12-14 21:37:11.856431
    1000 Statuses Processed: 2017-12-14 21:37:16.264347
    1100 Statuses Processed: 2017-12-14 21:37:20.708165
    1200 Statuses Processed: 2017-12-14 21:37:25.205227
    1300 Statuses Processed: 2017-12-14 21:37:29.780774
    1400 Statuses Processed: 2017-12-14 21:37:33.835281
    1500 Statuses Processed: 2017-12-14 21:37:38.014699
    1600 Statuses Processed: 2017-12-14 21:37:41.951134
    1700 Statuses Processed: 2017-12-14 21:37:45.675367
    1800 Statuses Processed: 2017-12-14 21:37:49.182706
    1900 Statuses Processed: 2017-12-14 21:37:52.564717
    2000 Statuses Processed: 2017-12-14 21:37:55.861279
    2100 Statuses Processed: 2017-12-14 21:38:00.974090
    2200 Statuses Processed: 2017-12-14 21:38:04.418916
    2300 Statuses Processed: 2017-12-14 21:38:07.766826
    2400 Statuses Processed: 2017-12-14 21:38:11.846535
    2500 Statuses Processed: 2017-12-14 21:38:15.426276
    2600 Statuses Processed: 2017-12-14 21:38:19.099690
    2700 Statuses Processed: 2017-12-14 21:38:22.950521
    2800 Statuses Processed: 2017-12-14 21:38:27.177544
    2900 Statuses Processed: 2017-12-14 21:38:46.166000
    3000 Statuses Processed: 2017-12-14 21:38:50.137834
    3100 Statuses Processed: 2017-12-14 21:38:54.290690
    3200 Statuses Processed: 2017-12-14 21:38:58.469814
    3300 Statuses Processed: 2017-12-14 21:39:02.552608
    3400 Statuses Processed: 2017-12-14 21:39:06.214255
    3500 Statuses Processed: 2017-12-14 21:39:10.642598
    3600 Statuses Processed: 2017-12-14 21:39:14.381642
    3700 Statuses Processed: 2017-12-14 21:39:18.168685
    3800 Statuses Processed: 2017-12-14 21:39:21.791550
    3900 Statuses Processed: 2017-12-14 21:39:26.259844
    4000 Statuses Processed: 2017-12-14 21:39:30.390235
    
    Done!
    4049 Statuses Processed in 0:03:02.921990
    
    

    Najstarszy pozyskany post pochodził z 11 listopada 2009 roku. Wszystkie dane zapisywane są w pliku csv, który można łatwo otworzyć np. w Excelu.

  • Uruchomienie pliku get_fb_posts_fb_group.py pozwoli na ściągnięcie postów z otwartej grupy facebookowej, a get_fb_comments_from_fb.py komentarzy, przy czym będziemy musieli wcześniej pozyskać ID komentowanych postów (np. za pomocą get_fb_posts_fb_page.py). Wygenerowany wtedy plik csv będzie miał nazwę w stylu kancelaria.premiera_facebook_statuses.csv – wówczas do kodu get_fb_comments_from_fb.py wpisujemy:

    
    app_id = "<FILL IN>"
    app_secret = "<FILL IN>"  # DO NOT SHARE WITH ANYONE!
    file_id = "kancelaria.premiera"
    
    

    i uruchamiamy (dla Pythona 2.6.*)

    
    python get_fb_comments_from_fb.py
      
    

    lub dla Pythona 3.7.*

    
    python3 get_fb_comments_from_fb.py
      
    

    Popularne strony i grupy facebookowe mogą mieć setki tysięcy lub nawet miliony komentarzy, dlatego należy ostrożnie korzystać z tego narzędzia.

Walled garden

Na koniec mała uwaga: mówiąc o mediach społecznościowych lubię posługiwać się metaforą grodzonego ogrodu (walled garden). Jak pisze Anne Helmond, media społecznościowe są zamkniętymi platformami, rządzącymi się własnymi prawami i narzucającymi użytkownikom określone granice w tym, co mogą w nich robić. API, czyli interfejsy programistyczne to szczegółowo regulowane furtki dostępu do zasobów zamkniętych w tych platformach i jedyny legalny sposób na to, aby je pozyskiwać i przetwarzać na zewnątrz. Kiedy pracujemy z Facebookiem czy Twitterem jesteśmy tylko klientami, których prawa i obowiązki są ściśle określone, a same zasoby mają przy tym skomplikowany status prawnoautorski.

Przy korzystaniu z tych zasobów warto również pamiętać, że dane nigdy nie są neutralne i że ich interpretacji nie można bezrefleksyjnie uogólniać. Wciąż nie wszyscy przecież korzystają z Facebooka czy Twittera, a Web jest tylko jednym z mediów komunikowania o rzeczywistości. Platformy, z którymi chcemy pracować, nie tylko zbierają wiele informacji o swoich użytkownikach, ale też monitorują wykorzystanie własnych zasobów. Dlatego np. na Facebooku zmuszeni jesteśmy do założenia konta deweloperskiego i autoryzowania je numerem telefonu.

Podczas jednych z warsztatów pojawiło się ważne pytanie: czy narzędzia, za pomocą których będziemy ściągać dane z Facebooka (albo Twittera) mogą w naszym imieniu cokolwiek publikować w tych platformach? Pokazane w tym tutorialu metody pobierania danych łączą się z API Facebooka jedynie w trybie “tylko do odczytu”.

Komentarze? Uwagi? Kontakt: m[at]wilkowski.org

Udostępnij na na Twitterze | Udostępnij na Facebooku

Przeczytaj także