안녕하세요. "생각의 웹"입니다.


이번 포스팅에서는 facebook의 graph API(https://developers.facebook.com/tools/explorer/)를 이용해 특정 fan page에 게시된 feed 글들을 word cloud로 만들어 보았습니다.




분석 대상 fan page: https://www.facebook.com/VisionMobile

 

참고 삼아 이 회사는 모바일 앱 및 IoT 관련 산업 및 개발자 동향을 분석해 인사이트 리포트를 제공하는 영국 회사로 깔끔한 시각화 (visualization) 과 핵심을 관통하는 분석으로 평소 많은 도움을 받고 있습니다.


코드 설명에 앞서, facebook의 경우 주기적으로 access token를 발급 받아서 유효한 값을 query parameter로 전송해야만 정상적으로 결과를 얻을 수 있습니다.

자세한 사항은 doc (https://developers.facebook.com/docs/graph-api?locale=ko_KR) 를 참고하시기 바랍니다.


1. feed data를 가져오는 class 만들기 

facebook의 특정 page에서 feeds를 가져오기 위해 PsyCharm 혹은 pip 로 'requests', 'urllib3' 를 설치 후 다음과 같이 구현했습니다.


import requests
import json
import facebook
import urllib3
import urllib3.contrib.pyopenssl # due to https://urllib3.readthedocs.org/en/latest/security.html#insecureplatformwarning
urllib3.contrib.pyopenssl.inject_into_urllib3()
urllib3.disable_warnings()

class FacebookRequester:
    base_url = 'https://graph.facebook.com/'
    version = 'v2.3'
    content = []
    def __init__(self, token):
        self.access_token = token
        self.page = 'me'
    def setPage(self, page):
        self.page = page
    def getFeeds(self, limit, times):
        fields = 'feed.limit(%s)' % limit
        url = '%s/%s/%s?fields=%s&access_token=%s' % \
              (self.base_url, self.version, self.page, fields, self.access_token)
        counter = 0
        print url
        while counter < times:
            response = requests.get(url).json()
            print response

            try:
                content = response['feed']['data']
                paging = response['feed']['paging']
            except KeyError: # in case of retrieving by next page
                content = response['data']
                paging = response['paging']

            #print content
            #print paging

            self.content = self.content + content
            next_page_url = paging['next']
            if not next_page_url:
                break
            else :
                counter += 1
                url = next_page_url
                #print url
        return self.content

상기 코드에서 유심히 볼 부분은 urllib3 입니다. 

이 라이브러리가 없으면 python 2.* 에서 https 로 전송 시도 시 TLS 보안 관련 결함이 있기 때문에 insecure platform warning 과 함께 전송이 되지 않습니다. 따라서 관련 가이드 (https://urllib3.readthedocs.org/en/latest/security.html#insecureplatformwarning) 에 따라 필요한 warning skip code가 추가되었습니다.


두 번째로 facebook은 한번의 요청으로 가져올 수 있는 데이터 양이 정해져 있기 때문에 그 다음 데이터를 가져올 수 있도록 paging property의 next attribute에 다음 요청의 URL 를 제공합니다. 따라서 다음 요청 시에는 이 값을 사용하도록 구현했습니다.

2. feed 가져와서 word 추출하기 


import os.path
import json
import sys
import nltk

import jsonreader

from prettytable import PrettyTable
from fb_requester import FacebookRequester

##
# Get feeds using facebook graph API
#
def get_feeds():

    ACCESS_TOKEN = ''
    requester = FacebookRequester(ACCESS_TOKEN)
    requester.setPage('VisionMobile')
    feeds = requester.getFeeds(100, 5)
    return feeds


##
# Tokenize all feed messages
#
def tokenize(feeds):

    feed_texts = []
    for feed in feeds:
        try:
            feed_message = feed['description'] # message attribute contains URL but description doesn't
            feed_texts.append(feed_message)

        except KeyError:
            #print feed # if feed has no message field
            continue

    tokens = []
    for s in feed_texts:
        tokens += nltk.tokenize.word_tokenize(s.lower())
    return tokens

##
# Get stemmed list
#
def get_stemmed_list(tokens):
    from nltk.corpus import stopwords

    stop_words = stopwords.words('english') + ['.', ',', '--', '\'s', '?', ')', '(', ':', '\'', '\'re', '"',
                                               '-', '}', '{', u'—', 'rt', 'http', '%', 'co', '@', '#', '/', u'…',
                                               u'#', u';', u'amp', u't', u'co', u']', u'[', u'`', u'`', u'&', u'|',
                                               u'\u265b', u"''", u'$', u'//', u'/', u'%',
                                                                              u'via', u'...', u'!', u'``', u'http']

    from nltk.stem import PorterStemmer

    stemmer = PorterStemmer()
    stemmed = []
    for token in tokens:
        # try to decode token
        try:
            decoded = token.decode('utf8')
            #print decoded
        except UnicodeError:
            decoded = token

        if decoded is '' or decoded in stop_words:
            continue
        stem = stemmer.stem(decoded)
        #print stem
        # Skip a few text. I don't know why stopwords are not working :(
        #skip facebook things
        if stem.find(u'facebook.com') > 0:
            continue
        #skip http things
        elif stem.find(u'http') >= 0:
            #print stem
            continue
        else:
            stemmed.append(stem)
    return stemmed


def write_file(filename, lines):
    f = file(filename, 'w')
    for word in lines:
        try:
            f.write(word.encode('utf-8') + '\n')
        except UnicodeEncodeError, e:
            print 'Encoding error ' + word + '\n'
    f.close()

# Simple test
feeds = get_feeds()
tokens = tokenize(feeds)
print tokens
stemmed = get_stemmed_list(tokens)
print stemmed
write_file('feed-word.txt', stemmed)


이 코드는 앞서 포스팅한 tweet으로 word cloud 만들기 코드와 거의 유사하며 tweeter와 facebook의 JSON shema 차이 부분만 변경되었으니 참고해 보시기 바랍니다.


이처럼 양대 SNS 서비스인 tweeter 와 facebook에서 추출한 비정형 데이터에서 문자열 추출을 통해 분석하는 예제를 수행해 보았습니다.

이제는 다양한 이유로 충분한 데이터를 모으려면 제약이 심한 관계로 아주 작은 데이터를 가지고 한 실습에 불과 하지만 이와 같은 방식으로 데이터를 모으고 분석할 수 있는 기반을 경험했다는 점에서 의의를 두고 싶습니다.


이상입니다.


감사합니다.

행복한 하루 되시길!

안녕하세요, "생각의 웹"입니다.


이번에는 갖은 시행 착오 끝에 설치를 완료한 NLTK를 활용해 IoT로 검색해 얻은 600 건의 트윗의 내용을 

word cloud로 만든 사례를 소개하고자 합니다.





이를 위해 python의 tweeter module을 이용해 아래와 같이 코딩했습니다.


# coding=UTF-8

import os.path
import json
import sys
import nltk

import collecttweets
import jsonreader

from collections import Counter
from prettytable import PrettyTable

##
# Get tweets from JSON dump file or twitter API
#
def get_tweets() :
	file_path = "tweets.json"
	if os.path.exists(file_path) :
		return jsonreader.read(file_path)
	else:
		return collecttweets.search_tweets_by_hash_tag('IoT', 5, 100)

##
# Tokenize all tweet messages
#
def tokenize(statuses) :
    status_texts = [ status['text']
        for status in statuses ]

    tokens = []
    for s in status_texts:
        tokens += nltk.tokenize.word_tokenize(s.lower())
    return tokens

##
# Get stemmed list
#
def get_stemmed_list(tokens) :
    from nltk.corpus import stopwords
    stop_words = stopwords.words('english') + ['.', ',', '--', '\'s', '?', ')', '(', ':', '\'', '\'re', '"',
        '-', '}', '{', u'—', 'rt', 'http', 't', 'co', '@', '#', '/', u'…',
        u'#', u';',  u'amp', u't', u'co', u']', u'[', u'`', u'`', u'&', u'|', u'\u265b', u"''", u'$', u'//', u'/'
        u'via',  u'...', u'!', u'``', u'http']

    from nltk.stem import PorterStemmer
    stemmer = PorterStemmer()
    stemmed = []
    for token in tokens:
        # try to decode token
        try:
            decoded = token.decode('utf8')
            #print decoded
        except UnicodeError:
            decoded = token

        if decoded is '' or decoded in stop_words:
            continue
        stem = stemmer.stem(decoded)
        #print stem
        # Skip a few text. I don't know why stopwords are not working :(
        #skip t.co things
        if stem.find(u't.co') > 0:
            continue
        #skip http things
        elif stem.find(u'http') >= 0:
            #print stem
            continue
        else:
            stemmed.append(stem)
    return stemmed

def write_file(filename, lines) :
    f = file(filename, 'w')
    for word in lines:
        try:
            f.write(word.encode('utf-8') + '\n')
        except UnicodeEncodeError, e:
            print 'Encoding error ' + word + '\n'
    f.close()

# Simple test
statuses = get_tweets()
tokens = tokenize(statuses)
print tokens
stemmed = get_stemmed_list(tokens)
print stemmed
write_file('word.txt', stemmed)



간략히 설명하면 

1) twitter API로 관심주제 (저 같은 경우는 IoT)로 tweet를 수집한다. 

2) tweet의 내용을 token으로 쪼개 모은다.

3) stemmer로 token를 분석해 불필요한 단어들을 제거한다. 

4) 남은 word들을 파일로 출력한다. 만들어진 word.txt를 아래 사이트에서 word cloud로 만들면 앞서 그림과 같이 예쁜 그림을 얻을 수 있습니다. 

(silverlight로 제작된 사이트니 IE에서 접속하는 걸 추천합니다 ;-) ) 

http://www.tagxedo.com/app.html 


이상입니다. 


감사합니다.

  1. 파이팅건맨 2015.03.28 20:49

    멋지네요, 제 홈에도 써 먹어야 겠어요~!ㅋㅋ

  2. 김진형 2015.06.01 21:39

    collecttweets 는 뭔지 알 수 있을까요?

    • 생각의 웹 WebofThink 2015.06.04 01:24 신고

      요즘 통 바삐 살다 보니 답글 늦었네요 ^^; 다음 코드 참조하시기 바랍니다 https://github.com/hyunghunny/wordcloud/blob/master/twitter/collecttweets.py

+ Recent posts