Update: Don’t do this. It’s seems obvious now, but for some reason I didn’t realize this would get you banned. Indeed the Twitter account used in the experiment was banned. Luckily we explained ourselves, promised to stop and Twitter re-instated the account :)
_________________________________________________________________
A couple months ago, I decided to spend an evening to try and figure out how I could automate the finding & following process on Twitter. First off let me be clear, this wasn’t for my personal twitter account @gapcm. God knows I don’t care about having lots of followers, nor do I care for all the self-promotion and spam that comes along with having lots of followers. That said, there are cases were a person would want to grow their follower base, even at the expense of following a ton of people – that’s were my script comes into play! First a little background..
About two years ago, my fiance and I started a site called Thursday for Dinner. Thursday for Dinner is a video blog dedicated to preserving family recipes. Our mission, as the site says, is to capture our family’s most treasured recipes and make them available to everyone. The Thursday for Dinner twitter account @tfdtv would be used as the guinea pig. Before I started this experiment, @tfdtv had about 600 followers and was listed about 8 times. After about 1.5 months of using my scripts @tfdtv is up to 2160 followers and is listed 126 times.
The idea of the script is this: If you have API credits left and your followers count is greater than your friends count, search Twitter for a specific term (you can also randomly choose from an array of terms). I always want to have more followers than friends (for this script), otherwise you’re looking a bit desperate. For each user who tweeted the given term, check to see if their already in our database as recently added. Assuming their not in the db, and that their followers to friends ratio is within a certain range, then follow them and add their user name to our database. The ratio is calculated like this:
Code:
$ratio = (($followers_count - $friends_count) / $followers_count);
It’s important to follow people within a specific ratio, cause if their follower to friends count is reasonably close, their more than likely going to follow you back. More important than just the ratio, is the term you use to search Twitter. The term you search needs to be relevant to your twitter stream/site content. For Thursday for Dinner, I search Twitter for the term foodie. It’s obvious that people who Tweet the word foodie, are going to like the premise of our site. Just before the script finishes, it checks all users in the database that are older than 3 days. If the given user is not following back, they are unfollowed. Whether their following or not, their user name is removed from the database.
To use this script, your going to need to know PHP/MySQL/Apache/REST. Your also going to need PEAR MDB2 and curl running. If you don’t know what I’m talking about, save yourself the trouble. First things first, you need to create a new MySQL database with the following table:
Code:
CREATE TABLE IF NOT EXISTS `twitter_users` (
`id` int(11) NOT NULL auto_increment,
`name` varchar(128) NOT NULL,
`date` datetime NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1 AUTO_INCREMENT=2259 ;
I created a class called SessionControl to manage the whole MySQL process. I won’t show that here, but you can download it in the zip below. The main class is the twitter.class.php. This is were the bulk of the work is done.
Code:
<?
require_once 'sessionControl.class.php';
class Twitter {
//
private $username = 'twitter_username';
private $password = 'twitter_password';
//
public function __construct() {
}
//
public function getUsername() {
return $this->username;
}
//
private function getCURL() {
if (!$curld = curl_init()) {
echo "Could not initialize cURL session<br>";
exit();
}
return $curld;
}
//
public function friendshipDetails($u1,$u2) {
$url = "http://twitter.com/friendships/show.json?source_screen_name=$u1&target_screen_name=$u2";
//echo $url;
//exit;
$curld = $this->getCURL();
curl_setopt($curld, CURLOPT_GET, true);
curl_setopt($curld, CURLOPT_URL, $url);
curl_setopt($curld, CURLOPT_HEADER, false);
curl_setopt($curld, CURLOPT_RETURNTRANSFER, true);
curl_setopt($curld, CURLOPT_HTTPHEADER, array('Expect:'));
$output = curl_exec($curld);
$pile = json_decode($output,true);
return $pile;
}
//
public function follow($u) {
$user = SessionControl::getInstance();
//
$url = "http://$this->username:$this->[email protected]/friendships/create/$u.json";
$curld = $this->getCURL();
curl_setopt($curld, CURLOPT_POST, true);
curl_setopt($curld, CURLOPT_URL, $url);
curl_setopt($curld, CURLOPT_HEADER, false);
curl_setopt($curld, CURLOPT_RETURNTRANSFER, true);
curl_setopt($curld, CURLOPT_HTTPHEADER, array('Expect:'));
$output = curl_exec($curld);
//$this->out($output);
$pile = json_decode($output,true);
//$this->out($pile);
//
$sql = "INSERT INTO twitter_users (id, name, date) VALUES (NULL, ".$user->quote($u,"text").", NOW())";
$user->query($sql);
//
return $pile;
}
//
public function isUserInDB($u) {
$user = SessionControl::getInstance();
$result = false;
$sql = 'SELECT * FROM twitter_users WHERE name = '.$user->quote($u,"text");
$sqlRes = $user->query($sql)->fetchAll();
if (!empty($sqlRes)) {
$result = true;
}
return $result;
}
//
private function destroy($u) {
$user = SessionControl::getInstance();
//
$url = "http://$this->username:$this->[email protected]/friendships/destroy/$u.json";
$curld = $this->getCURL();
curl_setopt($curld, CURLOPT_POST, true);
curl_setopt($curld, CURLOPT_URL, $url);
curl_setopt($curld, CURLOPT_HEADER, false);
curl_setopt($curld, CURLOPT_RETURNTRANSFER, true);
curl_setopt($curld, CURLOPT_HTTPHEADER, array('Expect:'));
$output = curl_exec($curld);
$pile = json_decode($output,true);
//
return $pile;
}
//
private function out($v) {
echo '<pre>';
print_r($v);
echo '</pre>';
}
//
public function unfollow($u = '', $days = 3) {
$user = SessionControl::getInstance();
if ($u == '' && $days > 1) {
$sql = "SELECT * FROM twitter_users WHERE date < ".$user->quote($this->getSQLDate(time() - ($days * 24 * 60 * 60)),'text');
$uf = $user->query($sql)->fetchAll();
foreach ($uf as $u) {
$details = $this->friendshipDetails($this->username,$u->name);
//$this->out($details);
//exit();
if (isset($details['relationship']['target']['following'])) {
$key = $details['relationship']['target']['following'];
} else {
$key = 0;
}
// not following, remove
if ($key != 1) {
$this->destroy($u->name);
$this->out('Removed ' . $u->name);
}
//exit();
// either way remove from db
$sqlDel = "DELETE FROM twitter_users WHERE id = $u->id";
$user->query($sqlDel);
}
}
}
//
public function getSQLDate($t) {
return date('Y-m-d H:i:s',$t);
}
//
public function getUser($u) {
$url = "http://twitter.com/users/show/$u.json";
$curld = $this->getCURL();
curl_setopt($curld, CURLOPT_GET, true);
curl_setopt($curld, CURLOPT_URL, $url);
curl_setopt($curld, CURLOPT_HEADER, false);
curl_setopt($curld, CURLOPT_RETURNTRANSFER, true);
curl_setopt($curld, CURLOPT_HTTPHEADER, array('Expect:'));
$output = curl_exec($curld);
$pile = json_decode($output,true);
return $pile;
}
//
public function getSearch($s) {
$url = "http://search.twitter.com/search.json?q=$s";
$curld = $this->getCURL();
curl_setopt($curld, CURLOPT_GET, true);
curl_setopt($curld, CURLOPT_URL, $url);
curl_setopt($curld, CURLOPT_HEADER, false);
curl_setopt($curld, CURLOPT_RETURNTRANSFER, true);
curl_setopt($curld, CURLOPT_HTTPHEADER, array('Expect:'));
$output = curl_exec($curld);
$pile = json_decode($output,true);
return $pile;
}
//
public function getLimit() {
$url = "http://twitter.com/account/rate_limit_status.json";
$curld = $this->getCURL();
curl_setopt($curld, CURLOPT_GET, true);
curl_setopt($curld, CURLOPT_URL, $url);
curl_setopt($curld, CURLOPT_HEADER, false);
curl_setopt($curld, CURLOPT_RETURNTRANSFER, true);
curl_setopt($curld, CURLOPT_HTTPHEADER, array('Expect:'));
$output = curl_exec($curld);
$pile = json_decode($output,true);
return $pile;
}
//
public function __sleep() {
return array_keys(get_object_vars($this));
}
//
public function __wakeup() {
}
}
?>
From here, the main control file called go.php runs everything. This is were the steps are executed. Here it is:
Code:
<?php
require_once 'twitter.class.php';
set_time_limit(-1);
$twitter = new Twitter();
$limit = $twitter->getLimit();
function getSearchTerm() {
//$terms = array("twitter_search_term_1",);
//$r = mt_rand(0,2);
//return $terms[$r];
return 'twitter_search_term';
}
if ($limit['remaining_hits'] > 0){
$me = $twitter->getUser($twitter->getUsername());
if (($me['followers_count']) > $me['friends_count']) {
$sterm = getSearchTerm();
dump('Hits Left: '.$limit['remaining_hits'].' -- Searching: ' . $sterm);
$search = $twitter->getSearch($sterm);
foreach ($search['results'] as $r) {
$user = $r['from_user'];
if (!$twitter->isUserInDB($user)) {
$info = $twitter->getUser($user);
$friends_count = $info['friends_count'];
$followers_count = $info['followers_count'];
if ($friends_count > 0 && $followers_count > 0) {
$ratio = (($followers_count - $friends_count) / $followers_count);
if ($ratio < 0.2 && $ratio > -0.4) {
$twitter->follow($user);
dump($user . ' followed -> friends: ' . $friends_count . ' - Followers: ' . $followers_count);
}
}
} else {
dump($user . ' in db');
}
}
}
//
$twitter->unfollow();
} else {
dump($limit);
}
function dump($r) {
echo '<pre>';
print_r($r);
echo '</pre>';
}
?>
Key points
- Twitter has a limit on the number of API calls you can execute based on a user name and IP address. So don’t run this a) too often and b) on your personal computer. You’ll need to run this on a separate box with a separate IP address.
- You’ll need to automate this with a cron job. I run it every 10 minutes. If your hosting company doesn’t allow for cron jobs, you can use WebBasedCron, which I made 4-5 years ago.
- The code is released under GPL. Use at your own risk. You can download the files here.