XMLHTTPRequest请求pb.nalog.ru始终返回404页面未找到问题
问题原因分析
- Fragment(哈希值)的作用: URL中的
#及其后续内容是客户端片段标识符,不会被发送到服务器。浏览器加载search.html后,由页面内的JavaScript解析片段参数并发起实际的搜索API请求。 - XMLHTTP的错误处理: 你的代码中把片段直接拼接到URL中,XMLHTTP60错误地将
#编码为%23,导致服务器收到的路径是/search.html%23t=...,这是一个不存在的资源,因此返回404。 - 动态内容加载: 即使你正确获取了
search.html页面,搜索结果也是通过JavaScript动态加载的,XMLHTTP不会执行页面脚本,因此无法直接从返回的HTML中获取结果元素。
解决方案
步骤1:定位实际搜索API端点
使用浏览器开发者工具(Network标签)观察点击“Искать”后的网络请求,会发现页面发起了一个API调用(通常是XHR/Fetch请求),示例格式:https://pb.nalog.ru/api/v3/search?query=9714055795&mode=all&_=1730356470622
其中:
query对应你输入的组织IDmode=all对应片段中的mode=search-all_是UTC毫秒级时间戳(和你生成的t值一致)
步骤2:修改VBA代码直接调用API
以下是修正后的代码,包含必要的请求头以模拟浏览器请求,并直接调用搜索API:
Option Explicit Private Type SYSTEMTIME wYear As Integer wMonth As Integer wDayOfWeek As Integer wDay As Integer wHour As Integer wMinute As Integer wSecond As Integer wMilliseconds As Integer End Type Private Declare PtrSafe Sub GetSystemTime Lib "kernel32" (lpSystemTime As SYSTEMTIME) Function CurrentTimeMillis() As Double ' 返回UTC时间戳(毫秒级,与Date.getTime()一致) Dim st As SYSTEMTIME GetSystemTime st Dim t_Start As Date, t_Now As Date t_Start = DateSerial(1970, 1, 1) t_Now = DateSerial(st.wYear, st.wMonth, st.wDay) + TimeSerial(st.wHour, st.wMinute, st.wSecond) CurrentTimeMillis = DateDiff("s", t_Start, t_Now) * 1000 + st.wMilliseconds End Function Public Sub FetchSearchResults() Dim http As New XMLHTTP60 Dim responseText As String Dim curr As Double Dim orgId As String orgId = "9714055795" ' 替换为目标组织ID curr = CurrentTimeMillis() With http .Open "GET", "https://pb.nalog.ru/api/v3/search?query=" & orgId & "&mode=all&_=" & curr, False ' 添加浏览器请求头,避免被服务器拦截 .setRequestHeader "User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36" .setRequestHeader "Referer", "https://pb.nalog.ru/" .setRequestHeader "Accept", "application/json, text/javascript, */*; q=0.01" .send ' 检查请求状态 If .Status = 200 Then responseText = .responseText Debug.Print "API响应内容:" & vbCrLf & responseText ' 根据API返回格式处理结果: ' 1. 如果是JSON:需要使用VBA-JSON库解析(需自行导入) ' 2. 如果是HTML片段:加载到HTMLDocument提取元素 Dim html As New HTMLDocument html.body.innerHTML = responseText Dim statusElements As IHTMLElementCollection Set statusElements = html.getElementsByClassName("pb-subject-status pb-subject-status--active") If statusElements.Length > 0 Then Debug.Print "找到状态元素:" & statusElements(0).innerText Else Debug.Print "未找到目标元素" End If Else Debug.Print "请求失败,状态码:" & .Status & ",响应:" & .responseText End If End With End Sub
步骤3:处理API响应
- 如果API返回JSON:需要导入VBA-JSON库来解析响应,提取所需数据。
- 如果API返回HTML片段:直接加载到
HTMLDocument中,即可通过getElementsByClassName等方法获取目标元素。
关键注意事项
- 请求头模拟: 很多网站会拦截没有浏览器标识的请求,因此必须添加
User-Agent、Referer等头信息。 - API端点验证: 请通过浏览器开发者工具确认实际的API路径,不同网站版本可能会有变化。
- 时间戳一致性: 确保时间戳是UTC毫秒级,与页面JavaScript使用的
Date.getTime()保持一致。
内容的提问来源于stack exchange,提问作者AntiDrondert
相关产品推荐
相关产品推荐

