twitterのお気に入りの画像を一括ダウンロード

追記 2017/07/15
C#に書き直した修正版 → https://ptsv.jp/2016/04/20/tweet-image-download-agent/


追記 2015/11/10
修正版 → スクリプトを修正したものを投稿していますm(_ _)m


ツイッターで、検索したりタイムラインに流れる画像で気になったのは片っ端から「お気に入り」に入れてました。で、とある日曜の夜中にふと、「ファボッったツイートの画像を全部ダウンロードしたい!」欲求に駆られ、ググってみたら下記ブログ記事を見つけた。

dyama.org/2014/10/berryjack-simple-twitter-media-downloader-by-shellscript/

ここで書かれていたtimelineに直接リクエストを投げる方法を、ブラウザで確認しながら調べてみると、できそうだったので、シェルスクリプトを流用させてもらいました。(m_m)
・・・Windowsなので、perlに書き直して完了。Win32版のwget.exeが必要ですが・・・。

ただ、「お気に入り」の画像を一括ダウンロードするにはログインが必要なんで、その部分を調べて書くのが面倒だったんで、Internet Explorerでログインした後、クッキーをエクスポートし、twitter.comドメインの部分だけ抜き出し cookies.txt と保存し、それをwgetに食わせることで強引に解決(^^;;; とりあえずなんで目をつむる。

Twitter APIとか使わないといけないのかなー、と思ってたんですが、上記ブログ記事のシェルスクリプトのおかげで随分簡単にゲトできました。ありがとうございました(^.^)

探せば便利なソフトがあると思うんですが・・・簡単にできたんで別にいいか(^^;
また、時間があれば、C#に書き直してGUIつくろー。

#!/usr/bin/perl
# 使い方
#
# > perl twitter.pl 画像タイムラインのURL(下記参照)
#
# 【任意のTwitterIDの画像の場合】
# https://twitter.com/i/profiles/show/(TwitterID)/media_timeline

# 【自分のお気に入りの場合】
# https://twitter.com/(自分のTwitterID)/favorites/timeline
# 別途ログイン後のクッキーが必要。IEなどでログインしてエクスポート。
# twitter.comドメインだけ抜き出して 同じディレクトリにcookies.txt として保存する必要あり。
#
# tmpというディレクトリがカレントディレクトリに作成され、画像がダウンロードされます。
# ダウンロードエージェントに GNU Wgetを利用しています。
# おいらのようにwindowsな人は別途 Win32版 GUN WGETが必要。

# 【追記】 wgetを使用せず、LWP::UserAgentを使用するように加筆したものを一番下に追加

use bigint;
mkdir 'tmp' unless(-e './tmp');
$param = '';
$timeline = $ARGV[0] || die "input timeline url...\n";

@options = ('--no-check-certificate',
            '-O -',
            "-a ./tmp/wget_$$.log");
push @options,'--load-cookies=cookies.txt' if(-e 'cookies.txt');

$options = join(' ',@options);
do
{
  $wget = sprintf('wget %s "%s%s"',$options,$timeline,$param);
  print $wget,"\n";
  $result = `$wget`;
  $result =~ s/\\\//\//g;

  @result = $result =~ m!https://pbs\.twimg\.com/media/\w+\.\w{3,4}\:large!g;
  foreach(@result)
    {
      $out = '';
      if(m/(\w+\.\w{3,4})\:large$/)
        {
          $filename = "tmp/$1";
          $out = "-O $filename";

          unless(-e $filename)
            {
              system("wget --no-check-certificate -a ./tmp/wget_$$.log -P tmp -nd $out $_");
              print "saved $1\n";
            }
        }
    }

  @result = $result =~ m/data-tweet-id=\\\"([0-9]+)/g;
  @result = sort @result;

  $cxt_id = shift @result;
  $max_id = $cxt_id - 1;

  $param = "?contextual_tweet_id=$cxt_id&max_id=$max_id";
} while( $cxt_id );

【追記】

wget を使う代わりに、LWP::UserAgent を使用するように改変。使い方は上と一緒。
・・・なんか無駄にコードが増えた(ーー;;;

#!/usr/bin/perl

# 使い方は上記wgetを使用するものと一緒

use strict;
use warnings;
use bigint;
use LWP::UserAgent;
use HTTP::Cookies;
use Time::Piece;

#クッキーファイル名
my $COOKIE = 'cookies.txt';

#作業用クッキーファイルパス
my $TMP_COOKIE = './tmp/libwww.'.$COOKIE;

#エージェント
my $UserAgent = LWP::UserAgent->new;

&{sub
{
  #arguments
  my @argv = @_;
  mkdir 'tmp' unless(-e './tmp');

  my $tmp = "./tmp/$$.media";
  my $param = '';
  my $timeline = $argv[0] || die "input timeline url...\n";
  my ($cxt_id,$max_id);

  #cookies.txtがカレントディレクトリにあればフォーマット変換して作業用ファイルに保存
  if(-e $COOKIE)
    {
      &convert_cookie;
      $UserAgent->cookie_jar(HTTP::Cookies->new(file => $TMP_COOKIE,autosave => 1));
    }

  do
    {
      $timeline = $argv[0].$param;

      print "---- getting and parsing\n$timeline ...\n----\n";
      my $result = &lwp_agent($timeline,'-') || die "can not get timeline. may be wrong url.\n";
      $result =~ s/\\\//\//g;

      foreach my $url_($result =~ m!https://pbs\.twimg\.com/media/\w+\.\w{3,4}\:large!g)
        {
          my $out = '';
          if($url_ =~ m/(\w+\.\w{3,4})\:large$/)
            {
              my $filename = "tmp/$1";
              unless(-e $filename)
                {
                  &lwp_agent($url_,$filename);
                  print "saved $1\n";
                }
            }
        }

      my @result = $result =~ m/data-tweet-id=\\\"([0-9]+)/g;
      @result = sort @result;

      $cxt_id = shift @result;
      $max_id = $cxt_id - 1;

      $param = "?contextual_tweet_id=$cxt_id&max_id=$max_id" if(defined $cxt_id);

    } while( $cxt_id );

  print "done!\n";

  #作業用のクッキー削除
  unlink $TMP_COOKIE if(-e $TMP_COOKIE);

}}(@ARGV);

sub lwp_agent
{
  my ($url,$ofile) = @_;
  my %options = ();

  if($ofile ne '-')
    {
      return $UserAgent->get($url,':content_file' => $ofile);
    }
  else
    {
      if(my $response = $UserAgent->get($url))
        {
          return $response->decoded_content;
        }
    }
  0;
}

sub convert_cookie
{
  my $fin = IO::File->new($COOKIE);
  my $fout = IO::File->new('>'.$TMP_COOKIE);

  $fout->print("#LWP-Cookies-1.0\n");
  foreach my $line_($fin->getlines)
    {
      chomp $line_;
      next if($line_ =~ /^$/ || $line_ =~ /^\#/);
      my ($domain,$flag,$path,$secure,$expires,$name,$value) = split(/\s+/,$line_);
      my $t = gmtime($expires);
      $expires = sprintf('%s, %d-%s-%04d %02d:%02d:%02d GMT',
                         $t->day,
                         $t->mday,
                         $t->month,
                         $t->year,
                         $t->hour,
                         $t->min,
                         $t->sec);
      $secure = $secure eq 'TRUE' ? 'secure' : '';

      $fout->print(qq(Set-Cookie3: $name=$value; path="$path"; domain=$domain; path_spec; expires="$expires"; $secure\n));
    }

  $fin->close;
  $fout->close;
}
__END__