Skip to content

Instantly share code, notes, and snippets.

@rendon
Created January 6, 2016 20:46
Show Gist options
  • Save rendon/94da8c42953f94635622 to your computer and use it in GitHub Desktop.
Save rendon/94da8c42953f94635622 to your computer and use it in GitHub Desktop.
FB bot
// ========================================
// ! 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