Получение постов и комментариев с Facebook с помощью Python. Часть 3

В предыдущей части мы рассмотрели использование Facebook Graph API для получения постов по дате. Затем мы внесли изменения в нашу базу данных для того, чтоб иметь возможность сохранять в ней данные, полученные из Facebook Graph API.

В третьей части мы объединим все предыдущее и покажем, как получать посты и комментарии со страниц Facebook. Мы будем опираться на методы и концепции, которые были описаны в предыдущих частях. Поэтому, если вы разобрались с Частью 1 и Частью 2, то этот пост не будет для вас сложным.

ПРЕДВАРИТЕЛЬНЫЕ ТРЕБОВАНИЯ:

Получение комментариев

Аналогично тому, как мы писали функцию создания URL для адресов постов, мы создадим и для адресов комментариев. Над нашей главной функцией добавьте следующий код:

def create_comments_url(graph_url, post_id, APP_ID, APP_SECRET):
    #create Graph API Call
    comments_args = post_id + "/comments/?key=value&access_token=" + \
        APP_ID + "|" + APP_SECRET
    comments_url = graph_url + comments_args

    return comments_url

По аналогии с функцией формирования адреса поста, тут мы передаём наш базовый graph_url, ID постав и наши параметры приложения: APP ID и APP Secret. Далее мы комбинируем post_id с аргументами комментариев и получаем адрес со списком комментариев.

Так же, как мы делали раньше, давайте посмотрим на возвращаемые данные, добавив один из полученных адресов в браузер. Для примера возьмём следующий адрес:

https://graph.facebook.com/post_id/comments/?key=value&access_token=APP_ID|APP_SECRET

Данные выглядят так:

JSON объект с комменатариями

Теперь напишем функцию для сбора этих данных. Она будет похожа на функцию, которую мы писали в Части 2 для получения данных постов. Скопируйте следующий код и вставьте его над основной функцией:

def get_comments_data(comments_url, comment_data, post_id):
    #render URL to JSON
    comments = render_to_json(comments_url)["data"]

    #for each comment capture data
    for comment in comments:
        try:
            current_comments = [comment["id"], comment["message"], comment["like_count"],
                                comment["created_time"], post_id]
            comment_data.append(current_comments)

        except Exception:
            current_comments = ["error", "error", "error", "error", "error"]

    #check if there is another page
    try:
        #extract next page
        next_page = comments["paging"]["next"]
    except Exception:
        next_page = None

    #if we have another page, recurse
    if next_page is not None:
        get_comments_data(next_page, comment_data, post_id)
    else:
        return comment_data

Давайте пробежимся по данной функции. Сначала мы запрашиваем список комментариев и преобразуем его в JSON объект. Затем для каждого комментария мы собираем его id, сообщение, время создания и добавляем к этому post_id. post_id — это ID поста, которому принадлежит комментарий.

Далее мы проверяем есть ли адрес следующей страницы комментариев. Если такой адрес есть, то мы вызываем функцию получения комментариев уже для него. Если нет, то просто возвращаем список собранных комментариев.

Добавляем таблицу комментариев

Теперь, когда у нас есть метод для получения комментариев, давайте создадим таблицу в базе данных для их хранения. Подключитесь к MySQL и выполните следующий код:

USE facebook_data;

CREATE TABLE comment_info(
    c_id INT NOT NULL PRIMARY KEY AUTO_INCREMENT,
    comment_id VARCHAR(200),
    message VARCHAR(800),
    likes_count BIGINT UNSIGNED,
    time_created DATETIME,
    post_id INT NOT NULL,
    INDEX(post_id),
    FOREIGN KEY(post_id) REFERENCES post_info(id) ON DELETE CASCADE
) ENGINE INNODB;

Он создаёт таблицу, в которой c_id — автоинкрементное поле для комментариев. Далее идут поля для полученных данных комментариев: id, сообщение, количество лайков, время создания, id поста. И в заключение мы создаём внешний ключ на поле post_id, который связан с id в таблице постов.

Сохранение комментариев

Теперь, имея таблицу для комментариев, мы можем её заполнять. Добавьте следующее выражение после объявления всех наших инсертов:

#SQL statement for adding comment data
insert_comments = ("INSERT INTO comment_info "
                   "(comment_id, message, likes_count, time_created, post_id)"
                   "VALUES (%s, %s, %s, %s, %s)")

В нашей основной функции после того места, где вы сохраняем данные поста, добавьте следующий код:

comment_data = []
#loop through and insert data
for post in post_data:
    post.append(last_key)
    cursor.execute(insert_posts, post)

    #capture post id of data just inserted
    post_key = cursor.lastrowid
    # print post_key
    comment_url = create_comments_url(graph_url, post[0], APP_ID, APP_SECRET)
    comments = get_comments_data(comment_url, comment_data, post_key)

    #insert comments
    for comment in comments:
        cursor.execute(insert_comments, comment)

Изначально мы создаём пустой список comment_data. Затем мы проходим циклом по всем полученным постам и сохраняем их. Для каждого поста после сохранения мы получаем его post_id. Далее мы формируем адрес для списка комментариев текущего поста и, используя его, получаем все комментарии поста. В заключение проходя по всем комментариям, мы сохраняем их в базу.

Результирующий код

В итоге наш скрипт на данный момент выглядит следующим образом:

import urllib2
import json
import mysql.connector
import datetime


def connect_db():
    #fill this out with your db connection info
    connection = mysql.connector.connect(user='JohnDoe', password='abc123',
                                         host = '127.0.0.1',
                                         database='facebook_data')
    return connection


def create_post_url(graph_url, APP_ID, APP_SECRET):
    #create authenticated post URL
    post_args = "/posts/?key=value&access_token=" + APP_ID + "|" + APP_SECRET
    post_url = graph_url + post_args
    return post_url


def render_to_json(graph_url):
    #render graph url call to JSON
    web_response = urllib2.urlopen(graph_url)
    readable_page = web_response.read()
    json_data = json.loads(readable_page)
    return json_data


def scrape_posts_by_date(graph_url, date, post_data, APP_ID, APP_SECRET):
    #render URL to JSON
    page_posts = render_to_json(graph_url)

    #extract next page
    next_page = page_posts["paging"]["next"]

    #grab all posts
    page_posts = page_posts["data"]

    #boolean to tell us when to stop collecting
    collecting = True

    #for each post capture data
    for post in page_posts:
        try:
            likes_count = get_likes_count(post["id"], APP_ID, APP_SECRET)
            current_post = [post["id"], post["message"], likes_count,
                            post["created_time"], post["shares"]["count"]]

        except Exception:
            current_post = [ "error", "error", "error", "error"]

    if current_post[2] != "error":
        print date
        print current_post[3]
        if date <= current_post[3]:
            post_data.append(current_post)

        elif date > current_post[2]:
            print "Done collecting"
            collecting = False
            break

    #If we still don't meet date requirements, run on next page
    if collecting == True:
        scrape_posts_by_date(next_page, date, post_data, APP_ID, APP_SECRET)

    return post_data


def get_likes_count(post_id, APP_ID, APP_SECRET):
    #create Graph API Call
    graph_url = "https://graph.facebook.com/"
    likes_args = post_id + "/likes?summary=true&key=value&access_token" + APP_ID + "|" + APP_SECRET
    likes_url = graph_url + likes_args
    likes_json = render_to_json(likes_url)

    #pick out the likes count
    count_likes = likes_json["summary"]["total_count"]

    return count_likes


def create_comments_url(graph_url, post_id, APP_ID, APP_SECRET):
    #create Graph API Call
    comments_args = post_id + "/comments/?key=value&access_token=" + APP_ID + "|" + APP_SECRET
    comments_url = graph_url + comments_args
    #print comments_url
    return comments_url


def get_comments_data(comments_url, comment_data, post_id):
    #render URL to JSON
    comments = render_to_json(comments_url)["data"]

    #for each comment capture data
    for comment in comments:
        try:
            current_comments = [comment["id"], comment["message"], comment["like_count"],
                                comment["created_time"], post_id]
            print current_comments
            comment_data.append(current_comments)

        except Exception:
            current_comments = ["error", "error", "error", "error", "error"]

    #check if there is another page
    try:
        #extract next page
        next_page = comments["paging"]["next"]
    except Exception:
        next_page = None

    #if we have another page, recurse
    if next_page is not None:
        get_comments_data(next_page, comment_data, post_id)
    else:
        return comment_data


def main():
    #simple data pull App Secret and App ID
    APP_SECRET = "Your app secret"
    APP_ID = "Your app ID"

    #to find go to page's FB page, at the end of URL find username
    #e.g. http://facebook.com/walmart, walmart is the username
    list_companies = ["walmart", "cisco", "pepsi", "facebook"]
    graph_url = "https://graph.facebook.com/"

    #the time of last weeks crawl
    last_crawl = datetime.datetime.now() - datetime.timedelta(weeks=1)
    last_crawl = last_crawl.isoformat()

    #create db connection
    connection = connect_db()
    cursor = connection.cursor()

    #SQL statement for adding Facebook page data to database
    insert_info = ("INSERT INTO page_info "
                   "(fb_id, likes, talking_about, username)"
                   "VALUES (%s, %s, %s, %s)")

    #SQL statement for adding post data
    insert_posts = ("INSERT INTO post_info "
                    "(fb_post_id, message, likes_count, time_created, shares, page_id)"
                    "VALUES (%s, %s, %s, %s, %s, %s)")

    #SQL statement for adding comment data
    insert_comments = ("INSERT INTO comment_info "
                       "(comment_id, message, likes_count, time_created, post_id)"
                       "VALUES (%s, %s, %s, %s, %s)")

    for company in list_companies:
        #make graph api url with company username
        current_page = graph_url + company

        #open public page in facebook graph api
        json_fbpage = render_to_json(current_page)

        #gather our page level JSON Data
        page_data = [json_fbpage["id"], json_fbpage["likes"],
                     json_fbpage["talking_about_count"],
                     json_fbpage["username"]]

        #extract post data
        post_url = create_post_url(current_page, APP_ID, APP_SECRET)

        post_data = []
        post_data = scrape_posts_by_date(post_url, last_crawl, post_data, APP_ID, APP_SECRET)

        #insert the data we pulled into db
        cursor.execute(insert_info, page_data)

        #grab primary key
        last_key = cursor.lastrowid

        comment_data = []
        #loop through and insert data
        for post in post_data:
            post.append(last_key)
            cursor.execute(insert_posts, post)

            #capture post id of data just inserted
            post_key = cursor.lastrowid
            #print post_key
            comment_url = create_comments_url(graph_url, post[0], APP_ID, APP_SECRET)
            comments = get_comments_data(comment_url, comment_data, post_key)
            #print comments
            #insert comments
            for comment in comments:
                cursor.execute(insert_comments, comment)

        #commit the data to the db
        connection.commit()

    connection.close()


if __name__ == "__main__":
    main()

Резюме

На этом серия постов «Получение постов и комментариев Facebook» завершена. В ней мы рассмотрели как получать посты по дате и как получить комментарии для поста.

 
comments powered by Disqus