트위터 파헤치기 시리즈 첫번째 - 수집하기

트위터 데이터를 주로 수집해서 사용하다 보니, 너무 관련된 포스트를 여러개 쓰는것 같지만..
많은 분들이 댓글 혹은 메일로도 연락이 오셔서 문의하시는 부분이 있어 이 기회에 정리해 보고자 한다.

이름하여 트위터 파헤치기 시리즈! 수집부터 시작해서 한국어 전처리, 워드 클라우드 시각화 및 클러스터링 시 적절한 하이퍼 파라미터 설정 등 분석 단계까지 조금씩 정리해 보고자 한다.

예시 주제로 요즘 우리들을 괴롭히는 코로나 바이러스 에 대해서 트위터를 살펴보는 것으로 정했다.

지금까지 트위터 수집 방법에 대해서 꽤 여러 포스트를 썼었는데, 지금까지 다루지 않은 방법으로 시도하고자 한다. 수집 방법을 많이 알면 알수록 좋으니까!

수집 도구 정하기

이번에 트위터 수집에 사용할 패키지는 twint 라는 친구이다.
(github page : https://github.com/twintproject/twint)

무료로 사용할 수 있고, 트위터 개발자 등록 과정이 필요가 없어서 간단하게 트랜드나 토픽을 알고 싶을때 사용하곤 했다.

돈 내고 쓰는 것이 아니기 때문에 조금씩 불편한 점들이 있다. 그러나 현존하는 무료 파이썬 패키지 중에 가장 잘 작동하는 트위터 크롤링 패키지가 아닐까 싶다.

full-archive 트위터 데이터가 필요한 연구자라면 본 패키지는 불필요하다. Premium API를 결제해서 사용하도록 하자. 본인이 시도해본 결과 프리미엄에 비해 10~20%의 데이터밖에 크롤링하지 못한다.

그러나, 하루에 어떤 토픽이 이슈가 되었고 전반적인 트랜드를 알고 싶은 사용자라면 이것으로 충분하다.

아래부터 코드는 주피터 노트북으로 열어서 실행하는 것을 기본으로 전제하고 작성한다. twint를 설치부터 해주자.

1
2
3
# python 3.6 
# install twint package
!pip install --user --upgrade -e git+https://github.com/twintproject/twint.git@origin/master#egg=twint

깃허브 홈페이지를 들어가보면 pip 설치 이외에도 설치 방법이 다양하게 나와있다. (Python 3.6 기준)

파라미터 설정하기

twint 패키지는 거의 대부분의 Twitter API 가 지원하는 옵션을 동일하게 지원한다. 자세한 사용법은 본 포스트에서는 다루지 않을 생각이다. wiki를 읽어보면 혼자서 할 수 있도록 설명이 잘 되어 있기 때문이다.

본 포스트의 목적은 코로나 바이러스 에 관한 트윗을 수집하는 것이므로, 여기에 초점을 맞춰서 파라미터를 설정해 보겠다. 설정하면서 등장하는 twint 옵션에 대해서는 간단하게 설명을 달아놓는 것으로.

1
2
3
4
5
6
7
8
9
10
11
12
import twint
c = twint.Config() # twint config 선언

# Parameter setting
c.Limit = 50
c.Search = '코로나 OR 우한 폐렴'
c.Since = '2020-04-23'
c.Until = '2020-04-24'
c.Output = 'covid19_sample_tweet.json'
c.Popular_tweets = True
c.Store_json = True
c.Hide_output = True

옵션이 생각보다 많다.. 위의 코드에 사용된 옵션에 대해서 하나하나 알아보자.

  • Limit: 총 수집할 트윗의 수를 의미 (모든 트윗을 수집하고 싶다면 옵션을 제거)
  • Search: 수집할 트윗의 키워드를 입력, Exact Match를 원하면 쌍따옴표를 사용
    (ex. ‘코로나 OR “우한 폐렴”‘ 으로 입력할 경우, 정확히 우한 폐렴 이라는 단어를 모두 포함하는 트윗만 수집됨)
  • Since, Until: 수집을 원하는 기간 범위 (끝은 포함하지 않음)
  • Output: 트윗을 수집 후 저장할 때 파일 이름
  • Popular_tweets: True일 때 트위터 탭 중 Polular을 의미, False의 경우 Recent을 의미
  • Store_json: 저장 시 JSON 포맷으로
  • Hide_output: True일 때 주피터 노트북 콘솔에 output이 출력되는 옵션을 끔

더 원하는 옵션이 있거나, 설명을 보고도 잘 이해하기 어렵다면 공식 홈페이지의 설명을 참고하자.

트위터 수집하기

자, 설정은 끝났다. 이제 위에서 설정한 twint을 실행시켜 볼 것이다. 아래의 코드를 입력한다.

1
twint.run.Search(c)

위의 옵션에서 나는 “트위터에서 코로나 또는 우한 폐렴을 포함하는 트윗을 2020년 4월 23일 (UTC), Popular 탭 기준으로 50개만 수집해줘” 를 주문했다.

제대로 실행되었다면, working directory에 covid19_sample_tweet.json 파일이 생성되었을 것이다. 뜯어서 살펴보자.

1
2
3
4
import pandas as pd

df = pd.read_json('covid19_sample_tweet.json', lines=True)
df[["created_at", "id", "tweet", "retweets_count"]].head() # 편의상 4개의 칼럼만 출력

위와 같이 4월 23일의 트윗이 잘 수집되었음을 확인할 수 있다.

크롤러 만들기

위까지 잘 따라왔다면 twint를 사용해서 하루 단위의 트윗을 어떻게 모으는지 알았을 것이다.
이제 loop를 구성해서, 주어진 기간 내 특정 트윗을 모두 수집하도록 코드를 구성해 보자.
이쯤 되면 트위터 크롤러라고 이름을 붙여도 될 것이다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
# Import packages
import twint
import pandas as pd
from os import mkdir, path
import datetime
import re

# Valid Directory Naming Function
def clean_name(term):
cleaned = re.sub('[^0-9a-zA-Zㄱ-ㅎ가-힣]', '', term) # 특수문자 제거
return cleaned

# Twint Search Function
def twint_search(dirname, searchterm, since, until, json_name, limit):

c = twint.Config()

# Parameter setting
c.Limit = limit
c.Search = searchterm
c.Since = since
c.Until = until
c.Hide_output = True
c.Store_json = True
c.Output = json_name
c.Debug = True
c.Resume = f'{dirname}/save_endpoint/save_endpoint_{since}.txt'
c.Popular_tweets = True

try:
twint.run.Search(c)

except (KeyboardInterrupt, SystemExit):
raise

except:
print(f"Problem with {since}.")

# Loop Function, Default number of tweet is 50
def twint_loop(searchterm, since, until, limit=50):

dirname = clean_name(searchterm)

# Create target directory
try:
mkdir(dirname)
mkdir(f'{dirname}/save_endpoint')
print("Directory" , dirname , "Created ")
except FileExistsError:
print("Directory" , dirname , "already exists")

# Loop
daterange = pd.date_range(since, until)

for start_date in daterange:

since = start_date.strftime("%Y-%m-%d")
until = (start_date + timedelta(days=1)).strftime("%Y-%m-%d")

json_name = "".join(since.split("-")) + ".json"
json_name = path.join(dirname, json_name)

print(f'Getting {since} ')
twint_search(dirname, searchterm, since, until, json_name, limit)

조금 함수의 형태들이 마음에 들지 않지만, 작동은 잘 한다.
따로 값을 지정하지 않으면 기본적으로 각 날짜에 대해 50개의 트윗만 가져오도록 설정했다.
50개의 트윗을 시간 순서대로 가져오고 싶다면 옵션 중 Popular_tweetsFalse로 지정하면 된다.

위의 섹션에서 다루지 않은 옵션이 있는데, DebugResume이다. 이는 대량의 트윗을 수집할 때 twint가 트위터 서버 측의 공격적인 크롤링 방지로 인해 TimeoutError를 발생시키기 때문에, 중간 저장 포인트를 만들기 위해 설정한 것이다.

일단 실행 고고!

1
2
3
4
5
6
7
8
Keyword = '코로나 OR 우한 폐렴'
twint_loop(Keyword, '2020-04-23', '2020-04-25', limit=50)

# 실행 화면
>> Directory 코로나OR우한폐렴 Created
>> Getting 2020-04-23
>> Getting 2020-04-24
>> Getting 2020-04-25

위와 같이 2020년 4월 23일부터 25일까지 트윗이 잘 수집됨을 확인할 수 있다.

Limit을 -1로 설정하면 조건을 만족하는 모든 트윗을 가져오게 되는데, 경우에 따라 몇 시간에서 몇십 시간이 소요될 수도 있다. (covid19와 같은 search 조건을 입력하면 그렇게 된다..)

그리고 너무 오랫동안 크롤러가 작동하게 되면 알수 없는 이유로 오류를 일으키는 경우가 간간히 존재한다. 경험적으로 크롤러가 끊어지는 부분들을 많이 보완한 코드가 위의 코드인데.. 문제들을 완전히 해결하고 싶다면 유료 버전을 검토해 보자.

수집된 내용을 확인해 볼까?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
from pathlib import Path
from tqdm.auto import tqdm
import os

# Saved files path
DATA_DIR = Path(f"./{clean_name(Keyword)}") # 저장된 파일 디렉토리 정보
json_files = [pos_json for pos_json in os.listdir(DATA_DIR) if pos_json.endswith('.json')]

# Data load
df_list= []
for file_name in tqdm(json_files):
temp_df = pd.read_json(DATA_DIR / file_name, lines=True)
df_list.append(temp_df)

df = pd.concat(df_list, sort=False)
df[["created_at", "id", "tweet", "retweets_count"]].tail() # 편의상 4개의 칼럼만 출력

수집이 잘 이루어졌음을 확인할 수 있다.

또한 위의 코드에는 여러개의 JSON 파일을 한번에 읽는 방법도 포함되어 있다.
하나의 JSON 파일에 너무 많은 트윗이 포함되어 있다면 읽는 데에도 시간이 오래 걸리니 유의하자.
통째로 묶어서 df에 저장하도록 되어 있는데, 트윗의 수가 몇 백만개가 넘어가면 Memory Error가 발생할 수 있다.
얼마나 읽어졌는지 눈으로 확인하기 위해 tqdm을 추가하였다. 오류가 난다면 제거해도 상관없다.

다음 포스트에서는 위와 같은 방법으로 수집한 트윗에 대해 한국어 NLP에서 가장 고충을 겪고 있는 점 중 하나인 전처리 (preprocessing)에 대해 다루어 볼 계획이다.