Adam Green
Twitter API Consultant
adam@140dev.com
781-879-2960
@140dev

Twitter API Tools: Get list member user profiles

by Adam Green on February 14, 2014

in 140dev Source Code,Twitter API Tools

Installation note: All of the Twitter API tools are built around a set of common library files that must be downloaded and installed before running the code shown here.

Twitter lists are a really underutilized feature, especially now that the limits have been raised to 1,000 lists, each with 5,000 members. I doubt if anyone will need 5,000,000 list members, but there are more uses for lists than most people realize. I think lists make a great way for users to generate a set of accounts that can be used by other apps.

Instead of building an entire user interface by hand to allow users to input a set Twitter accounts for your apps, you can let them build and manage a list in Twitter, and then read that list as input for your processing. Another benefit is that users can share their lists with others. A team can collaborate through lists by creating a Twitter account and sharing the login, so they can all edit the lists.

Today’s tool reads any public Twitter list from any account, and adds complete account profiles for the members to a database. It allows you to collect multiple lists into a single table, while keeping their original list identity. It also clears the members of any list from the table as an option, so you can refresh the database copy when users change the list.

Since this tool needs a database table for storage, I have included the MySQL creation statement at the start of the script. I’m going to keep this model for all the tools. It also serves as useful documentation. You can copy this statement and paste it into the SQL box in phpMyAdmin.

list_members.php

<?php
// Copy list members to a database table
// Copyright (c) 2014 Adam Green. All rights reserved. 
// Contact info: http://140dev.com, @140dev, adam@140dev.com
// Released as open source under MIT license

/* Create this table to store list members
CREATE TABLE IF NOT EXISTS `list_members` (
  `owner_screen_name` varchar(20) NOT NULL,
  `slug` varchar(100) NOT NULL,
  `user_id` bigint(20) unsigned NOT NULL,
  `screen_name` varchar(20) NOT NULL,
  `name` varchar(40) DEFAULT NULL,
  `profile_image_url` varchar(200) DEFAULT NULL,
  `location` varchar(30) DEFAULT NULL,
  `url` varchar(200) DEFAULT NULL,
  `description` varchar(200) DEFAULT NULL,
  `created_at` datetime NOT NULL,
  `followers_count` int(10) unsigned DEFAULT NULL,
  `friends_count` int(10) unsigned DEFAULT NULL,
  `statuses_count` int(10) unsigned DEFAULT NULL,
  `protected` tinyint(1) NOT NULL,
  PRIMARY KEY (`owner_screen_name`,`slug`,`user_id`),
  KEY `screen_name` (`screen_name`),
  KEY `owner_screen_name` (`owner_screen_name`),
  KEY `slug` (`slug`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
*/

// Arguments for list_members()
// $owner_screen_name is a string with account screen name
// $slug is a string with list name, spaces are replaced with - 
// For example: https://twitter.com/twitter/lists/official-twitter-accts
// $owner_screen_name = twitter
// $slug = official-twitter-accts

// $table_name is a string with name of DB table for users
// $clear_table is an optional value, if set to 1 the table is truncated first
function list_members($owner_screen_name, $slug, $table_name, $clear_table=0) {
	
  if (empty($owner_screen_name) || empty($slug) || empty($table_name)) {
    print "ERROR: Invalid arguments";
    exit;
  }
		
  // Connect to the database
  require('db_lib.php');
  $oDB = new db;
	
  if ($clear_table) {
    // Clear the table of old entries for this list
    $oDB->select("DELETE FROM $table_name
      WHERE owner_screen_name = '" . $oDB->escape($owner_screen_name) . "' " .
      "AND slug = '" . $oDB->escape($slug) . "'");
  }

  // Connect to API with OAuth
  require('oauth_lib.php');
  $connection = get_connection();	
	
  // Loop through pages of members, each page has 20 members
  // This is rate limited to 480 calls per 15 minute window
  // The total is 9,600 members, more than the 5,000 member limit
	
  // Start cursor at -1, end when cursor becomes 0
  $cursor = -1;	
  while ($cursor<>0) { 
    $connection->request('GET', $connection->url('1.1/lists/members'), 
      array('owner_screen_name' => $owner_screen_name,
      'slug' => $slug,
      'include_entities' => false,  // We don't need user's entities
      'skip_status' => true, // We don't need user's last tweet
      'cursor' => $cursor));
				
    // Exit on API error
    if ($connection->response['code'] <> 200) {
      print "ERROR: " . $connection->response['code'] . "\n";
      print $connection->response['response'];
    }
	
    // Escape string values that may contain quotes
    $owner_screen_name = $oDB->escape($owner_screen_name);
    $slug = $oDB->escape($slug);
		
    $results = json_decode($connection->response['response']);
    $users = $results->users;
    foreach($users as $user) {
			
      $screen_name = $oDB->escape($user->screen_name);
			
      // Prevent duplicates
      $where = "owner_screen_name = '$owner_screen_name' 
        AND slug = '$slug' AND screen_name = '$screen_name'";
      if (!$oDB->in_table($table_name,$where)) {
				
        // If user is not protected
        if (empty($user->protected)) {
          $protected = 0;
        } else {
          $protected = 1;
        }				
				
        $field_values = "owner_screen_name = '$owner_screen_name', " .
          "slug = '$slug', " .
          "user_id = " . $user->id_str . ", " .
          "screen_name = '$screen_name', name = '" . $oDB->escape($user->name) . "', " .
          "profile_image_url = '" . $user->profile_image_url . "', " .
          "location = '" . $user->location . "', " .
          "url = '" . $user->url . "', " .
          "description = '" . $oDB->escape($user->description) . "', " .
          "created_at = '" . $oDB->date($user->created_at) . "', " .
          "followers_count = " . $user->followers_count . ", " .
          "friends_count = " . $user->friends_count . ", " .
          "statuses_count = " . $user->statuses_count . ', ' . 
          "protected = $protected";
					
         $oDB->insert($table_name, $field_values);
       }
    }

    // Get the cursor for the next page of results
    $cursor = $results->next_cursor;
  }
}

?>

You can test this tool with list_members_test.php, which is set to read the members of this list: https://twitter.com/twitter/lists/twitter-engineering.

list_members_test.php

<?php

require('list_members.php');
list_members('twitter','twitter-engineering','list_members',1);

?>

One other point. This will read public lists from any account, and can also read a private list owned by the account whose OAuth tokens are used for making the API request.

Leave a Comment

Previous post:

Next post: