将多次抓取的 scrapeURL 结果连接到一个列表中
Concatenating scrapeURL results from multiples scrapings into one list
我正在使用 Haskell 的 Scalpel 库抓取 https://books.toscrape.com。到目前为止,这是我的代码:
import Text.HTML.Scalpel
import Data.List.Split (splitOn)
import Data.List (sortBy)
import Control.Monad (liftM2)
data Entry = Entry {entName :: String
, entPrice :: Float
, entRate :: Int
} deriving Eq
instance Show Entry where
show (Entry n p r) = "Name: " ++ n ++ "\nPrice: " ++ show p ++ "\nRating: " ++ show r ++ "/5\n"
entries :: Maybe [Entry]
entries = Just []
scrapePage :: Int -> IO ()
scrapePage num = do
items <- scrapeURL ("https://books.toscrape.com/catalogue/page-" ++ show num ++ ".html") allItems
let sortedItems = items >>= Just . sortBy (\(Entry _ a _) (Entry _ b _) -> compare a b)
>>= Just . filter (\(Entry _ _ r) -> r == 5)
maybe (return ()) (mapM_ print) sortedItems
allItems :: Scraper String [Entry]
allItems = chroots ("article" @: [hasClass "product_pod"]) $ do
p <- text $ "p" @: [hasClass "price_color"]
t <- attr "href" $ "a"
star <- attr "class" $ "p" @: [hasClass "star-rating"]
let fp = read $ flip (!!) 1 $ splitOn "£" p
let fStar = drop 12 star
return $ Entry t fp $ r fStar
where
r f = case f of
"One" -> 1
"Two" -> 2
"Three" -> 3
"Four" -> 4
"Five" -> 5
main :: IO ()
main = mapM_ scrapePage [1..10]
基本上,allItems
抓取每本书的标题、价格和评级,对价格进行一些格式化以获得浮动,然后 returns 将其作为一种类型 Entry
。 scrapePage
获取与结果页码相对应的数字,抓取该页面以获得 IO (Maybe [Entry])
,对其进行格式化 - 在本例中,过滤 5 星书籍并按价格排序 - 并打印每个条目。 main
在第 1 到 10 页执行 scrapePage
。
我 运行 遇到的问题是我的代码抓取、过滤和排序每个页面,而我想抓取所有页面 然后 过滤和排序.
两页(在 GHCi 中)有效的是:
i <- scrapeURL ("https://books.toscrape.com/catalogue/page-1.html") allItems
j <- scrapeURL ("https://books.toscrape.com/catalogue/page-2.html") allItems
liftM2 (++) i j
这个 returns 由第 1 页和第 2 页的结果组成的列表,然后我可以打印它,但我不知道如何为所有 50 个结果页实现此列表。帮助将不胜感激。
只是return条目列表,没有任何处理(或者你可以在这个阶段做过滤)
-- no error handling
scrapePage :: Int -> IO [Entry]
scrapePage num =
concat . maybeToList <$> scrapeURL ("https://books.toscrape.com/catalogue/page-" ++ show num ++ ".html") allItems
以后可以一起处理
process = filter (\e -> entRate e == 5) . sortOn entPrice
main = do
entries <- concat <$> mapM scrapePage [1 .. 10]
print $ process entries
此外,您可以轻松地使您的代码与 async
包
中的 mapConcurrently
并发
main = do
entries <- concat <$> mapConcurrently scrapePage [1 .. 20]
print $ process entries
我正在使用 Haskell 的 Scalpel 库抓取 https://books.toscrape.com。到目前为止,这是我的代码:
import Text.HTML.Scalpel
import Data.List.Split (splitOn)
import Data.List (sortBy)
import Control.Monad (liftM2)
data Entry = Entry {entName :: String
, entPrice :: Float
, entRate :: Int
} deriving Eq
instance Show Entry where
show (Entry n p r) = "Name: " ++ n ++ "\nPrice: " ++ show p ++ "\nRating: " ++ show r ++ "/5\n"
entries :: Maybe [Entry]
entries = Just []
scrapePage :: Int -> IO ()
scrapePage num = do
items <- scrapeURL ("https://books.toscrape.com/catalogue/page-" ++ show num ++ ".html") allItems
let sortedItems = items >>= Just . sortBy (\(Entry _ a _) (Entry _ b _) -> compare a b)
>>= Just . filter (\(Entry _ _ r) -> r == 5)
maybe (return ()) (mapM_ print) sortedItems
allItems :: Scraper String [Entry]
allItems = chroots ("article" @: [hasClass "product_pod"]) $ do
p <- text $ "p" @: [hasClass "price_color"]
t <- attr "href" $ "a"
star <- attr "class" $ "p" @: [hasClass "star-rating"]
let fp = read $ flip (!!) 1 $ splitOn "£" p
let fStar = drop 12 star
return $ Entry t fp $ r fStar
where
r f = case f of
"One" -> 1
"Two" -> 2
"Three" -> 3
"Four" -> 4
"Five" -> 5
main :: IO ()
main = mapM_ scrapePage [1..10]
基本上,allItems
抓取每本书的标题、价格和评级,对价格进行一些格式化以获得浮动,然后 returns 将其作为一种类型 Entry
。 scrapePage
获取与结果页码相对应的数字,抓取该页面以获得 IO (Maybe [Entry])
,对其进行格式化 - 在本例中,过滤 5 星书籍并按价格排序 - 并打印每个条目。 main
在第 1 到 10 页执行 scrapePage
。
我 运行 遇到的问题是我的代码抓取、过滤和排序每个页面,而我想抓取所有页面 然后 过滤和排序.
两页(在 GHCi 中)有效的是:
i <- scrapeURL ("https://books.toscrape.com/catalogue/page-1.html") allItems
j <- scrapeURL ("https://books.toscrape.com/catalogue/page-2.html") allItems
liftM2 (++) i j
这个 returns 由第 1 页和第 2 页的结果组成的列表,然后我可以打印它,但我不知道如何为所有 50 个结果页实现此列表。帮助将不胜感激。
只是return条目列表,没有任何处理(或者你可以在这个阶段做过滤)
-- no error handling
scrapePage :: Int -> IO [Entry]
scrapePage num =
concat . maybeToList <$> scrapeURL ("https://books.toscrape.com/catalogue/page-" ++ show num ++ ".html") allItems
以后可以一起处理
process = filter (\e -> entRate e == 5) . sortOn entPrice
main = do
entries <- concat <$> mapM scrapePage [1 .. 10]
print $ process entries
此外,您可以轻松地使您的代码与 async
包
mapConcurrently
并发
main = do
entries <- concat <$> mapConcurrently scrapePage [1 .. 20]
print $ process entries