はじめに
先日Twitterのタイムラインを見ててwttr.inというcurl
コマンドで各地の天気予報が見れるwebサービスがあることを知りました。
以下の図はcygwin上のcurl
コマンドでの実行例ですが、こんな感じで各地域の天気を知ることが出来ます。
地味に便利なwebサービスです。
で、curl
コマンドでいけるならPowerShellでもなんとかできんのかと思い調べてみたのが今回のエントリの内容になります。
PowerShellでwttr.inを表示してみる
結論から先に書くと、Windows 10 TH2(1511)以降のOSであればPowerShellでwttr.inを表示する事ができます。
PowerShellでwttr.inを表示させるには以下に示す2つの問題に対処する必要があり、ここからはその問題点と対処法について書いていきます。
wttr.inの実装について
調査に先立ってwttr.inの実装について軽く触れておきます。
wttr.inはGithubでソースが公開されておりFlask製のアプリであることがわかります。
また、天気予報の表示にはgoのコマンドラインツールであるwegoが使われています。
UserAgentの設定
最初に何も考えずにPowerShellのcurl(Invoke-WebRequest)
でアクセスしてみます。
すると以下の様になりHTML形式の文字列が返されてしまいます。
# Contentプロパティにアクセスしないといけないのはちと面倒ですが仕方ないですね... (curl http://wttr.in/).Content
wttr.inではUserAgentによってHTMLを返すかコンソール用の文字列を返すか判定しており、UserAgentにcurl
、wget
、httpie
が含まれている場合にコンソール用の文字列を返す様になっています。
ですので、以下の様にUserAgentを指定してアクセスする必要があります。
# -UserAgentを "curl"にしてアクセス (curl http://wttr.in/ -UserAgent "curl" ).Content
ANSIエスケープシーケンスコードの設定
UserAgentを指定してアクセスすることでコンソール用の文字列を返すことができる様になりましたが、今度は以下の様に色付きの部分のANSIエスケープシーケンスコードがそのまま表示されてしまいます。
Windows10までのWindows環境ではANSIエスケープシーケンスコードは表示することが出来ず、ANSICON等のツールで何とか頑張るしかありませんでした。
しかし、Windows 10 TH2のアップデートによりConsole Hostが改善されWin32 APIで設定することによりCmd.exeやPowerShellコンソールでANSIエスケープシーケンスコードを扱える様になりました。
詳細については以下の記事を参照してください。
Nivot Ink | Windows 10 TH2 (v1511) Console Host Enhancements
この記事から抜粋した以下のコードを実行するとPowerShellコンソールのモードを変更してANSIエスケープシーケンスコードが使える様になります。
# # Windows 10 TH2(1511)以降でのみ有効 # # Win32 API定義をAdd-Typeする Add-Type -MemberDefinition @" [DllImport("kernel32.dll", SetLastError=true)] public static extern bool SetConsoleMode(IntPtr hConsoleHandle, int mode); [DllImport("kernel32.dll", SetLastError=true)] public static extern IntPtr GetStdHandle(int handle); [DllImport("kernel32.dll", SetLastError=true)] public static extern bool GetConsoleMode(IntPtr handle, out int mode); "@ -Namespace Win32 -Name NativeMethods # コンソールモードを変更 $Handle = [Win32.NativeMethods]::GetStdHandle(-11) # stdout $Mode = 0 $Result = [Win32.NativeMethods]::GetConsoleMode($Handle, [ref]$Mode) $Mode = $Mode -bor 4 # undocumented flag to enable ansi/vt100 $Result = [Win32.NativeMethods]::SetConsoleMode($Handle, $Mode)
また、コンソールのフォントがLucida Console
でないと表示がずれてしまうので、とりあえずCHCP 437
を実行してコンソールの表示フォントも変えておきます。
# Lucida Consoleフォントを設定画面に出すためにchcp 437しておく。 # フォントの変更は設定画面からやってください chcp 437
その上で再度curl
コマンドを実行すると、一部の色が表示されていない*1ものの、ANSIエスケープシーケンスコードを処理した内容を表示することが出来ます。
# コンソールモードを変更後curlでアクセスする (curl http://wttr.in/ -UserAgent "curl" ).Content
最後に
PowerShellでも頑張ればwttr.inを表示出来ることがわかりました。
Windows 10でない環境の場合は最初の例の様にCygwinを使うのが楽で正確だと思います。
【2016/04/15追記】もう一つの方法
Redditの有志達の間でwttr.inを表示させる別の方法が話題になってました。
ttps://www.reddit.com/r/PowerShell/comments/4e5eyi/making_wttrin_working_with_powershell/
(何故かわかりませんがRedditへのリンクをはるとはてなに怒られるのでh抜きの懐かしい感じにしておきます。)
によると、
(curl -Uri "http://wttr.in/").ParsedHtml.Body.FirstChild.OuterText
とすることで、HTMLの結果から必要な部分を抜き出してコンソールに表示させています。
この方法だと色情報は消失してしまいますがWindows 10でなくても動作しますね。
実行結果はこんな感じです。
【2016/08/03追記】Anniversary Update(1607)
本日Windows 10 Anniversary Update(1607)が来ました。
こちらの更新を適用すれば標準でエスケープシーケンスがサポートされますので、何もせずとも、
(curl http://wttr.in/ -UserAgent "curl" ).Content
とcurl
するだけでよい感じに表示してくれます。
*1:どうもまだ完全なサポートはされていない様です...