packages feed

reddit-scrape-0.0.0: src/ScrapeReddit.hs

module ScrapeReddit where

import Network.HTTP.Client (Manager)
import RIO
import qualified RIO.Text as Text
import RIO.Time (UTCTime, defaultTimeLocale, iso8601DateFormat, parseTimeM)
import Text.HTML.Scalpel
  ( Config (..),
    Scraper,
    anySelector,
    attr,
    chroot,
    chroots,
    defaultDecoder,
    hasClass,
    scrapeURLWithConfig,
    text,
    (@:),
  )

data Link = Link
  { title :: Text,
    href :: String,
    currentScore :: Maybe Int,
    comments :: Maybe Int,
    date :: Maybe UTCTime
  }
  deriving (Eq, Show, Generic)

scrapeSubReddit :: Manager -> String -> IO (Maybe [Link])
scrapeSubReddit manager subReddit =
  scrapeURLWithConfig
    (Config {decoder = defaultDecoder, manager = Just manager})
    (mconcat ["https://old.reddit.com/r/", subReddit, "/"])
    links

links :: Scraper Text [Link]
links = chroots ("div" @: [hasClass "thing", hasClass "link"]) link'

link' :: Scraper Text Link
link' = do
  title <- text $ "a" @: [hasClass "title"]
  href <- Text.unpack <$> attr "href" ("a" @: [hasClass "title"])
  currentScore <- (Text.unpack >>> readMaybe) <$> attr "title" ("div" @: [hasClass "score"])
  comments <- chroot ("a" @: [hasClass "comments"]) commentNumber
  date <- chroot ("time" @: [hasClass "live-timestamp"]) dateTimeFromTime
  pure $ Link {title, href, currentScore, comments, date}

commentNumber :: Scraper Text (Maybe Int)
commentNumber = do
  commentLinkText <- Text.unpack <$> text anySelector
  case words commentLinkText of
    [numberText, _comments] -> pure $ readMaybe numberText
    _anythingElse -> pure Nothing

dateTimeFromTime :: Scraper Text (Maybe UTCTime)
dateTimeFromTime = do
  timeString <- Text.unpack <$> attr "datetime" anySelector
  pure $ parseTimeM True defaultTimeLocale dateFormat timeString

dateFormat :: String
dateFormat = iso8601DateFormat $ Just "%H:%M:%S+00:00"