0

我在解析来自 url 的数据时遇到问题。

我有带有“https://”的网址,所以我认为我应该使用 import Network.HTTP.Conduit 但是

simpleHttp url

返回 L.ByteString 我真的不明白在那之后我应该做什么

所以我有这样的代码来获取数据

toStrict1 :: L.ByteString -> B.ByteString
toStrict1 = B.concat . L.toChunks

main :: IO ()
main = do
    lbs <- simpleHttp url
    let page = toStrict1 lbs

和解析示例

    let lastModifiedDateTime = fromFooter $ parseTags doc
    putStrLn $ "wiki.haskell.org was last modified on " ++ lastModifiedDateTime
    where fromFooter = unwords . drop 6 . words . innerText . take 2 . dropWhile (~/= "<li id=footer-info-lastmod>")

我怎样才能结合这两个部分的代码?

4

1 回答 1

2

如您所见,该simpleHttp函数返回一个惰性字节串。在 TagSoup 中有几种方法可以处理这个问题。

首先,事实证明你可以直接解析它。该函数parseTags具有签名:

parseTags :: StringLike str => str -> [Tag str]

这意味着它可以str使用StringLike实例解析任何类型,如果您查看Text.StringLike模块文档,您会看到lazyByteStrings有一个StringLike实例。

然而,如果你走这条路,你需要意识到ByteString世界中的一切都是“被困”的,所以你必须使用wordsunwords字节串兼容的函数版本来编写代码,甚至你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.UTF8utf8-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>")
于 2019-05-11T02:55:05.857 回答