end0tknr's kipple - web写経開発

太宰府天満宮の狛犬って、妙にカワイイ

perl で twitter api へ oauth 後、ユーザ情報を取得

https://blog.thingslabo.com/archives/000063.html

OAUTHの練習として、上記urlの写経。

ただし、上記urlは2011年の内容で、その後のtwitterの仕様変更により 動作しない部分がありましたので、修正しています。

以下を callback.pl というfile名で保存し、 これをCGIとしてブラウザからアクセスすると、ユーザ情報詳細?が表示されます。

OAUTHでの動作を確認する為、「print STDERR "POINT 1.1\n"」のような debug write を大量に入れています

#!/usr/local/bin/perl
use strict;
use warnings;
use utf8;
use CGI;
use OAuth::Lite::Consumer;
use LWP::UserAgent;
use JSON;
use Data::Dumper;

# 「CGI::param called in list context ...」のerrorとなる為、以下を記載
# https://end0tknr.hateblo.jp/entry/20150621/1434845779
$CGI::LIST_CONTEXT_WARN = 0;

# key や secretは、https://developer.twitter.com/en にて取得
my $OAUTH_CONSUMER_PARAM =
    {consumer_key      =>'ないしょ',
     consumer_secret   =>'ないしょ',
     
     site              =>"http://twitter.com/",
     request_token_path=>"https://api.twitter.com/oauth/request_token",
     access_token_path =>"https://api.twitter.com/oauth/access_token",
     authorize_path    =>"https://api.twitter.com/oauth/authorize",
     
     callback_url => 'http://cent80.a5.jp:8080/Test/callback.pl'};

# 今回、試用したAPIの内容は、以下のurlにある説明が分かりやすい。
#  refer to https://syncer.jp/twitter-api-matome/get/account/verify_credentials
my $API_REQ_URL = 'https://api.twitter.com/1.1/account/verify_credentials.json';


main();


sub main {

    print STDERR "POINT 1.1\n";
    
    my $consumer = OAuth::Lite::Consumer->new(%$OAUTH_CONSUMER_PARAM);
    my $query = CGI->new;

    print STDERR "POINT 1.2\n";

    my $oauth_token    = $query->param('oauth_token');
    my $oauth_verifier = $query->param('oauth_verifier');

    if($oauth_token and $oauth_verifier){
        print STDERR "POINT 1.3\n";
        return reqest_with_token_and_verifier($consumer,
                                              $oauth_token,
                                              $oauth_verifier);
    }
    
    print STDERR "POINT 1.4\n";
    return reqest_without_token_and_verifier($consumer,$query);
}

sub reqest_with_token_and_verifier {
    my ($consumer,$oauth_token,$oauth_verifier) = @_;

    print STDERR "POINT 2.1\n";
    my $access_token =
        $consumer->get_access_token(token   =>$oauth_token,
                                    verifier=>$oauth_verifier);
                                    
    print STDERR "POINT 2.2\n";
    my $req = $consumer->gen_oauth_request(method=> 'GET',
                                           url   => $API_REQ_URL,
                                           token => $access_token);
    
    print STDERR "POINT 2.3\n";
    
    my $ua = new LWP::UserAgent();
    my $res = $ua->request($req);

    if(not $res->is_success){
        print STDERR "POINT 2.4\n";
        my $tmp_msg = join(" ", $res->status_line,  $!);
        die $tmp_msg;
    }

        print STDERR "POINT 2.5\n";

    my $account = JSON::decode_json($res->content);

    print "Content-type: text/plain;charset=UTF-8\n\n";
    
    print Dumper($account);
    return;
}

sub reqest_without_token_and_verifier {
    my ($consumer,$query) = @_;

    print STDERR "POINT 3.1\n";
    my $request_token = $consumer->get_request_token();
    my $uri = $consumer->url_to_authorize(token => $request_token);
    print $query->redirect($uri);
    print STDERR "POINT 3.2\n";
    return;
}

ちなみに、以下が、最終的にtwitter apiから取得できた情報

$VAR1 = {
          'status' => {
                        'truncated' => bless( do{\(my $o = 0)}, 'JSON::PP::Boolean' ),
                        'possibly_sensitive' => $VAR1->{'status'}{'truncated'},
                        'in_reply_to_user_id' => undef,
                        'entities' => {
                                        'hashtags' => [
                                                        {
                                                          'indices' => [
                                                                         39,
                                                                         42
                                                                       ],
                                                          'text' => 'fb'
                                                        }
                                                      ],
                                        'user_mentions' => [],
                                        'symbols' => [],
                                        'urls' => [
                                                    {
                                                      'indices' => [
                                                                     16,
                                                                     38
                                                                   ],
                                                      'display_url' => "qiita.com/ine1127/items/\x{2026}",
                                                      'url' => 'http://t.co/VAlerC7r1q',
                                                      'expanded_url' => 'http://qiita.com/ine1127/items/64b5b6cf52471c3fe59c'
                                                    }
                                                  ]
                                      },
                        'created_at' => 'Sat Sep 12 22:57:03 +0000 2015',
                        'is_quote_status' => $VAR1->{'status'}{'truncated'},
                        'favorite_count' => 1,
                        'id_str' => '642834335138099200',
                        'place' => undef,
                        'lang' => 'ja',
                        'in_reply_to_user_id_str' => undef,
                        'in_reply_to_status_id' => undef,
                        'in_reply_to_screen_name' => undef,
                        'text' => "\x{554f}\x{984c}\x{306a}\x{3051}\x{308c}\x{3070}\x{3001}\x{3044}\x{3044}\x{3093}\x{3067}\x{3059}\x{3051}\x{3069}\x{306d}
http://t.co/VAlerC7r1q #fb",
                        'contributors' => undef,
                        'favorited' => $VAR1->{'status'}{'truncated'},
                        'geo' => undef,
                        'id' => '642834335138099200',
                        'in_reply_to_status_id_str' => undef,
                        'retweet_count' => 0,
                        'coordinates' => undef,
                        'source' => '<a href="http://twitter.com" rel="nofollow">Twitter Web Client</a>',
                        'retweeted' => $VAR1->{'status'}{'truncated'}
                      },
          'url' => 'http://t.co/RL6kuGrhX7',
          'created_at' => 'Sat Jul 18 08:56:42 +0000 2009',
          'follow_request_sent' => $VAR1->{'status'}{'truncated'},
          'profile_image_url_https' => 'https://pbs.twimg.com/profile_images/1881562143/profile_normal.gif',
          'name' => 'end0tknr',
          'lang' => undef,
          'translator_type' => 'none',
          'id_str' => '57893029',
          'following' => $VAR1->{'status'}{'truncated'},
          'protected' => $VAR1->{'status'}{'truncated'},
          'profile_background_tile' => $VAR1->{'status'}{'truncated'},
          'entities' => {
                          'description' => {
                                             'urls' => []
                                           },
                          'url' => {
                                     'urls' => [
                                                 {
                                                   'expanded_url' => 'http://d.hatena.ne.jp/end0tknr/',
                                                   'display_url' => 'd.hatena.ne.jp/end0tknr/',
                                                   'url' => 'http://t.co/RL6kuGrhX7',
                                                   'indices' => [
                                                                  0,
                                                                  22
                                                                ]
                                                 }
                                               ]
                                   }
                        },
          'statuses_count' => 520,
          'contributors_enabled' => $VAR1->{'status'}{'truncated'},
          'profile_image_url' => 'http://pbs.twimg.com/profile_images/1881562143/profile_normal.gif',
          'profile_text_color' => '333333',
          'description' => "\x{592a}\x{5bb0}\x{5e9c}\x{5929}\x{6e80}\x{5bae}\x{306e}\x{72db}\x{72ac}\x{306f}\x{3001}\x{5999}\x{306b}\x{304b}\x{308f}\x{3044}\x{3044}",
          'profile_sidebar_fill_color' => 'DDEEF6',
          'default_profile_image' => $VAR1->{'status'}{'truncated'},
          'profile_link_color' => '1DA1F2',
          'id' => 57893029,
          'default_profile' => bless( do{\(my $o = 1)}, 'JSON::PP::Boolean' ),
          'listed_count' => 1,
          'suspended' => $VAR1->{'status'}{'truncated'},
          'is_translator' => $VAR1->{'status'}{'truncated'},
          'profile_background_image_url' => 'http://abs.twimg.com/images/themes/theme1/bg.png',
          'geo_enabled' => $VAR1->{'status'}{'truncated'},
          'notifications' => $VAR1->{'status'}{'truncated'},
          'profile_use_background_image' => $VAR1->{'default_profile'},
          'followers_count' => 3,
          'friends_count' => 10,
          'profile_background_color' => 'C0DEED',
          'has_extended_profile' => $VAR1->{'status'}{'truncated'},
          'screen_name' => 'end0tknr',
          'location' => '',
          'needs_phone_verification' => $VAR1->{'status'}{'truncated'},
          'is_translation_enabled' => $VAR1->{'status'}{'truncated'},
          'profile_sidebar_border_color' => 'C0DEED',
          'favourites_count' => 0,
          'time_zone' => undef,
          'profile_background_image_url_https' => 'https://abs.twimg.com/images/themes/theme1/bg.png',
          'utc_offset' => undef,
          'verified' => $VAR1->{'status'}{'truncated'}
        };