Created
January 6, 2016 20:46
-
-
Save rendon/94da8c42953f94635622 to your computer and use it in GitHub Desktop.
FB bot
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// ======================================== | |
// ! Casper | |
// ! Common issues: Unsafe Javascript attempt to access frame with URL | |
// ! Issues: http://goo.gl/u1murB | |
// ! Version : 1.0 | |
// ======================================== | |
var fs = require('fs'); | |
var utils = require('./src/utils'); | |
var system = require('system'); | |
var casper = require('casper').create(); | |
var collection = {}; | |
var credentials = null; | |
// ======================================== | |
// ! Bot Profiles | |
// ======================================== | |
if (fs.exists('src/credentials.json')) { | |
var users = JSON.parse(fs.read('src/credentials.json')); | |
var bot = utils.assignBot(users, 150); | |
credentials = users[bot]; | |
} | |
// ======================================== | |
// ! Casper Config | |
// ======================================== | |
if (!credentials) { | |
system.stderr.write(JSON.stringify({error: 'No users left'})); | |
setTimeout(function() { | |
casper.exit(1); | |
}, 0); | |
} | |
casper.options.userAgent = credentials.ua; | |
casper.options.stepTimeout = 1e12; | |
casper.options.waitTimeout = 1e12; | |
casper.options.viewportSize = { width: 1024, height: 768 }; | |
casper.options.pageSettings = { loadImages:true, loadPlugins:true, webSecurityEnabled: false }; | |
collection.data = {}; | |
collection.global = {}; | |
collection.global.timeout = 1000; | |
// ======================================== | |
// ! Casper arguments check | |
// ======================================== | |
if (typeof casper.cli.args[0] == 'undefined') { | |
system.stderr.write(JSON.stringify({error: 'Missing handle.' + casper.cli.args})); | |
setTimeout(function() { | |
casper.exit(1); | |
}, 0); | |
} | |
// ======================================== | |
// ! Casper test debug | |
// ======================================== | |
if (casper.cli.args[1] == 'test') { | |
casper.options.verbose = true; | |
casper.options.logLevel = "debug"; | |
} | |
function test(callback) { | |
if (casper.cli.args[1] == 'test') { | |
return callback(); | |
} | |
} | |
// ======================================== | |
// ! Start | |
// ======================================== | |
casper.start(); | |
// ======================================== | |
// ! Cookies | |
// ======================================== | |
casper.then(function(){ | |
if (fs.exists('src/cookies_'+credentials.id+'.txt')) { | |
phantom.cookies = JSON.parse(fs.read('src/cookies_'+credentials.id+'.txt')); | |
} | |
}); | |
// ======================================== | |
// ! Login | |
// ======================================== | |
casper.thenOpen('http://www.facebook.com/', function() { | |
if (!casper.visible('form#login_form')) { | |
return true; | |
} else { | |
casper.waitForSelector('form#login_form', function () { | |
this.fill('form#login_form', { | |
email: credentials.email, | |
pass: credentials.pass | |
}, true); | |
}); | |
} | |
}); | |
casper.then(function() { | |
// Cookies | |
var cookies = JSON.stringify(phantom.cookies); | |
fs.write('src/cookies_'+credentials.id+'.txt', cookies, 644); | |
// Bot profile Counter | |
if (fs.exists('src/credentials.json')) { | |
var users = JSON.parse(fs.read('src/credentials.json')); | |
for (i in users) { | |
if (credentials.id === users[i].id) { | |
users[i].idle = false; | |
users[i].tokens = users[i].tokens-1; | |
} else { | |
users[i].idle = true; | |
} | |
fs.write('src/credentials.json', JSON.stringify(users), 644); | |
} | |
} | |
// Test Login | |
test(function() { | |
casper.capture('src/login.png', {top: 0, left: 0, width: 1024, height: 768}); | |
}); | |
}); | |
// ======================================== | |
// ! Username | |
// ======================================== | |
casper.then(function(){ | |
casper.thenOpen('https://www.facebook.com/'+casper.cli.args[0], function() { | |
var selector = '#pagelet_escape_hatch'; | |
function profile(){ | |
var thumb = JSON.parse(document.querySelector('#pagelet_timeline_main_column').getAttribute('data-gt')); | |
return thumb.profile_owner; | |
} | |
function init() { | |
collection.id = casper.cli.args[0].toString(); | |
collection.original_id = casper.evaluate(profile); | |
collection.relations = []; | |
collection.version = 1; | |
collection.global.url = casper.getCurrentUrl(); | |
collection.global.param = collection.global.url.substr(collection.global.url.lastIndexOf('/') + 1); | |
collection.global.handler = collection.global.param.replace('profile.php?id=', ''); | |
collection.data.username = (collection.global.url.indexOf("profile.php?id=") > -1) ? null : collection.global.param; | |
collection.data.email = (collection.data.username) ? collection.data.username.toLowerCase()+'@facebook.com' : null; | |
collection.data.bot = credentials.id; | |
collection.global.url_friends = (collection.data.username) ? 'https://facebook.com/'+collection.data.username+'/friends' : 'http://facebook.com/profile.php?id='+collection.global.handler+'&sk=friends'; | |
collection.global.url_about = (collection.data.username) ? 'https://facebook.com/'+collection.data.username+'/about?' : 'http://facebook.com/profile.php?id='+collection.global.handler+'&sk=about&'; | |
} | |
function timeout(){ | |
system.stderr.write(JSON.stringify({error:'Profile timeout', stack: credentials})); | |
setTimeout(function() { | |
casper.exit(); | |
}, 0); | |
} | |
casper.waitForSelector(selector, init, timeout, collection.global.timeout); | |
// Test username | |
test(function() { | |
casper.capture('src/username.png', {top: 0, left: 0, width: 1024, height: 768}); | |
}); | |
}); | |
}); | |
// ======================================== | |
// ! Counter | |
// ======================================== | |
casper.then(function() { | |
// Cookies | |
var cookies = JSON.stringify(phantom.cookies); | |
fs.write('src/cookies_'+credentials.id+'.txt', cookies, 644); | |
// Test Login | |
test(function() { | |
casper.capture('src/login.png', {top: 0, left: 0, width: 1024, height: 768}); | |
}); | |
}); | |
// ======================================== | |
// ! Education & Work | |
// ======================================== | |
casper.then(function(){ | |
casper.thenOpen(collection.global.url_about+'section=education', function() { | |
casper.page.injectJs('src/jquery.js'); | |
// Education & Work element | |
var selector = '#pagelet_eduwork'; | |
// Init | |
function init() { | |
// Education | |
collection.data.education = casper.evaluate(function() { | |
return $('#pagelet_eduwork>div>div[data-pnref="edu"] li.experience').map(function() { | |
return { | |
name : $(this).find('a:not([class])').text(), | |
link : $(this).find('a:not([class])').attr('href'), | |
role : $(this).find('.fsm').text(), | |
text : $(this).find('.fsm').parent().next().text() | |
}; | |
}).toArray(); | |
}); | |
// Skills | |
collection.data.skills = casper.evaluate(function() { | |
return $('#pagelet_eduwork>div>div:not([data-pnref]) li a').map(function() { | |
return { | |
name : $(this).text(), | |
link : $(this).attr('href') | |
}; | |
}).toArray(); | |
}); | |
// Work | |
collection.data.work = casper.evaluate(function() { | |
return $('#pagelet_eduwork>div>div[data-pnref="work"] li.experience').map(function() { | |
return { | |
name : $(this).find('a:not([class])').text(), | |
link : $(this).find('a:not([class])').attr('href'), | |
role : $(this).find('.fsm').text(), | |
text : $(this).find('.fsm').parent().next().text() | |
}; | |
}).toArray(); | |
}); | |
} | |
function timeout(){ | |
system.stderr.write(JSON.stringify({error:'Education timeout', stack: credentials})); | |
setTimeout(function() { | |
casper.exit(); | |
}, 0); | |
} | |
// Education | |
casper.waitForSelector(selector, init, timeout, collection.global.timeout); | |
// Test Education | |
test(function() { | |
casper.capture('src/education.png', { top: 0, left: 0, width: 1024, height: 768 }); | |
}); | |
}); | |
}); | |
// ======================================== | |
// ! Place | |
// ======================================== | |
casper.then(function(){ | |
casper.thenOpen(collection.global.url_about+'section=living', function() { | |
casper.page.injectJs('src/jquery.js'); | |
var living = '#pagelet_hometown'; | |
function init() { | |
// Lives | |
collection.data.lives = casper.evaluate(function() { | |
return $('#current_city').map(function() { | |
return { | |
name : $(this).find('a:not([class])').text(), | |
link : $(this).find('a:not([class])').attr('href'), | |
role : $(this).find('.fsm').text() | |
}; | |
}).toArray(); | |
}); | |
// From | |
collection.data.from = casper.evaluate(function() { | |
return $('#hometown').map(function() { | |
return { | |
name : $(this).find('a:not([class])').text(), | |
link : $(this).find('a:not([class])').attr('href'), | |
status : $(this).find('.fsm').text() | |
}; | |
}).toArray(); | |
}); | |
} | |
function timeout(){ | |
system.stderr.write(JSON.stringify({error:'Contact timeout', stack: credentials})); | |
setTimeout(function() { | |
casper.exit(); | |
}, 0); | |
} | |
casper.waitForSelector(living, init, timeout, collection.global.timeout); | |
// Test Place | |
test(function() { | |
casper.capture('src/place.png', {top: 0, left: 0, width: 1024, height: 768}); | |
}); | |
}); | |
}); | |
// ======================================== | |
// ! Contact Info | |
// ======================================== | |
casper.then(function(){ | |
casper.thenOpen(collection.global.url_about+'section=contact-info', function() { | |
casper.page.injectJs('src/jquery.js'); | |
var contact_el = '#pagelet_basic'; | |
function init() { | |
// Contact information | |
collection.data.contact = casper.evaluate(function() { | |
var self_obj = {}; | |
return $('#pagelet_contact>div>ul>li').map(function() { | |
var key = $(this).find('span').eq(0).text().toLowerCase(); | |
self_obj[key] = $(this).find('span').eq(1).text(); | |
return self_obj; | |
}).toArray(); | |
}); | |
collection.data.basic = casper.evaluate(function() { | |
var self_obj = {}; | |
return $('#pagelet_basic>div>ul>li').map(function() { | |
var key = $(this).find('span').eq(0).text().toLowerCase(); | |
self_obj[key] = $(this).find('span').eq(1).text(); | |
return self_obj; | |
}).toArray(); | |
}); | |
} | |
function timeout(){ | |
system.stderr.write(JSON.stringify({error:'Contact timeout'})); | |
} | |
casper.waitForSelector(contact_el, init, timeout, collection.global.timeout); | |
// Test Contact | |
test(function() { | |
casper.capture('src/contact.png', {top: 0, left: 0, width: 1024, height: 768}); | |
}); | |
}); | |
}); | |
// ======================================== | |
// ! Family | |
// ======================================== | |
casper.then(function(){ | |
casper.thenOpen(collection.global.url_about+'section=relationship', function() { | |
casper.page.injectJs('src/jquery.js'); | |
var selector = '#pagelet_relationships'; | |
function init() { | |
collection.data.sentimental = casper.evaluate(function() { | |
return $('#pagelet_relationships>div:not([id]) ul>li').find('div.clearfix>div>div>div').text(); | |
}); | |
collection.data.family = casper.evaluate(function() { | |
return $('#family-relationships-pagelet ul>li').map(function(item) { | |
return { | |
name : $(this).find('span').eq(0).text(), | |
link : $(this).find('a').eq(0).attr('href'), | |
kin : $(this).find('span').eq(0).parent().next().text() | |
}; | |
}).toArray(); | |
}); | |
} | |
function timeout(){ | |
system.stderr.write(JSON.stringify({error:'Family timeout', stack: credentials})); | |
setTimeout(function(){ | |
casper.exit(); | |
}, 0); | |
} | |
casper.waitForSelector(selector, init, timeout, collection.global.timeout); | |
// Test Family | |
test(function() { | |
casper.capture('src/family.png', {top: 0, left: 0, width: 1024, height: 768}); | |
}); | |
}); | |
}); | |
// ======================================== | |
// ! Bio | |
// ======================================== | |
casper.then(function() { | |
casper.thenOpen(collection.global.url_about+'section=bio', function() { | |
casper.page.injectJs('src/jquery.js'); | |
// Bio target selector | |
var bio_el = '#pagelet_bio'; | |
// Init | |
function init() { | |
collection.data.bio = casper.evaluate(function(){ | |
return { | |
pronounce : $('#pagelet_pronounce>div>ul>li').find('span').text(), | |
nickname : $('#pagelet_nickname>div>ul>li').find('span').text(), | |
quotes : $('#pagelet_quotes>div>ul>li').find('span').text(), | |
bio : $('#pagelet_bio>div>ul>li').find('span').text() | |
}; | |
}); | |
} | |
function timeout(){ | |
system.stderr.write(JSON.stringify({error:'Bio timeout', stack: credentials})); | |
setTimeout(function(){ | |
casper.exit(); | |
}, 0); | |
} | |
// Wait for selector and init evaluate | |
casper.waitForSelector(bio_el, init, timeout, collection.global.timeout); | |
// Test Bio | |
test(function() { | |
casper.capture('src/bio.png', {top: 0, left: 0, width: 1024, height: 768}); | |
}); | |
}); | |
}); | |
// ======================================== | |
// ! Timeline | |
// ======================================== | |
casper.then(function() { | |
casper.thenOpen(collection.global.url_about+'section=year-overviews', function() { | |
casper.page.injectJs('src/jquery.js'); | |
// Timeline target selector | |
var timeline = '.fbProfileEditExperiences'; | |
// Init | |
function init() { | |
// Unit test assert | |
// Evaluete | |
collection.data.timeline = casper.evaluate(function() { | |
var self_obj = {}; | |
return $('.fbProfileEditExperiences>li').map(function() { | |
var key = $(this).find('.clearfix>div').eq(0).text().toLowerCase(); | |
self_obj[key] = $(this).find('.clearfix>div').eq(1).find('li').map(function() { | |
return { | |
name : $(this).find('span').text(), | |
link : $(this).find('a').attr('href') | |
}; | |
}).toArray().filter(Boolean); | |
return self_obj; | |
}).toArray().filter(Boolean); | |
}); | |
} | |
function timeout(){ | |
system.stderr.write(JSON.stringify({error:'Timeline timeout', stack: credentials})); | |
setTimeout(function(){ | |
casper.exit(); | |
}, 0); | |
} | |
// Wait for selector and init evaluate | |
casper.waitForSelector(timeline, init, timeout, collection.global.timeout); | |
test(function() { | |
casper.capture('src/timeline.png', {top: 0, left: 0, width: 1024, height: 768}); | |
}); | |
}); | |
}); | |
// ======================================== | |
// ! Friends scroll | |
// ======================================== | |
casper.then(function() { | |
casper.thenOpen(collection.global.url_friends, function() { | |
// Friends list element | |
var friends_el = '#pagelet_timeline_medley_friends'; | |
function init() { | |
if (casper.visible('#pagelet_timeline_medley_friends input.inputtext') && casper.visible('#pagelet_timeline_medley_friends li[class]').lenght > 1) { | |
function tryAndScroll() { | |
return casper.waitFor(function() { | |
casper.scrollToBottom(); | |
return true; | |
}, function() { | |
if (!casper.visible('#timeline-medley>div>div:nth-child(2)')) { | |
casper.wait(500, function() { | |
return tryAndScroll(); | |
}); | |
} | |
}); | |
} | |
return tryAndScroll(); | |
} else { | |
return true; | |
} | |
} | |
function timeout(){ | |
system.stderr.write(JSON.stringify({error:'Friends timeout', stack: credentials})); | |
} | |
casper.waitForSelector(friends_el, init, timeout); | |
}); | |
}); | |
// ======================================== | |
// ! Friends format | |
// ======================================== | |
casper.then(function() { | |
var li = '#pagelet_timeline_medley_friends li[class]'; | |
// Check if has friends | |
var friends = casper.visible(li) ? this.getElementsInfo(li) : null; | |
if (friends) { | |
for (var i = 0; i < friends.length; i++) { | |
var friend_id = friends[i].html.match(/data-profileid=["|']+([0-9]+)?/); | |
if (friend_id && friend_id.length) { | |
collection.relations.push({id:friend_id[1]}); | |
} | |
} | |
collection.data.friends_count = collection.relations.length; | |
} | |
// Test friends | |
test(function() { | |
casper.capture('src/friends.png', {top: 0, left: 0, width: 1024, height: 768}); | |
}); | |
}); | |
// ======================================== | |
// ! Save | |
// ======================================== | |
casper.then(function() { | |
delete collection.global; | |
system.stdout.write(JSON.stringify(collection)); | |
}); | |
// ======================================== | |
// ! Run | |
// ======================================== | |
casper.run(function() { | |
var self = this; | |
// Hack phantomjs issue | |
setTimeout(function(){ | |
casper.exit(); | |
}, 0); | |
}); | |
// ======================================== | |
// ! Casper Events | |
// ======================================== | |
// print out all the messages in the headless browser context | |
casper.on('facebook.maxreach', function(msg) { | |
system.stderr.write(JSON.stringify({error: 'Facebook calls to this API have exceeded the rate limit.', stack: msg})); | |
}); | |
// print out all the messages in the headless browser context | |
casper.on('page.error', function(msg, backtrace) { | |
system.stderr.write(JSON.stringify({error: msg, stack: backtrace})); | |
}); | |
casper.on('error', function (msg, backtrace) { | |
system.stderr.write(JSON.stringify({error: msg, stack: backtrace})); | |
}); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment