首页 > 解决方案 > Haskell webdriver:如何获取元素内容?

问题描述

问题:

我正在尝试使用 Haskell 和 webdriver 包制作一个网络爬虫,我正在尝试获取 html 元素的属性和内部 html,我尝试使用函数 show,但它只显示一个 UUID,因为 Element 是一种新型文本,它是 UUID,所以我不知道如何获取元素的内容。

依赖项:

dependencies:
- base >= 4.7 && < 5
- http-client
- http-client-tls
- bytestring
- webdriver
- text

代码:

{-# LANGUAGE OverloadedStrings #-}
module Main (main) where
import Test.WebDriver
import System.IO
import Control.Monad (mapM, mapM_)
import Control.Monad.IO.Class (liftIO)
import qualified Data.Text as Text
import Control.Concurrent (threadDelay)
newtype Attr = {
    attrName    :: String
   ,attrContent :: String
   } deriving (Show)
firefoxConfig :: WDConfig
firefoxConfig = hilf $ useBrowser firefox defaultConfig
  where
    hilf m = m { wdHTTPRetryCount = 100 } {-, wdCapabilities = defaultCaps {
      additionalCaps = [ ("moz:firefoxOptions", object
        [ ("args", Array (fromList [String "--headless"])) ]
            )]  }} -}
main :: IO ()
main = runSession firefoxConfig $
  openPage "https://www.youtube.com/c/SomeChannel/videos" >>
  liftIO (threadDelay $ 10 * 1000000) >>
  findElems (ByXPath "//*[@id=\"video-title\"]") >>= \user_data ->
  liftIO (mapM_ (putStrLn . show . getAttrs) user_data)
  >> closeSession
  where getAttrs :: Element -> [Attr]
        getAttrs elment = ??????????? -- I need get the Attributes of the element

标签: haskellwebdriver

解决方案


为了获取内容,我认为您想要getText,并且为了获取单个属性attr,两者都来自Test.WebDriver.Commands. 后者有 type (HasCallStack, WebDriver wd) => Element -> Text -> wd (Maybe Text)。它采用元素 ID 和属性名称并获取Just属性值,或者在属性不存在Nothing的情况下获取。null

为了列出所有属性,看起来 Selenium 没有定义 API,所以我认为你需要使用executeJS,像这样(未经测试):

getAttributes element = executeJS [element]
  "var result = {};\n\
  \var attrs = arguments[0].attributes;\n\
  \for (var i = 0; i < attrs.length; ++i)\n\
  \  result[attrs[i].name] = attrs[i].value;\n\
  \return result;"

您也无法使用纯类型Element -> [Attr],您需要保留在 WebDriverWD上下文中。

如果缺少命令,您还可以始终使用低级函数(如doElemCommandfrom Test.WebDriver.Commands.Internal)直接调用它,使用 Selenium 命令 URL:

getAttribute :: (HasCallStack, WebDriver wd) => Text -> Element -> wd Text
getAttribute attribute element
  = doElemCommand methodGet element
    ("/attribute/" <> urlEncode attribute)
    Null

但是,如果可能,最好避免这种情况。


推荐阅读