使用cURL爬取http站点返回403错误,https站点正常的原因咨询
问题分析与解决方案
HTTP请求返回403的核心原因
- 站点强制HTTPS访问:很多网站已配置为仅接受HTTPS请求,直接访问HTTP协议地址会被服务器直接拦截返回403,即便开启了
CURLOPT_FOLLOWLOCATION,部分服务器也不会提供HTTP到HTTPS的跳转逻辑。 - HTTP请求头部信息不全:当前代码仅设置了
User-Agent,但部分站点对HTTP请求的头部校验更严格,缺失Accept、Accept-Language等常规浏览器头部会被判定为非合法请求。 - 反爬策略针对性拦截:如今正常用户请求基本都使用HTTPS,HTTP请求更容易被反爬系统标记为爬虫,直接触发403拦截。
代码修复与优化建议
1. 自动转换HTTP为HTTPS优先请求
直接将HTTP URL替换为HTTPS,避免触发站点的HTTP拦截规则:
foreach($urls as $url){ // 自动替换http协议为https $url = preg_replace('/^http:/', 'https:', $url); // 后续curl逻辑保持不变 }
2. 补充完整的浏览器请求头部
模拟真实用户的请求头,降低被反爬系统识别的概率:
$user_agent = "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.131 Safari/537.36"; // 补充常见浏览器请求头 $headers = [ 'Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8', 'Accept-Language: zh-CN,zh;q=0.8,en;q=0.6', 'Connection: keep-alive', 'Upgrade-Insecure-Requests: 1' ]; $ch = curl_init(); curl_setopt($ch, CURLOPT_USERAGENT, $user_agent); curl_setopt($ch, CURLOPT_HTTPHEADER, $headers); // 注入请求头 // 其他curl配置保持不变
3. 修复循环逻辑的核心BUG
当前代码在循环处理多URL时,会覆盖$html和$ch变量,最终仅处理最后一个URL的结果。需将请求结果的判断与解析逻辑移入循环内部:
foreach($urls as $url){ $url = preg_replace('/^http:/', 'https:', $url); $user_agent = "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.131 Safari/537.36"; $headers = [ 'Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8', 'Accept-Language: zh-CN,zh;q=0.8,en;q=0.6', 'Connection: keep-alive', 'Upgrade-Insecure-Requests: 1' ]; $ch = curl_init(); curl_setopt($ch, CURLOPT_USERAGENT, $user_agent); curl_setopt($ch, CURLOPT_HTTPHEADER, $headers); curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); curl_setopt($ch, CURLOPT_VERBOSE, true); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); curl_setopt($ch, CURLOPT_URL,$url); curl_setopt($ch, CURLOPT_FOLLOWLOCATION, TRUE); $html = curl_exec($ch); if (!curl_errno($ch)) { $statusCode = curl_getinfo($ch, CURLINFO_HTTP_CODE); if($statusCode == 200){ @$DOM = new DOMDocument; @$DOM->loadHTML('<?xml encoding="UTF-8"?>' . $html); $h1Nodes = $DOM->getElementsByTagName('h1'); // 避免无H1标签导致报错 if ($h1Nodes->length > 0) { array_push($final, $h1Nodes->item(0)->textContent); } else { array_push($final, '该页面无H1标签'); } } else { array_push($final, "请求失败,状态码:{$statusCode}"); } } else { array_push($final, "CURL错误:" . curl_error($ch)); } curl_close($ch); // 及时释放curl资源 }
4. JS代码的细节修复
异步函数末尾缺少闭合括号,且遍历数组时应取元素而非索引:
(async()=>{ let response = await webscrape(urls); if(response[0] == '['){ const arr = JSON.parse(response); for(var x in arr){ fetched_data.push(arr[x]); // 修正为取数组元素,而非索引值 } } })(); // 补充闭合括号
额外注意事项
- 关闭
CURLOPT_SSL_VERIFYPEER存在安全风险,生产环境建议保留该验证,或指定合法的CA证书路径。 - 若部分站点仍返回403,可尝试添加
Cookie头部模拟登录状态,或通过CURLOPT_COOKIEJAR和CURLOPT_COOKIEFILE维持会话。
内容的提问来源于stack exchange,提问作者user21500731
相关产品推荐
相关产品推荐

