什么场景应该用Invoke-WebRequest而不是curl?

选Invoke-WebRequest的三个明确信号:Windows Server常驻脚本、需要与PowerShell对象体系集成、要用Windows凭据。其他场景curl通常更省心。

三大差异对比:

维度Invoke-WebRequestcurl建议选择
返回类型强类型PowerShell对象(Headers、Content、StatusCode等属性)文本流需要后续用PS对象处理,选前者
参数命名完整单词加连字符(-Uri-Method短选项(-X-H团队协作、脚本可读性,选前者
代理配置-Proxy-ProxyCredential-x--proxy-user差别不大
依赖Windows内置Win 10 1803之后内置,早期版本要额外装老Windows优选前者
编码处理PowerShell 5.1易乱码,7+改善一致中文站点PS 5.1要额外配

Invoke-WebRequest简写为iwr,与它的兄弟Invoke-RestMethod简写为irm。区别在于:iwr返回完整响应对象,包含headers、cookies、状态码;irm自动解析JSON/XML为对象,只返回body。抓取和调试用iwr,纯API消费用irm

基本请求怎么发?GET/POST与请求头如何设置?

最短的GET请求一行搞定,长期脚本要显式配好超时和错误处理。

GET最简形式:

$r = Invoke-WebRequest -Uri "https://example.com/api/list"
$r.StatusCode          # 状态码
$r.Content             # 响应体(字符串)
$r.Headers             # 响应头

带自定义header的GET:

$headers = @{
    "User-Agent"    = "Mozilla/5.0 (Windows NT 10.0)"
    "Accept"        = "application/json"
    "Authorization" = "Bearer $token"
}
$r = Invoke-WebRequest -Uri $url -Headers $headers -TimeoutSec 30

POST三种body格式:

# 1. Form 表单
$body = @{ keyword = "招投标"; page = 1 }
Invoke-WebRequest -Uri $url -Method Post -Body $body

# 2. JSON
$body = @{ query = "舆情"; limit = 100 } | ConvertTo-Json
Invoke-WebRequest -Uri $url -Method Post -Body $body `
    -ContentType "application/json; charset=utf-8"

# 3. 文件上传(multipart/form-data)
$form = @{
    file = Get-Item "./data.csv"
    name = "招标数据"
}
Invoke-WebRequest -Uri $url -Method Post -Form $form

超时相关三个参数:

参数作用默认值建议
-TimeoutSec整个请求超时100秒生产环境显式设10-30秒
-MaximumRedirection允许重定向次数5抓取静态页可设0
-DisableKeepAlive关闭长连接默认启用单次请求可开,批量抓取不开

如何配置代理和身份认证?

代理配置有三种方式,覆盖大多数场景。

方式一:命令行参数

$proxyUrl = "http://proxy.example.com:8080"
$user = "your_user"
$pass = ConvertTo-SecureString "your_pass" -AsPlainText -Force
$cred = New-Object System.Management.Automation.PSCredential($user, $pass)

Invoke-WebRequest -Uri $url `
    -Proxy $proxyUrl `
    -ProxyCredential $cred

方式二:环境变量

$env:HTTP_PROXY  = "http://user:pass@proxy.example.com:8080"
$env:HTTPS_PROXY = "http://user:pass@proxy.example.com:8080"
$env:NO_PROXY    = "localhost,127.0.0.1,*.internal"

Invoke-WebRequest -Uri $url  # 自动生效

方式三:系统代理

Invoke-WebRequest -Uri $url -UseDefaultCredentials
# 使用当前Windows登录凭据+IE代理设置

三种方式对比:

方式适用场景注意事项
命令行参数单脚本、临时任务密码明文写在脚本里要脱敏
环境变量CI/CD、多脚本共用Windows服务重启会清空
系统代理Windows域内运维仅内网、账密不透明

PowerShell 5.1和7+在代理支持上有差异:

  • 5.1不支持SOCKS5,只支持HTTP/HTTPS代理
  • 5.1不支持-SkipHttpErrorCheck,4xx/5xx会抛异常
  • 7+对HTTP/2支持完整,5.1只走HTTP/1.1

跨境物流信息查询这类需要走境外代理的场景,7+的稳定性和错误处理明显好于5.1,长期任务建议升级。

会话管理Cookie保持怎么用?

跨请求维持登录状态用-SessionVariable创建会话对象,后续请求带-WebSession复用。

登录+抓取的完整流程:

# 1. 登录,创建会话
$login = Invoke-WebRequest -Uri "https://example.com/login" `
    -Method Post `
    -Body @{ username = "u"; password = "p" } `
    -SessionVariable "session"

# 2. 用同一会话抓取
$page = Invoke-WebRequest -Uri "https://example.com/dashboard" `
    -WebSession $session

# 3. 会话内的Cookie
$session.Cookies.GetCookies("https://example.com") | Format-Table Name, Value

手动读写Cookie:

# 手动添加
$cookie = New-Object System.Net.Cookie
$cookie.Name   = "sessionid"
$cookie.Value  = "abc123"
$cookie.Domain = "example.com"
$session.Cookies.Add($cookie)

# 序列化保存(长期任务重启后恢复)
$session.Cookies.GetCookies("https://example.com") |
    Select-Object Name, Value, Domain, Path, Expires |
    ConvertTo-Json | Set-Content "cookies.json"

会话管理常见坑:

  • 域名不匹配:登录返回的Cookie域名为.example.com,抓取子域api.example.com时若显式指定domain=example.com会失效
  • Path不覆盖:登录返回Path=/user,抓取/api时Cookie不发送
  • HttpOnly不影响PS:Invoke-WebRequest能读到所有Cookie,包括HttpOnly
  • Secure Cookie:只在HTTPS请求时发送,混用HTTP/HTTPS要注意

编码乱码、字符集怎么处理?

PowerShell 5.1的中文乱码是最常见的教程盲点。原因是5.1默认按ISO-8859-1解析Content,中文站点几乎必乱。

三种解决方案:

方案一:手动重新解码

$r = Invoke-WebRequest -Uri $url
$bytes = [System.Text.Encoding]::GetEncoding("ISO-8859-1").GetBytes($r.Content)
$content = [System.Text.Encoding]::UTF8.GetString($bytes)

方案二:改用Invoke-RestMethod并指定字符集

$r = Invoke-RestMethod -Uri $url -ContentType "text/html; charset=utf-8"

方案三:升级到PowerShell 7+

7+默认按响应头Content-Typecharset参数解析,行为符合直觉。

编码问题的自检脚本:

# 输出响应真实字符集
$r = Invoke-WebRequest -Uri $url
$r.Headers["Content-Type"]
$r.BaseResponse.CharacterSet  # PowerShell 7+ 可用

写入文件时的编码坑同样常见:

# ❌ 5.1 默认写入UTF-16 with BOM
$content | Out-File "data.html"

# ✅ 显式指定UTF-8无BOM
[System.IO.File]::WriteAllText("data.html", $content, 
    [System.Text.UTF8Encoding]::new($false))

TLS版本、证书与安全设置如何配置?

PowerShell 5.1默认不启用TLS 1.2,抓取要求TLS 1.2+的目标站会直接握手失败。

启用TLS 1.2的三种粒度:

# 全会话级(脚本开头一次)
[Net.ServicePointManager]::SecurityProtocol = 
    [Net.SecurityProtocolType]::Tls12 -bor [Net.SecurityProtocolType]::Tls13

# 系统级(管理员权限,注册表持久)
Set-ItemProperty -Path 'HKLM:\SOFTWARE\Microsoft\.NETFramework\v4.0.30319' `
    -Name 'SchUseStrongCrypto' -Value 1 -Type DWord

# PowerShell 7+ 自动支持 TLS 1.3

证书相关配置:

# 跳过证书校验(仅调试用,生产禁用)
# PowerShell 7+
Invoke-WebRequest -Uri $url -SkipCertificateCheck

# PowerShell 5.1(全局跳过,副作用大)
[System.Net.ServicePointManager]::ServerCertificateValidationCallback = { $true }

常见TLS错误对照:

错误根因修复
The request was aborted: Could not create SSL/TLS secure channel未启用TLS 1.2Tls12设置
The remote certificate is invalid according to the validation procedure系统根证书过期certutil -generateSSTFromWU更新
The underlying connection was closed目标要求TLS 1.3或特定加密套件升级到PS 7+

长期任务下的错误重试与日志怎么做?

生产环境跑Invoke-WebRequest的三个必备能力:错误分类、指数退避重试、结构化日志。

带指数退避的通用请求函数:

function Invoke-RetryRequest {
    param(
        [string]$Uri,
        [string]$Method = "GET",
        [hashtable]$Headers = @{},
        [int]$MaxRetries = 3,
        [int]$InitialDelay = 1000
    )
    
    for ($i = 0; $i -lt $MaxRetries; $i++) {
        try {
            $r = Invoke-WebRequest -Uri $Uri -Method $Method `
                -Headers $Headers -TimeoutSec 20 -ErrorAction Stop
            return $r
        }
        catch {
            $status = $_.Exception.Response.StatusCode.value__
            
            # 分类:可重试 vs 立即失败
            if ($status -in 400,401,403,404) {
                Write-Warning "不重试的错误: $status"
                throw
            }
            
            $delay = $InitialDelay * [Math]::Pow(2, $i)
            Write-Warning "第 $($i+1) 次失败: $status,等待 ${delay}ms 重试"
            Start-Sleep -Milliseconds $delay
        }
    }
    throw "达到最大重试次数"
}

错误分类原则:

状态码分类处理
200-299成功正常处理响应
300-399重定向Invoke-WebRequest默认跟随5次
400/401/403/404客户端错误立即失败,不重试
407代理鉴权失败立即失败,检查代理配置
429访问频率限制Retry-After头,按值等待重试
500/502/503/504服务端错误指数退避重试
网络异常连接层指数退避重试

结构化日志便于后续采集到日志系统:

function Write-StructuredLog {
    param($Level, $Message, $Extra = @{})
    $log = @{
        timestamp = (Get-Date).ToString("o")
        level     = $Level
        message   = $Message
    } + $Extra
    $log | ConvertTo-Json -Compress | Add-Content "task.log"
}

Write-StructuredLog -Level "INFO" -Message "请求完成" -Extra @{
    url    = $url
    status = $r.StatusCode
    ms     = $sw.ElapsedMilliseconds
}

舆情监测和招投标数据这类需要日跑几万次请求的任务,务必把三样都上齐:分类的错误处理、指数退避、结构化日志。缺任何一项,故障复盘就会很痛苦。

FAQ

Q:Invoke-WebRequest和Invoke-RestMethod到底该用哪个?

抓取网页、需要拿到状态码/headers/原始HTML就用Invoke-WebRequest;纯粹调用返回JSON/XML的REST API、想直接拿到解析后的对象就用Invoke-RestMethod。两者底层实现完全相同,只是返回类型不一样。生产环境把两者结合用最常见:先用iwr做健康检查看状态码,再用irm消费API。

Q:为什么代理配了但请求不走代理?

四种典型原因:一是环境变量在当前会话没生效,$env:HTTP_PROXY需要重启会话或用Set-Item Env:重新赋值;二是目标URL在$env:NO_PROXY匹配范围内;三是使用了-UseDefaultCredentials,此时会走系统IE代理设置而非命令行参数;四是Invoke-WebRequest内部走了.NET WebRequest的默认代理策略,可以显式-Proxy $null覆盖。用FiddlerWireshark抓包能直接确认。

Q:PowerShell 5.1能不能用SOCKS5代理?

内置不支持。5.1的Invoke-WebRequest底层是HttpWebRequest,只支持HTTP/HTTPS代理协议。要用SOCKS5有三条路:一是升级到PowerShell 7+,7+原生支持;二是本地起一个HTTP-to-SOCKS转换器如Privoxy,PowerShell走HTTP代理连到本地转换器;三是用.NET CoreSocketsHttpHandler手写,工作量大。多数团队直接选升级7+。

Q:抓取的HTML能不能用CSS选择器或XPath解析?

Invoke-WebRequest返回的$r.ParsedHtml在Windows PowerShell 5.1上是HTMLDocument对象,可以用getElementsByTagName等原生方法,但速度慢且依赖IE引擎。生产环境更推荐用HtmlAgilityPack——它是.NET NuGet包,或者用AngleSharp。PowerShell 7+已经移除ParsedHtml属性,必须用第三方库。

Q:请求量大的时候有没有性能瓶颈?

三个典型瓶颈:一是ServicePoint连接数限制,[System.Net.ServicePointManager]::DefaultConnectionLimit默认2,改成100+;二是DNS缓存,同一域名解析会缓存,长时间脚本要定期清理;三是单线程模型,PowerShell本身是同步阻塞。要打真正的并发要么用Start-Job做进程隔离但开销大,要么用Runspaces的RunspacePool更轻量,要么直接切到PowerShell 7的ForEach-Object -Parallel

Q:怎么调试请求实际发出的完整内容?

三个方法叠加用最清楚:一是本地起Fiddlermitmproxy,PowerShell配代理到127.0.0.1:8080,能看到完整request/response;二是$r.BaseResponse.ResponseUri看重定向后的最终URL;三是设置$VerbosePreference = "Continue"后加-Verbose参数,PowerShell会打印内部诊断信息。

青果网络代理IP - CTA Banner
点赞(69)
数据采集采购实录:某电商日均千万级请求实战
并发采集 合规采集 代理IP异常 IP代理
2026-08-21

某跨境电商从日均百万级采集扩容到千万级,踩过的坑集中在四个工程维度:IP调度架构、故障隔离机制、成本模型设计、合规治理。堆IP解决不了规模化问题,系统性的架构决策才是关键。

PHP curl GET请求:数据采集代码实例
数据采集 HTTP代理 企业级代理 代理IP池
2026-08-20

PHP curl GET 采集的稳定性不在"如何发出请求",而在 headers 组合、代理接入、错误处理、编码兼容、UA 轮换五个环节。本文给出从基础请求到反限制采集的完整代码路径。

数据采集实战复盘:企业级避坑清单与5类失败根因
数据采集 企业级代理 代理IP池 动态代理
2026-08-19

企业级数据采集的失败很少来自单一原因,多是网络层、协议层、风控层、数据层、合规层的问题叠加。本篇按5层给出可对照的避坑清单,并附3个脱敏案例说明"看似同一个问题、根因不同"的诊断路径。

2026HTTP代理服务商9家对比分析:全维度性能与多场景应用综合对比
HTTP代理 代理服务商 IP代理 IP池
2026-08-18

HTTP代理选型的分水岭不是"谁 IP 池大、谁可用率高",而是"产品类型、协议边界、计费方式和业务场景是否吻合"。青果网络以短效/隧道/独享/长效四类产品覆盖 APP 大数据分析、网站采集器、拓客数据三类主流场景;极安代理适合预算敏感的中小团队;被点名的另外 7 家 HTTP 代理各有差异化落点,其中协议边界差异会直接影响选型可行性。

微信公众账号

微信扫一扫加关注

发表
评论
返回
顶部