フォロワーの差分(OAuth 版)
http://d.hatena.ne.jp/chabom/20100818/1282092637 のコードはBasic 認証でもう使えないので、OAuth 対応した。
利用するには、Consumer key, Consumer secret, Access Token, Access Token Secret は Twitter Developer Platform — Twitter Developers でアプリを登録して取得する必要があります。
signature 作るところで、16 進表記は大文字にしないといけないのに気づかずにハマッた。System.Web.HttpUtility.UrlEncode は小文字で出力される。バカチン。
Hexadecimal characters in encodings MUST be upper case
http://oauth.net/core/1.0/#encoding_parameters
$API_URL = "https://api.twitter.com/1/statuses/followers.xml" $API_METHOD = "GET" $OLD_FILE = "followers_old.txt" # System.Web.HttpUtility.UrlEncode だと 16 進数が小文字になってダメなので function Encode-URL($s){ ($s.ToCharArray() | foreach { if ($_ -match "[a-z]|[-,_,.,~,)]|[0-9]") { $_ } else { "{0}{1:X}" -f "%", [System.Text.Encoding]::ASCII.GetBytes($_)[0] } }) -join "" } function Create-OAuthHeader { param ( [string]$url, [string]$method ) $CONSUMER_KEY = "Consumer key" $CONSUMER_SECRET = "Consumer secret" $TOKEN = "Access Token" $TOKEN_SECRET = "Access Token Secret" # unix-time $timestamp = [int](((Get-Date) - [DateTime]"1970/01/01 09:00:00").TotalSeconds) $rand = New-Object System.Random $nonce = $rand.next(123400, 9999999).ToString() $params = @("oauth_consumer_key=$CONSUMER_KEY", "oauth_nonce=$nonce", "oauth_signature_method=HMAC-SHA1", "oauth_timestamp=$timestamp", "oauth_token=$TOKEN", "oauth_version=1.0") | sort # signature を作る $base = @( $method, (Encode-URL $url), (Encode-URL ($params -join "&")) ) $base = $base -join "&" $hmac = New-Object System.Security.Cryptography.HMACSHA1 $hmac.Key = [System.Text.Encoding]::ASCII.GetBytes($CONSUMER_SECRET + "&" + $TOKEN_SECRET) $hash = $hmac.ComputeHash( [System.Text.Encoding]::ASCII.GetBytes($base) ) $signature = Encode-URL( [System.Convert]::ToBase64String($hash) ) $params += "oauth_signature=$signature" return $params -join "," } $wc = New-Object System.Net.WebClient $users = @() $cursor = -1 while ($cursor -ne 0) { $header = Create-OAuthHeader $API_URL $API_METHOD $wc.Headers.Set("Authorization", "OAuth $header") $xml = [xml] $wc.DownloadString($API_URL + "?cursor=$cursor") $cursor = $xml.users_list.next_cursor # $users に 現在のfollowersを入れる $xml.users_list.users.user | foreach { $users += $_.screen_name } } $wc.Dispose() # diff Compare-Object $(Get-Content $OLD_FILE) $users -SyncWindow 100 # 現在のfollowersをold.txtに出力する Set-Content -Path $OLD_FILE -Value $users "current followers: " + $users.length