【问题标题】:What is the best way to get data from url and parse it on Haskell?从 url 获取数据并在 Haskell 上解析的最佳方法是什么?
【发布时间】:2019-09-24 08:23:18
【问题描述】:

我在解析来自 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>")

如何结合这两部分代码?

【问题讨论】:

  • 您可以使用scalpel。我个人觉得它是一种相当方便的解析 HTML 的方法。它是一个与 Python 中的 BeautifulSoup 具有相同范围的库,但当然更具声明性和类型安全性:)。
  • tagsoup 是另一种选择。
  • toStrict 已经在库中可用时,为什么还要定义toStrict1
  • @MichaelLitchard 是的,我打算使用 tagoup。但我需要用嵌套对象解析列表,文档中没有实际示例。也许你知道我在哪里可以找到这样的? toStrict1 是我的错误,谢谢:) 我现在什至不知道如何处理这个 ByteString...

标签: haskell haskell-tagsoup


【解决方案1】:

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

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

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

这意味着它可以使用StringLike 实例解析任何类型的str,如果您查看Text.StringLike 模块文档,您会发现懒惰的ByteStrings 有一个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 兼容版本的函数,如words 等。)StringText 都有StringLike 实例,因此它们都可以与TagSoup 配合使用。

如果我们要编写生产质量的代码,我们实际上会查阅来自 HTTP 请求的响应标头和/或检查 HTML 中的 &lt;meta&gt; 标记以确定真正的编码。但是,如果我们只是假设编码是 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>")

使用utf8-string 包中的Data.ByteString.Lazy.UTF8String 版本如下所示:

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>")

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2022-01-06
    • 2016-08-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-12-24
    • 1970-01-01
    相关资源
    最近更新 更多