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


이번 포스팅에서는 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에서 추출한 비정형 데이터에서 문자열 추출을 통해 분석하는 예제를 수행해 보았습니다.

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


이상입니다.


감사합니다.

행복한 하루 되시길!

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


한글 윈도우즈 8.1 64bit 버전에서 nltk 설치 관련해 이전 포스팅(http://webofthink.tistory.com/59)을 작성한 바 있으나

pycharm 설치 이후에도 nltk 관련 다양한 문제가 있어 해결 방안(이라기 보다 제가 해결 했던 방법)을 공유하고자 이렇게 글을 시작합니다.



먼저 시스템 > 시스템 속성 > 환경 변수에 다음과 같은 사용자 변수를 추가해 줍니다.


HOME

PYTHONHOME


이 변수에는 한글이 포함되지 않은 임의의 존재하는 경로를 입력합니다.



이후 nltk 설치 이후 정상 설치 여부를 확인하기 위해서는 python console 에서 (pycharm의 Tools > Python Console을 추천합니다.) 

다음과 같은 명령어를 수행하면 됩니다.



import nltk

저 같은 경우는 상기 명령 수행 이후 DecodingError가 발생했는데 에러가 발생한 위치를 보면 python 설치 경로\Lib\site-packages\nltk\downloader.py의 아래 줄이 문제를 발생시킵니다.


933  return os.path.join(homedir, 'nltk_data')


문제의 원인은 제 home 경로에 해당하는 위치에 한글이 포함되어 있고 windows 8.1의 경우 이 경로를 임의로 바꿀 수 없기 때문입니다.

따라서 문제를 발생시키는 homedir 변수의 값에 한글 경로가 포함되지 않는 경로를 할당해서 우회합니다.


933  homedir = os.environ['PYTHONHOME']
934  return os.path.join(homedir, 'nltk_data')



이로써 (저의 경우) nltk import 가 정상적으로 수행되었습니다. 이후 관련 package룰 다운로드 받기 위해 아래와 같이 download() 함수를 수행하면 새로운 다운로드 창에서 관련 package들을 다운로드 받을 수 있습니다.


import nltk
nltk.download()


몇 번에 걸쳐 python 설치/제거 작업을 반복하며 얻은 노하우니 만큼 유용하게 쓰였으면 합니다.

이상입니다.


감사합니다.

행복한 하루 되세요!


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


이번에는 갖은 시행 착오 끝에 설치를 완료한 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 


이상입니다. 


감사합니다.

+ Recent posts