node.js 로 트위터봇을 만들어보자.
일단 node.js 를 알아야하고(이전에 작성한 Node.js 초간단 3분 훝기 글을 참조해도 된다.), 트위터 api 에 대해서 알아야한다.
트위터 api 는 3종류의 api 가 있다. (참조 : https://dev.twitter.com/start )
- Search API
- REST API
- Streaming API
이중 Search API 만 별도의 인증이 필요하지 않으며, 나머지 2개의 API 에서는 oAuth (Open ID Authentication) 을 필요로 한다.
예제로 만들 트위터봇은 계정 1개를 사용하며, 멘션이 날라올 경우 멘션을 날리는 사람에게 리플라이를 하는 기능을 구현한다. 따라서, 다음 2가지 api 가 필요하다
- 멘션 조회
- 메세지 작성
이 2개의 API 는 REST API 에서 제공된다. 따라서 2개의 API 모두 oAuth 인증을 필요로 한다.
oAuth 인증을 위해서는 다음 값이 필요하다.
- Consumer Key
- Consumer Secret
- Access Token
- Access Token Secret
oAuth 에 관한 자세한 정보는 http://dev.naver.com/openapi/apis/oauth/guide 를 참조한다.
1. 트위터 계정 설정하기
access token 을 발급받기 위해서 https://dev.twitter.com/apps 로 들어가 트위터 어플리케이션을 생성한다.
어플리케이션을 생성하면, oAuth 인증 Access Level 이 Read-only 로 되어있다. 트윗을 날리기 위해선, Write Level 이 필요하다.
settings 메뉴에 들어가서 Application Type 을 'Read and Write' 로 변경한다.
마지막으로 Detail 메뉴로 다시 돌아온 후, 최하단에서 Access Token 을 생성한다.
2. 모듈 설치
프로젝트를 생성한다.
대몬형태로 띄울 프로그램을 만들기만 하면 되지만, 여기서는 웹서버를 실행시켜놓는 형태로 하겠다.
expresss [프로젝트명] -s 를 실행한다.
express 모듈을 로컬에 설치한다.
npm install express 를 실행한다.
oAuth 인증을 할 oAuth 모듈을 설치한다.
npm install oauth 를 실행한다.
3. 소스 작성
본격적으로 소스를 작성해보자.
oAuth 객체를 생성한다.
// app.js
var OAuth= require('oauth');
var tokens = {
twitterAccessToken : '579900828-erXEQXRlg0Kx2l9S4uR9OcNT7npsjtwxxxxx',
twitterAccessTokenSecret : 'zQu3VLFp8P6dj1j9W7wmnZ3PS9HVTlhpxtxxxxx',
twitterConsumerKey : 'zASiWXu1F9HqnAb15xxxxx',
twitterConsumerSecret : '5labh3Y1s7iNfyLeraA7UB7vtGme5O5I8qxxxxxx'
};
oAuth= new OAuth.OAuth(
"http://twitter.com/oauth/request_token",
"http://twitter.com/oauth/access_token",
tokens.twitterConsumerKey, tokens.twitterConsumerSecret,
"1.0A", null, "HMAC-SHA1"
);
oAuth 객체를 이용하여 twitter api 를 다루는 twitter.js 를 만들어보자. 해당 위치는 프로젝트 최상위에 둔다. (app.js 와 같은 위치)
사용된 트위터 API 는 다음과 같다.
- 멘션 조회 : https://dev.twitter.com/docs/api/1/get/statuses/mentions
- 메세지 작성 : https://dev.twitter.com/docs/api/1/post/statuses/update
// twitter.js
var qs = require('querystring');
/**
* Twitter Service
* @param oAuth oAuth
* @param tokens {twitterAccessToken:'your twitter Access Token', twitterAccessTokenSecret:'your twitter Access Token Secret'}
* @author slothink. (slothink at gmail.com)
*/
exports.Twitter = function(oAuth, tokens) {
this._oAuth = oAuth;
this._tokens = tokens;
}
var defaultCallbackFunc = function(error, data, cbFunc) {
if(error) console.log(require('sys').inspect(error))
else {
if(typeof cbFunc == "function") {
console.log(data);
cbFunc(JSON.parse(data));
}else {
console.log(data)
}
}
};
exports.Twitter.prototype.tweet = function(message, cbFunc, option) {
var param = {"status":encodeURIComponent(message)};
var param = {"status":message};
for(var key in option) {
param[key] = option[key];
}
this._oAuth.post(
"http://api.twitter.com/1/statuses/update.json",
this._tokens.twitterAccessToken, this._tokens.twitterAccessTokenSecret,
param, function(error, data) {
defaultCallbackFunc(error, data, cbFunc);
});
}
exports.Twitter.prototype.getMentions = function(cbFunc, params) {
var url = "https://api.twitter.com/1/statuses/mentions.json?" + qs.stringify(params);
console.log(url);
this._oAuth.get(
url,
this._tokens.twitterAccessToken, this._tokens.twitterAccessTokenSecret,
function(error, data) {
defaultCallbackFunc(error, data, cbFunc);
}
);
}
다음은 twitter api 를 이용해 트윗봇을 구현한 기능이다.
// twitterbot.js
var fs = require('fs'), Twitter = require('./twitter');
exports.TwitterBot = function(tokens) {
this._twitter = new Twitter.Twitter(oAuth, {twitterAccessToken:tokens.twitterAccessToken, twitterAccessTokenSecret:tokens.twitterAccessTokenSecret});
this._tokens = tokens;
this._messages = [
"어쩌라구",
"자라",
"-_-",
"ㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋ",
"내가 네 친구냐?",
"나 남자거든",
"현장씨는 소고기를 좋아합니다",
"잇힝=ㅅ=*",
"바보!!",
"아잉~ >_<*",
"허얼...................",
"나랑 데이트할래?",
"누구세요?",
"흥",
"영화 볼래? 뭐가 좋을까?",
"나야",
"별루다",
"잘래",
"연락처 좀 줄래?",
"보고싶다",
"헤헤헤헤"
];
this._lastId = null;
this._work = 0;
}
exports.TwitterBot.prototype.botMessage = function(text) {
var mul = Math.floor(Math.random() * 100000) + 1
var message = this._messages[(this._work * mul) % this._messages.length];
this._work++;
return message;
}
exports.TwitterBot.prototype.commit = function() {
fs.writeFile('./work.txt', this._lastId, 'utf-8', function(err) {
if(err) {
throw err;
}
});
}
exports.TwitterBot.prototype.waitAndReply = function() {
console.log("wait and reply:" + this._work);
var my = this;
var params = {};
if(this._lastId != null) {
params.since_id = this._lastId;
console.log(params);
}
this._twitter.getMentions(function(data) {
for(var key in data) {
var tweet = data[key];
console.log("["+ tweet.id_str+"] " + tweet.user.name + " (@"+ tweet.user.screen_name+") say : ");
console.log(tweet.text);
if(my._lastId == null || my._lastId != tweet.id_str) {
my._lastId = tweet.id_str;
my.commit();
}
var message = '@'+tweet.user.screen_name +' '+my.botMessage(tweet.text);
my._twitter.tweet(message, function(data) {
my._lastId = data.id_str;
my.commit();
}, {in_reply_to_status_id:tweet.id_str,});
}
}, params);
}
work.txt 파일은 마지막으로 처리한 메세지 id 이다. 이것을 이용함으로써, 한번 메세지 날린 트윗에 대해 중복으로 날라가는 것을 방지한다.
app.js 에 work.txt 파일을 처리한 후, 주기적으로 트위터 봇을 호출하는 로직을 삽입하면 완료다.
// app.js
var fs = require('fs'), TwitterBot = require('./twitterbot');
fs.readFile('./work.txt', encoding='utf-8', function(err, data) {
if(err) {
fs.writeFile('./work.txt', encoding='utf-8', function(err, data) {
bot
});
data = null;
}
var bot = new TwitterBot.TwitterBot(tokens);
bot._lastId = data;
console.log('start at id:'+bot._lastId);
setInterval(function() {
bot.waitAndReply();
}, 1000 * 30);
});
이제 실행해보자.
4. 여자친구 사귀기
잘 된다.. 이쁜 여자친구 사귀십시오..ㅋㅋ