Haskellでvkontakte.ruステータスにTwitter(またはrss)を再投稿する

この記事では、ツイートをVKontakteステータスに再投稿する小さなプログラムに焦点を当てます。

タスクは非常にシンプルで、完全に独創的です。 それはすべて、これがpythonでどのように解決されるかについてのHabrに関する記事とphpに関する同様の記事を読んだという事実から始まりました。 インターネット上では、一部のオンラインサービスでさえこのタスク専用であるようです。 しかし、ここでは、お気に入りのツールを使用して、この単純な問題を自分で解決することが全体の目的です。 実際、phpのソリューションは後で同じ目的で登場しました。



さて、何を書いたのですか? ハスケルで、natürlich!

私がすべてをどうやってやったか、そしてそれをどのように繰り返すかについて、もう少し詳しく説明します。 おそらく、理解するのに特別な知識は必要ありません。



エントリー



Haskellのlivejournalのrssからの再投稿に関する2つの記事と記事は、ソリューションの実装に役立ちました。

最初、私は正直にtwitter-apiを介してtwitterの仕事をしたかったのですが、対応するライブラリをハッカーから突きましたが、すぐには機能せず、そのままにしておきました。 そして、twitterはrssで放送されており、haskellでrssを読むことはすでに解決された問題なので、私はこの方法で行った。

さらに、これはより普遍的なソリューションです。 任意のrssチャンネルをvkontakteにブロードキャストできます。 これはtwitter2vkontakteではなく、rss2vkontakteであると言うこともできます。

さらに、 vkontakte-apiを使用し、前任者のようにステータスを検索するページを解析しませんでした。 これはプラスだと思います。



残りは文学的ハスケルコードです。 つまり、コメント付きのコードではなく、haskellの通常のソースであるコード片付きの詳細なコメントです。 この投稿は、拡張子が.lhsのファイルに全体として単純に保存し、インタープリター/コンパイラーに渡すことができます。 すべて正常に動作するはずです。

すべての作業コードは、次の文字で強調表示されます: >







必要な準備



既にHaskellコンパイラとコアライブラリセットが用意されていることを前提としています。 そうでない場合、これは簡単に修正できます-Haskell Platformをインストールする必要があります 。 とても簡単です。



次に、追加のライブラリをインストールするには、コンソールに入力するだけです:

cabal update

cabal install regex-tdfa curl feed utf8-string







以下は、インポートの簡単なリストと簡単な説明です。

正規表現を数回使用しました:



> import Text.Regex.TDFA ( (=~) )







リストをカットアンドペーストしたら:



> import Data.List ( intercalate )







すべてのインターネットリクエストに、curlライブラリを使用しました。



> import Network.Curl ( curlGetString )

> import Network.Curl.Opts







RSSフィードを読んで解析します。



> import Text.Feed.Import ( parseFeedString )

> import Text.Feed.Query ( getFeedItems , getItemSummary )







そして、一度文字列をUnicodeにエンコードしたとしても:



> import Codec.Binary.UTF8.String ( encodeString )









さらに、より充実した、おそらくは不必要に詳細な説明を含む、より有益なコードがあります...



RSS経由のTwitter



最初に必要なのは、rssツイートフィードのアドレスです。 Twitterページで取得できます。 別の定数を取得しましょう:



> feedUrl = "https://twitter.com/statuses/user_timeline/22251772.rss"







rssフィードを取得して解析する方法については、rss2ljに関する記事を参照してください 。 しかし、私はこのライブラリを使用しませんでした。 もちろん、すべてがうまくできていますが、rssフィードをダウンロードし、最初の要素を取得してその内容を抽出する簡単な関数が必要です。 そして、ここに私がそれを作った方法があります:



> getTweet :: IO String

> getTweet = do

> (_,feed) <- curlGetString feedUrl []

> return $ getMsg $ head $ getItems feed

> where

> getItems = maybe (error "rss parsing failed!" ) getFeedItems . parseFeedString

> getMsg = maybe (error "rss-item parsing failed!" ) format . getItemSummary

> format = unwords . ( "twitter:" : ) . tail . words . encodeString







その中で何が起こっているのかを説明します。 curlGetString :: URLString -> [CurlOption] -> IO (CurlCode, String)



は、url、オプションのリストをCurlOk



、操作コード(すべてがうまくCurlOk



場合はCurlOk



)とサーバー応答を提供します。 この場合、twitter-rssフィードをアドレスとして指定し、オプションは指定しません。 完了コードには注意を払いません。 しかし、答えの大部分はフィードと呼ばれます。

次の行は右から左に読む必要があります:フィード要素( getItems feed



)を抽出し、リストを取得し、そこから最初の要素( head



)を取得し、そこからメッセージ自体( getMsg



)を抽出して出力に返します。

そして、これらの関数について、同じ順序でさらに詳しく説明します。 それらはそれぞれ、ポイントフリースタイルで、つまり、引数を指定せずに、他の関数の構成(ドット)として単純に記述されます。

コンポジションは、右から左へ、ポイントgetItems



に読み取ることもできます(つまり、関数の適用順: getItems



まずparseFeedString



関数(フィードライブラリから)を使用します。タイプ( parseFeedString



String -> Maybe Feed



)、つまり、あらゆる種類のポリッジを含む文字列を受け取ります。 rssタグから生成されますが、抽象タイプのフィードを作成します。これにより、既に何かを行うことができますMaybe Feed



値が返されるため、パーサーが抑制されてNothing



が返されることがあります。パースがうまくいけば、我々は(の値を取得。«RSS解析が!失敗» Just



)し、その後ではないに適用されます 機能にgetFeedItems



リスト中のフィード要素から抽出され、この分岐( Nothing



Just ...



)、標準的な機能を実装しmaybe





getItems



機能した後、フィードアイテムのリストを取得します: [Item]



。 必要なのは、最初のもの(つまり、日付による最後のもの)だけです。 head



機能でそれを取る。 そして、 getMsg



メッセージテキストgetMsg



を掘り下げたいとgetMsg



ます。

この関数の構造はgetItems



似ていgetItems



。最初にgetItemSummary



getItemSummary



Maybe String



が返されます。 コンテンツを抽出できなかった場合、対応するエラーを発行します。 それ以外の場合は、受信したメッセージをフォーマットします。

フォーマット( format



)は次のように簡単に実行されます(再び右から左へ):文字列をUnicodeでエンコードし、(スペースで)単語に分割し、最初の単語を削除し、代わりに「twitter:」を挿入し(オプション)、すべての単語を1行に戻します。 rssツイートの最初の単語は常にあなたのニックネームです。 したがって、私たちはそれを捨てます。



それはすべてrssです。 私はすべてをあまりにも詳細に説明したかもしれませんが、興味があり、haskellに不慣れな人にとっては、この説明は意味のあるものだったと思います。



Vkontakte API



まず、VKontakteを操作するための定数をいくつか作成します。



> email = " e-mail"

> uid = " user-id "

> pass = " "







これは、VKontakteでの登録に対応するデータです。



すべての操作は、対応するトリッキーなアドレスを使用して、サーバーへのGET要求(同じcurlGetString



関数)によって実行されます。 それらは次のように構築されます。

ベースアドレス(例: userapi.com/data ?)と、アンパサンド&で区切られたkey = valueの形式のパラメータのリスト

そのようなアドレスを形成するために、いくつかの補助関数を作成します。



> param :: (String, String) -> String

> param (key, value) = key ++ "=" ++ value ++ "&"







この関数は、単純にペア(キー、値)を受け取り、そこから目的の形式の文字列を作成します。



> formUrl :: String -> [(String, String)] -> String -> String

> formUrl base opts sid = base ++ ( concatMap param (opts ++ [( "id" ,uid)]) ) ++ sid







baseのベースアドレス、オプションopts



のリスト(ペアの形式)、およびセッションID sid



(後でそれについて)から、必要な形式のURLを形成します。

内容は括弧内にありmap



。mapは関数とリストを取り、リストの各要素に関数を適用します。 つまり、ペアのリスト(, )



から、文字列のリストを"=&"



ます。 そして、 concat



これらすべての行を1つに接着します( concatMap = concat . map



)。

タスクごとにオプションのセットは異なりますが、すべての場合、ユーザー識別子( uid



)を指定する必要があります。そのため、毎回このオプションを記述しないように、この関数の定義に追加します。



何らかの形でVKontakteを使用するには、最初にログインする必要があります。 サーバーは、Cookie(Cookie)とセッションID(sid =セッションID)を提供します。 クッキーは使用しませんでしたが、ユーザーデータの取得/変更に関するほとんどすべての操作にはsidが必要です。



> login :: IO String

> login = do

> (_,headers) <- curlGetString authUrl [CurlHeader True]

> return ( headers =~ "sid=[a-z0-9]*" :: String )

> where

> authUrl = formUrl "http://login.userapi.com/auth?"

> [( "site" , "2" ), ( "fccode" , "0" ),

> ( "fcsid" , "0" ), ( "login" , "force" ),

> ( "email" ,email), ( "pass" ,pass)] ""







認証アドレスには多くのオプションがあり、その目的は理解していませんでしたが、ドキュメントから取ったので、それらなしでは何も機能しません。 書かれたformUrl



関数を使用してこのアドレスを作成し、電子メールとパスワードが最後の2つのオプションに挿入されます。 ただし、sidパラメータは空のままです。まだ持っていません。実際には、 login



関数を作成しました。

その中で何が起こるか:curlリクエストがauthUrl



に送信され、 headers



が返されます(このために、 CurlHeader



オプションがCurlHeader



)。 実際には、Cookie、リダイレクトアドレスなどがあります。 これがサーバーが送信するアドレスです。探しているものは隠されています。 秘密の正規表現手法を使用して、「sid = 35dfe55b09b599c9​​fx622fcx8cd83a37」という形式の切望されたセッションIDがheaders



から取り出されます。

haskellでの正規表現については説明しません。これは別のトピックです。 これは、目的のタイプの部分文字列の単なる検索であると想定できます。



いいね! sidを取得しました。現在、apiのすべての可能性が連絡しています。 このタスクでは、ステータスの変更という1つだけが必要です。

原則として、VKontakteとのやり取りは次のコマンドで無料です。



(_,answer) <- curlGetString someUrl []







someUrl



は対応するリクエスト(ドキュメントを参照)であり、 answer



はサーバーの応答です。 ステータス変更リクエストは次のようになります。



> setActivityUrl :: String -> String -> String

> setActivityUrl text = formUrl "http://userapi.com/data?" [( "act" , "set_activity" ), ( "text" , text)]







formUrl



関数の3番目のパラメーターsid



は指定されていないことに注意してください。 これは部分的なアプリケーションです-関数には3つのパラメーターがあり、2つだけを指定しました。これは、残りの1つのパラメーターから関数を取得したことを意味します。 つまり、 setActivityUrl



は、 text



パラメーター(実際には新しいステータス)だけでなく、2番目のsid



パラメーターの関数であり、それは、そのまま右側に追加されます。



もう一つの些細なこと:ツイートのテキストにはスペースがありますが、これはurlリクエストには受け入れられません。 したがって、すべてのスペースを%20で置き換える単純な関数を作成します。



> escSpaces = intercalate "%20" . words







文字列を単語のリストに分割し、このリスト内の隣接するアイテムの間に文字列「%20」を挿入し、すべてを再び1つの文字列に接着します(最後の2つのアクションはintercalate



関数によって行われます)。



これで、既に説明した部分からステータスを変更する機能を収集できます。



> setStatus :: String -> String -> IO ()

> setStatus text sid = do

> (_,answer) <- curlGetString url []

> if answer =~ " \" ok \" :1" :: Bool

> then putStrLn text

> else error "something is bad with vkontakte-api..."

> where

> url = setActivityUrl (escSpaces text) sid







この関数をより簡単に1行で記述することができます。



setStatus text sid = curlGetString (setActivityUrl (escSpaces text) sid) []







しかし、最初のオプションはより明確で、サーバーの応答を確認します-回答に"ok":1



が含まれる場合"ok":1



、すべてが正常です-ステータスが変更され、ユーザーに(つまり、自分自身に)通知します。

それだけです! これで、モザイクのすべての部分が揃い、組み立てが非常に簡単になりました。



メイン



これらのすべての機能が何のために書かれたか:



> main = do

> tweet <- getTweet

> sid <- login

> setStatus tweet sid







とてもシンプルに見えますよね? ここではコメントは不要です。

私の説明では、他のすべての機能は非常に明確に見えると思います。

〜40 LinesOfCodeのための統計。



おわりに



このコードを実行するには、既に述べたように、投稿全体を拡張子.lhsのファイルに保存し、コンソールに入力する必要があります。



runhaskell _.lhs







以上です。

このリリースを自動化する方法について話すために続編が必要かどうかはわかりません。

私自身(Mac OS Xのユーザーとして)は、Automatorで「サービス」を作成し、ホットキーを割り当てることでこれを決定しました。それをすばやく呼び出すことは、起動を自動化するだけですが、これで十分です。



これが読む人にとって興味深いものであったことを願っています。 質問/提案/異議を待っています(:



upd:テーマ別ブログに移動しました。



All Articles