如您所见,该simpleHttp
函数返回一个惰性字节串。在 TagSoup 中有几种方法可以处理这个问题。
首先,事实证明你可以直接解析它。该函数parseTags
具有签名:
parseTags :: StringLike str => str -> [Tag str]
这意味着它可以str
使用StringLike
实例解析任何类型,如果您查看Text.StringLike
模块文档,您会看到lazyByteStrings
有一个StringLike
实例。
然而,如果你走这条路,你需要意识到ByteString
世界中的一切都是“被困”的,所以你必须使用words
与unwords
字节串兼容的函数版本来编写代码,甚至你putStrLn
需要一个适配器。一个完整的工作示例如下所示:
import Network.HTTP.Conduit
import Text.HTML.TagSoup
import qualified Data.ByteString.Lazy as BL
import qualified Data.ByteString.Lazy.Char8 as CL
main :: IO ()
main = do
lbs <- simpleHttp "https://wiki.haskell.org"
let lastModifiedDateTime = fromFooter $ parseTags lbs
putStrLn $ "wiki.haskell.org was last modified on "
++ CL.unpack lastModifiedDateTime
where fromFooter = CL.unwords . drop 6 . CL.words
. innerText . take 2 . dropWhile (~/= "<li id=footer-info-lastmod>")
它工作正常:
> main
wiki.haskell.org was last modified on 9 September 2013, at 22:38.
>
来自的函数Data.ByteString.Lazy.Char8
基本上假设字节串是 ASCII 编码的,这对于这个例子来说已经足够接近了。
但是,根据正确的字符编码将字节串解码为有效的文本类型会更加健壮。Haskell 中两种主要的文本类型是默认String
类型,它效率低且速度慢,但易于使用,另Text
一种是高效但有点复杂的类型。(例如ByteString
,您需要使用Text
- 兼容版本的函数 likewords
等等。)两者String
都有Text
实例StringLike
,因此它们都可以与 TagSoup 一起正常工作。
如果我们要编写生产质量的代码,我们实际上会查阅来自 HTTP 请求的响应标头和/或检查<meta>
HTML 中的标记以确定真正的编码。但是,如果我们只是假设编码是 UTF-8(它是),Text
版本看起来像这样:
import Network.HTTP.Conduit
import Text.HTML.TagSoup
import qualified Data.Text.Lazy as TL
import qualified Data.Text.Lazy.Encoding as TL
import qualified Data.ByteString.Lazy as BL
main :: IO ()
main = do
lbs <- simpleHttp "https://wiki.haskell.org"
let lastModifiedDateTime = fromFooter $ parseTags (TL.decodeUtf8 lbs)
putStrLn $ "wiki.haskell.org was last modified on "
++ TL.unpack lastModifiedDateTime
where fromFooter = TL.unwords . drop 6 . TL.words
. innerText . take 2 . dropWhile (~/= "<li id=footer-info-lastmod>")
并且使用包中的版本String
如下所示:Data.ByteString.Lazy.UTF8
utf8-string
import Network.HTTP.Conduit
import Text.HTML.TagSoup
import qualified Data.ByteString.Lazy as BL
import qualified Data.ByteString.Lazy.UTF8 as BL
main :: IO ()
main = do
lbs <- simpleHttp "https://wiki.haskell.org"
let lastModifiedDateTime = fromFooter $ parseTags (BL.toString lbs)
putStrLn $ "wiki.haskell.org was last modified on "
++ lastModifiedDateTime
where fromFooter = unwords . drop 6 . words
. innerText . take 2 . dropWhile (~/= "<li id=footer-info-lastmod>")