首页 > 解决方案 > 使用 Haskell 进行 Web 抓取循环

问题描述

我想学习 Haskell,并且我有另一个小项目(目前在 Elixir 中),我想将其移植为练习。这是一个简单的网络抓取工具,可以抓取 url 列表。

想象一下,有一个邮政编码列表,大约有 2500 个项目。对于每个条目,应抓取一个网页,格式为http://www.acme.org/zip-info?zip={ZIP}. 我设法编写了使用 Scalpel 抓取单个网页的代码。

但是我将如何去刮掉 2500 件物品呢?在 Elixir 中,我映射了邮政编码列表,在每个页面请求之后,都会有 1 秒的短暂睡眠,以减轻目标网站的压力。对我来说,尽可能快地抓取网站并不重要。

我将如何在 Haskell 中执行此操作?我读到了,threadSleep但是我如何结合使用列表来遍历和主要方法,因为睡眠是副作用。

感谢您的见解!

标签: haskell

解决方案


大概你已经有一个功能,如:

scrapeZip :: Zip -> IO ZipResult

然后您可以编写一个函数traverse来获取一个返回 zip 结果列表的 IO 操作:

scrapeZips :: [Zip] -> IO [ZipResult]
scrapeZips zipCodes = traverse scrapeZip zipCodes

但是您想添加延迟,可以使用threadDelay(您可以从 导入它Control.Concurrent)来完成:

scrapeZipDelay :: Zip -> IO ZipResult
scrapeZipDelay zip = do
  x <- scrapeZip zip
  threadDelay 1000000 -- one second in microseconds
  return x

然后你可以使用scrapeZipDelaytraverse

scrapeZipsDelay :: [Zip] -> IO [ZipResult]
scrapeZipsDelay zipCodes = traverse scrapeZipDelay zipCodes

除了定义一个全新的scrapeZipDelay函数,您还可以使用<*运算符编写一个非常小的版本:

scrapeZipsDelay :: [Zip] -> IO [ZipResult]
scrapeZipsDelay zipCodes = 
  traverse (\zip -> scrapeZip zip <* threadDelay 1000000) zipCodes

推荐阅读