Haskellで簡単なDL&テキスト処理
WEBサイトのページをちょちょっとダウンロードしてきて,
簡単なテキスト処理をして必要な情報を抜き出す的なやつ.
HTMLパーサすら要らないくらいの簡単な処理.
今までそういう仕事はRubyでちゃちゃっと書いてたけど,
Haskellでも書いてみようっていうコーナー.
パーサコンビネータ(Parsec)とやらの勉強も兼ねて.
import Network.HTTP ( getRequest , getResponseBody , simpleHTTP) import Text.Parsec ( parse, try, (<|>), ParseError , char, string, anyChar, alphaNum , many1, between) import Text.Parsec.String (Parser) import Control.Applicative ((<$>), (<*>), (*>)) import Data.List (isInfixOf) main :: IO () main = do html <- simpleGet uri mapM_ (print' . generateURI) $ filter containFLV $ lines html where print' = either print putStrLn uri :: String uri = "http://dengekibunko.dengeki.com/webradio/" simpleGet :: String -> IO String simpleGet uri = getResponseBody =<< simpleHTTP (getRequest uri) containFLV :: String -> Bool containFLV = (".flv" `isInfixOf`) generateURI :: String -> Either ParseError String generateURI line = buildURI <$> (pickID line) where buildURI objectID = concat [dir, objectID, ".m4v"] dir = "http://seel.peevee.tv/userdir/h.264sd/" pickID :: String -> Either ParseError String pickID = parse pickOut "" where pickOut = search $ between (string "PeeVeeObject(\"") (string ".flv") $ many1 $ alphaNum <|> (char '/') search :: Parser a -> Parser a search expr = foldr1 (\e f -> try e <|> shiftl f) (repeat expr) where shiftl = (anyChar *>)
mainは, URIからHTMLを得て, 行で分割して, ふるいに掛けて, 処理・書き出し.
search関数はこちらの記事を参照した
http://tnomura9.exblog.jp/15023782/ .
ただし明示的な再帰で表現されていたので,
畳み込みで表現しなおしてみた
(畳み込み方を間違えて無限ループと戦ったりしつつ).
正規表現をちょっと使えば出来る程度のことを
パーサコンビネータでやるのは若干面倒くさくも感じるが,
可読性やメンテナンス性, 再利用可能性を考えると確かに便利そう.
2015.06.26 追記
print'関数を定義して, LeftとかRightをshowしないようにした
(なんかもっとかっこいいやり方がある気もするが…).
調べた限りではeither関数を使うのがよさそう.