在 Haskell 中,wreq
库是一个非常方便的 HTTP 请求库,适合用来编写爬虫程序。你可以使用它来发送 GET 或 POST 请求,抓取网页内容,处理响应数据等。我们可以结合 HTTP 代理配置来实现网络请求。
下面我将展示如何在 Haskell 中使用 wreq
库配合 HTTP 请求编写一个爬虫程序。

1、安装 wreq
和 http-client
库
首先,确保你已安装 wreq
库。你可以通过 cabal
安装它。wreq
依赖于 http-client
和 http-client-tls
库,因此需要一起安装。
bash
cabal update
cabal install wreq
2、、导入必要模块
在 Haskell 中,我们需要导入以下模块:
haskell
import Control.Lens
import Network.Wreq
import qualified Data.ByteString.Lazy.Char8 as L8
import Network.HTTP.Client (newManager, defaultManagerSettings)
import Network.Wreq.Session (withSession)
import Data.Aeson
Control.Lens
: 用于从 HTTP 请求和响应中提取数据。Network.Wreq
: 提供了发送 HTTP 请求的功能。Data.ByteString.Lazy.Char8
: 用于处理响应的字节流。Network.HTTP.Client
: 负责创建 HTTP 客户端和配置代理。Network.Wreq.Session
: 用于创建带有会话状态的请求,适合需要持续会话的爬虫任务。
3、设置 HTTP 代理
假设你需要使用 HTTP 代理服务器来发送请求,首先需要配置代理:
haskell
import Network.Wreq
import Network.HTTP.Client (newManager, defaultManagerSettings, managerModifyRequest)
import Network.HTTP.Client.TLS (tlsManagerSettings)
-- 设置 HTTP 代理
setupProxy :: IO Manager
setupProxy = do
manager <- newManager tlsManagerSettings
return $ managerModifyRequest manager $ \req -> do
let proxy = "http://localhost:8080" -- 代理地址
setRequestProxy proxy req
在上面的代码中,我们创建了一个 setupProxy
函数,它将设置代理服务器地址。你可以根据实际需要修改代理的 URL。
4、发送 HTTP 请求并获取网页内容
我们将通过 wreq
库发送 HTTP 请求,抓取网页内容,并使用 Lens
提取响应体中的内容。以下是一个抓取网页内容并打印响应的简单例子:
haskell
import Network.Wreq
import Control.Lens
import Data.ByteString.Lazy.Char8 as L8
-- 使用代理发送 GET 请求并打印网页内容
fetchPage :: IO ()
fetchPage = do
manager <- setupProxy
let opts = defaults & manager .~ Just manager
response <- getWith opts "https://www.example.com" -- 目标网页
L8.putStrLn (response ^. responseBody) -- 打印网页的响应体
在这个例子中,getWith
函数通过代理发送 GET 请求,并获取目标网页的响应内容。responseBody
是通过 Lens 提取响应体内容,我们将其打印到控制台。
5、处理 JSON 响应
如果你抓取的是 JSON 数据,可以使用 aeson
库来解析 JSON 响应。wreq
与 aeson
库结合得很好,允许你直接将 JSON 响应转化为 Haskell 数据类型。
假设我们从 API 获取 JSON 数据,并解析它:
haskell
import Network.Wreq
import Control.Lens
import Data.Aeson
import Data.Maybe (fromJust)
-- 假设我们有一个 JSON 响应,格式为:{"id": 1, "name": "example"}
data Response = Response {
id :: Int,
name :: String
} deriving (Show)
instance FromJSON Response where
parseJSON = withObject "Response" $ \v -> Response
<$> v .: "id"
<*> v .: "name"
-- 使用代理发送 GET 请求并解析 JSON 响应
fetchJson :: IO ()
fetchJson = do
manager <- setupProxy
let opts = defaults & manager .~ Just manager
response <- getWith opts "https://jsonplaceholder.typicode.com/users/1"
let jsonResponse = response ^. responseBody
let parsedData = decode jsonResponse :: Maybe Response
case parsedData of
Just data' -> print data'
Nothing -> putStrLn "Failed to parse JSON"
在这个例子中,Response
是我们定义的一个数据类型,用来表示 JSON 响应的数据结构。FromJSON
实例使得我们能够从 JSON 数据中提取字段。decode
函数将 JSON 响应解析为 Response
类型。
6、完整示例:通过代理抓取网页并解析数据
最后,以下是一个完整的示例,展示如何使用 wreq
配合代理抓取网页,并解析其 JSON 数据:
haskell
import Network.Wreq
import Control.Lens
import Network.HTTP.Client (newManager, defaultManagerSettings, managerModifyRequest)
import Network.HTTP.Client.TLS (tlsManagerSettings)
import Data.Aeson
import qualified Data.ByteString.Lazy.Char8 as L8
import Data.Maybe (fromJust)
-- 设置代理
setupProxy :: IO Manager
setupProxy = do
manager <- newManager tlsManagerSettings
return $ managerModifyRequest manager $ \req -> do
let proxy = "http://localhost:8080" -- 设置代理地址
setRequestProxy proxy req
-- 数据类型用于解析 JSON
data Response = Response {
id :: Int,
name :: String
} deriving (Show)
instance FromJSON Response where
parseJSON = withObject "Response" $ \v -> Response
<$> v .: "id"
<*> v .: "name"
-- 使用代理发送 GET 请求并解析 JSON
fetchJson :: IO ()
fetchJson = do
manager <- setupProxy
let opts = defaults & manager .~ Just manager
response <- getWith opts "https://jsonplaceholder.typicode.com/users/1"
-- 解析 JSON 响应
let jsonResponse = response ^. responseBody
let parsedData = decode jsonResponse :: Maybe Response
case parsedData of
Just data' -> print data'
Nothing -> putStrLn "Failed to parse JSON"
main :: IO ()
main = fetchJson
7、总结
在这个 Haskell 示例中,我们展示了如何使用 wreq
库配合 HTTP 代理进行网络请求,并抓取网页内容或 API 返回的 JSON 数据。主要步骤包括:
- 配置 HTTP 代理。
- 使用
wreq
发送 HTTP 请求。 - 使用
Lens
提取响应体内容。 - 使用
Aeson
库解析 JSON 数据。
我们可以根据需要扩展这个爬虫程序,添加更多的请求头、POST 请求支持、错误处理等。