Created
June 29, 2021 20:12
-
-
Save Gro-Tsen/3fd3e452de050c4813c790a5a5fc55b4 to your computer and use it in GitHub Desktop.
This file contains 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
#! /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; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
See https://twitter.com/gro_tsen/status/1409970460293361664 for usage and more comments.