首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >通过镜头从树上过滤内部元素

通过镜头从树上过滤内部元素
EN

Stack Overflow用户
提问于 2016-09-30 08:20:49
回答 1查看 333关注 0票数 2

我经常承认我的镜头不好,但是通过例子学习不是一件好事吗?我想要使用HTML,用taggy-lens解析它,然后从内部删除所有的script元素。以下是我的尝试:

代码语言:javascript
复制
#!/usr/bin/env stack
-- stack --resolver lts-7.1 --install-ghc runghc --package text --package lens --package taggy-lens --package string-class --package classy-prelude

{-# LANGUAGE NoImplicitPrelude #-}
{-# LANGUAGE OverloadedStrings #-}

import ClassyPrelude
import Control.Lens hiding (children, element)
import Data.String.Class (toText, fromText, toString)
import Data.Text (Text)
import Text.Taggy.Lens
import qualified Text.Taggy.Lens as Taggy
import qualified Text.Taggy.Renderer as Renderer

somehtmlSmall :: Text
somehtmlSmall =
    "<!doctype html><html><body>\
    \<div id=\"article\"><div>first</div><div>second</div><script>this should be removed</script><div>third</div></div>\
    \</body></html>"

renderWithoutScriptTag :: Text
renderWithoutScriptTag =
    let mArticle :: Maybe Taggy.Element
        mArticle =
            (fromText somehtmlSmall) ^? html .
            allAttributed (ix "id" . only "article")
        mArticleFiltered =
            fmap
                (\el ->
                      el ^.. to universe . traverse .
                      filtered (\n -> n ^. name /= "script"))
                mArticle
    in maybe "" (toText . concatMap Renderer.render) mArticleFiltered

main :: IO ()
main = print renderWithoutScriptTag

将此文件标记为可执行文件并运行它,您将看到:

代码语言:javascript
复制
➜  tmp  ./scraping-question.hs
"<div id=\"article\"><div>first</div><div>second</div><script>this should be removed</script><div>third</div></div><div>first</div><div>second</div><div>third</div>"

所以,这不管用。我想:

  • 有一个有效的解决方案
  • 理解工作解决方案

如果你能帮我认识到我的问题,我会特别感激的。谢谢!

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2016-10-05 05:22:28

问题的根源是universe,它将DOM树扁平化为列表。如果您再次查看输出,您将看到过滤工作正常,但是树结构丢失了--因此您得到了未修改的项目元素(所有的子元素都在其中),然后是子节点减去script元素。

一个Control.Lens.Plated组合器可以做您想做的事情,就是transform,它以自下而上的方式转换“树中的每个元素”:

代码语言:javascript
复制
transform :: Plated a => (a -> a) -> a -> a

特别是,您可以使用它递归地过滤子节点:

代码语言:javascript
复制
renderWithoutScriptTag :: Text
renderWithoutScriptTag =
    let mArticle :: Maybe Taggy.Element
        mArticle =
            (fromText somehtmlSmall) ^? html .
            allAttributed (ix "id" . only "article")
        mArticleFiltered =
            fmap
                (transform (children %~ filter (\n ->
                    n ^? element . name /= Just "script")))
                mArticle
    in maybe "" (toText . Renderer.render) mArticleFiltered
票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/39786824

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档