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テヌマ別ブログに移動したした。

Source: https://habr.com/ru/post/J85894/


All Articles