使用libcurl抓取网站内置搜索栏结果遇405错误求助
解决Laravel Livewire动态搜索的抓取问题(405 Method Not Allowed)
问题核心
你遇到的wire:model.debounce.600ms是Laravel Livewire的专属属性,这类搜索依赖Livewire的AJAX异步请求实现,并非常规的URL参数式GET请求。直接用普通GET/POST请求会触发405错误,本质是请求端点、格式与网站预期不匹配。
第一步:抓包分析真实请求
打开浏览器开发者工具(F12)切换到Network标签,输入搜索关键词,定位Livewire的请求,重点记录:
- 请求方法:几乎都是POST
- 请求URL:通常为
/livewire/message/[组件名称](比如/livewire/message/search-bar) - 请求Headers:必须包含
X-Livewire、X-CSRF-TOKEN(网站启用CSRF验证时)、Cookie(需会话验证时),Content-Type多为application/json或multipart/form-data - 请求体:结构化数据(多为JSON),包含组件ID、搜索关键词、触发动作(如
action: "search")等字段
第二步:修正libcurl请求代码
以下是适配Livewire请求的libcurl示例,核心是完全匹配抓包到的请求规则:
#include <curl/curl.h> #include <vector> #include <string> #include <nlohmann/json.hpp> // 需引入nlohmann/json库解析JSON using json = nlohmann::json; // 回调函数:保存请求返回数据 size_t WriteCallback(void* contents, size_t size, size_t nmemb, std::string* s) { size_t newLength = size * nmemb; try { s->append((char*)contents, newLength); } catch(std::bad_alloc &e) { return 0; } return newLength; } std::vector<std::string> getSearchResults(const std::string& keyword) { std::vector<std::string> resultUrls; CURL* curl = curl_easy_init(); if(curl) { // 1. 先获取CSRF令牌和Cookie(若网站需要) std::string homePageData; curl_easy_setopt(curl, CURLOPT_URL, "https://目标网站域名/"); curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, WriteCallback); curl_easy_setopt(curl, CURLOPT_WRITEDATA, &homePageData); curl_easy_perform(curl); // 从首页HTML提取CSRF令牌(匹配<meta name="csrf-token" content="xxx">) std::string csrfToken = "此处替换为提取到的CSRF令牌"; // 提取Cookie(curl自动保存,可通过curl_easy_getinfo获取) char* cookie; curl_easy_getinfo(curl, CURLINFO_COOKIELIST, &cookie); // 2. 构造Livewire搜索请求 std::string postUrl = "https://目标网站域名/livewire/message/搜索组件名称"; // 按抓包结果构造请求体JSON json postData = { {"component", "搜索组件的类名/别名"}, {"data", {{"搜索字段名", keyword}}}, {"action", "search"} // 替换为抓包到的动作名称 }; std::string postBody = postData.dump(); // 设置curl核心参数 curl_easy_setopt(curl, CURLOPT_URL, postUrl.c_str()); curl_easy_setopt(curl, CURLOPT_POST, 1L); curl_easy_setopt(curl, CURLOPT_POSTFIELDS, postBody.c_str()); curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE, postBody.size()); // 设置必要请求头 struct curl_slist* headers = NULL; headers = curl_slist_append(headers, ("X-CSRF-TOKEN: " + csrfToken).c_str()); headers = curl_slist_append(headers, "X-Livewire: true"); headers = curl_slist_append(headers, "Content-Type: application/json"); headers = curl_slist_append(headers, ("Cookie: " + std::string(cookie)).c_str()); curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers); // 执行请求并解析结果 std::string response; curl_easy_setopt(curl, CURLOPT_WRITEDATA, &response); CURLcode res = curl_easy_perform(curl); if(res == CURLE_OK) { json responseJson = json::parse(response); std::string resultHtml = responseJson["html"]; // 用HTML解析库(如gumbo-parser)提取<a>标签的href属性,以下为简单匹配示例 size_t pos = 0; while((pos = resultHtml.find("<a href=\"", pos)) != std::string::npos) { pos += 9; size_t endPos = resultHtml.find("\"", pos); if(endPos != std::string::npos) { resultUrls.push_back(resultHtml.substr(pos, endPos - pos)); pos = endPos; } } } // 清理资源 curl_slist_free_all(headers); curl_easy_cleanup(curl); } return resultUrls; }
备选库推荐
若觉得libcurl处理JSON和HTML解析繁琐,可换用:
- cpprestsdk:微软官方C++ REST库,原生支持HTTP请求与JSON解析,简化AJAX流程
- Reqwest(C++版):轻量级HTTP客户端,搭配nlohmann/json使用更简洁
- gumbo-parser:专门的HTML解析库,提取URL比字符串匹配更可靠
关键注意事项
- 必须严格匹配抓包到的请求格式(端点、头、请求体),否则仍会返回405
- 部分网站会验证
Referer、User-Agent,需在请求头中添加对应字段 - 若遇反爬,需补充User-Agent轮换、请求延迟等逻辑
内容的提问来源于stack exchange,提问作者rokenrock
相关产品推荐
相关产品推荐

