Skip to content

Instantly share code, notes, and snippets.

@Gro-Tsen
Created June 29, 2021 20:12
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Gro-Tsen/3fd3e452de050c4813c790a5a5fc55b4 to your computer and use it in GitHub Desktop.
Save Gro-Tsen/3fd3e452de050c4813c790a5a5fc55b4 to your computer and use it in GitHub Desktop.
#! /usr/local/bin/perl -w
# This Perl script uses the Twitter API to get the list of friends (or
# optionally, followers) of the calling user, and optionally store it
# in a Twitter list. To use this, you must first get a Twitter API
# key and store it in the $HOME/.twitterkeys file: see comments below
# for how to get this API key from Twitter and the twitterkeys file
# format. Also, the Net::Twitter and DateTime::Format::Strptime
# modules needs to be installed (packages libnet-twitter-perl and
# libdatetime-format-strptime-perl on Debian).
use strict;
use warnings;
# use Encode;
use Getopt::Std;
use Net::Twitter;
use DateTime::Format::Strptime;
use Data::Dumper;
use open IN => ':utf8';
binmode STDIN, ":utf8";
binmode STDERR, ":utf8";
binmode STDOUT, ":utf8";
# Get options
my %opts;
getopts("rd:l:", \%opts);
# -r: output list of followers (rather than following (=friends))
# -d <secs>: delay between requests
# -l <id>: Twitter list id in which to store result (create the list first)
my $max_per_request = 100;
my $delay = ($opts{d} // 30) + 0; # Seconds per request
my $list_id;
if ( defined($opts{l}) ) {
die "Badly formed argument to -l" unless $opts{l} =~ m/^([0-9]+)$/;
$list_id = $1;
}
# See <URL: https://developer.twitter.com/en/apply/user.html > for how
# to apply to get a Twitter API key. The authentication file format
# looks like this (four lines, without the "## " at start; store in
# $HOME/.twitterkeys):
## API-Key: W8L4wLVhV5IZIL6gzuhLHI0Gx
## API-Key-Secret: 0YmJreeefTTqRRaJ50I/Vatl3xQsVTAywbsc3b6SudS51sL427
## Access-Token: 1409939550886109187-RYsUsBC6YR7r1dHw2kSqMZFvSVzUG9
## Access-Token-Secret: XDDKYdu0uo7+BMuMyRo3yPH3Eiw8pj9OREJsDgGN3W6b3
# Read authentication file
my $keyfname = $ENV{"HOME"}."/.twitterkeys";
my %keyfdata;
open my $keyf, "<", $keyfname or die "Can't open $keyfname: $!";
while (<$keyf>) {
s/\#.*//;
next if m/^\s+$/;
die "Bad key file format: $_" unless m/^\s*([A-Za-z][A-Za-z0-9\-]*)\:\s+(\S+)\s*$/;
print STDERR "Read auth data \[$1\]=$2\n";
$keyfdata{$1} = $2;
}
close $keyf;
my $consumer_key = $keyfdata{"API-Key"} or die "Didn't find API-Key in key file";
my $consumer_secret = $keyfdata{"API-Key-Secret"} or die "Didn't find API-Key-Secret in key file";
my $access_token = $keyfdata{"Access-Token"} or die "Didn't find Access-Token in key file";
my $access_token_secret = $keyfdata{"Access-Token-Secret"} or die "Didn't find Access-Token-Secret in key file";
die "Badly formed Access-Token" unless $access_token =~ m/^([0-9]+)\-/;
my $self_id = $1;
# Open the Twitter connection.
my $nt = Net::Twitter->new(
traits => [qw/API::RESTv1_1/],
consumer_key => $consumer_key,
consumer_secret => $consumer_secret,
access_token => $access_token,
access_token_secret => $access_token_secret,
);
die "Couldn't open Twitter connection" unless $nt;
my $datetime_parser = DateTime::Format::Strptime->new(
pattern => "%a %b %d %T %z %Y", time_zone => "UTC", locale => "C",
on_error => "croak");
my $cnt = 0;
for ( my $cursor = -1, my $r ; $cursor ; $cursor = $r->{next_cursor} ) {
if ( $opts{r} ) {
$r = $nt->followers({ count => $max_per_request, cursor => $cursor });
} else {
$r = $nt->friends({ count => $max_per_request, cursor => $cursor });
}
# print Dumper $r;
my @ids;
foreach my $ur ( @{$r->{users} } ) {
my $created_at = $datetime_parser->parse_datetime($ur->{"created_at"});
printf "%d\t%s\t%s\t%s\t%s\t%s\t%s\n", $ur->{id}, $ur->{screen_name}, $created_at->strftime("%Y-%m-%dT%H:%M:%SZ"), $ur->{followers_count}, $ur->{friends_count}, ($ur->{verified}?"true":"false"), $ur->{name};
push @ids, $ur->{id};
$cnt++;
}
stdout->flush();
printf STDERR "Got %d so far (cursor=%d), sleeping...\n", $cnt, $r->{next_cursor};
sleep $delay;
if ( defined($list_id) ) {
$nt->add_list_members({ list_id => $list_id, user_id => \@ids });
sleep $delay;
}
}
@Gro-Tsen
Copy link
Author

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment