Разбор HTML в Haskell
Я пытаюсь разобрать a
ссылки из основной части (<article>
) из сообщения в блоге. Я адаптировал то, что нашел на FPComplete, но ничего не распечатано. (Насколько я понимаю, код не работает, поскольку он выполняется в онлайн-среде IDE и с целью Bing также не создает ссылок.)
В GHCI я могу смоделировать первую строку parseAF, и это дает мне большую запись, которую я считаю правильной. Но cursor $// findNodes &| extractData
возвращается []
Я пробовал регулярные выражения, но это не было приятно, пытаясь найти такой длинный кусок текста.
Кто-нибудь может помочь?
{-# LANGUAGE OverloadedStrings #-}
module HtmlParser where
import Network.HTTP.Conduit (simpleHttp)
import Prelude hiding (concat, putStrLn)
import Data.Text (concat)
import Data.Text.IO (putStrLn)
import Text.HTML.DOM (parseLBS)
import Text.XML.Cursor (Cursor, attribute, element, fromDocument, ($//), (&//), (&/), (&|))
-- The URL we're going to search
url = "http://www.amsterdamfoodie.nl/2015/wine-beer-food-restaurants-troost/"
-- The data we're going to search for
findNodes :: Cursor -> [Cursor]
findNodes = element "article" &/ element "a"
-- Extract the data from each node in turn
extractData = concat . attribute "href"
cursorFor :: String -> IO Cursor
cursorFor u = do
page <- simpleHttp u
return $ fromDocument $ parseLBS page
-- Process the list of data elements
processData = mapM_ putStrLn
-- main = do
parseAF :: IO ()
parseAF = do
cursor <- cursorFor url
processData $ cursor $// findNodes &| extractData
ОБНОВЛЕНИЕ После дальнейшего изучения кажется, что проблема заключается в element "article"
, Если я заменю это на element "p"
, что нормально в этом случае как единственный p
с в article
в любом случае, тогда я получаю свои ссылки. Довольно странно....!!
2 ответа
Я думаю, что вы можете сделать это очень легко читаемым способом с помощью HXT, составив фильтры:
{-# LANGUAGE Arrows #-}
import Text.XML.HXT.Core
import Text.XML.HXT.Curl
import Text.XML.HXT.TagSoup
links url = extract (readDocument
[ withParseHTML yes
, withTagSoup
, withCurl []
, withWarnings no
] url)
extract doc = runX $ doc >>> xmlFilter "article" >>> xmlFilter "a" >>> toHref
xmlFilter name = deep (hasName name)
toHref = proc el -> do
link <- getAttrValue "href" -< el
returnA -< link
Вы можете назвать это следующим образом:
links "http://www.amsterdamfoodie.nl/2015/wine-beer-food-restaurants-troost/"
ОК, проблема в том, что &/
только смотрит на непосредственных детей, тогда как &//
пройдут через всех потомков
findNodes = element "article" &// element "a"