- 修改了 `Response` 结构体,添加了 `Message`, `TraceID`, 和 `Error` 字段,并将 `Code` 类型从 `string` 改为 `int`。 - 更新了 `Data` 结构体字段,以匹配新的 API 返回格式。 - 更改了目标 URL 为 `https://qifu.baidu.com/api/v1/ip-portrait/brief-info?ip=`。 - 添加了 `Referer` 请求头。 - 移除了不再需要的 `Cookie` 头。 - 调整了错误处理逻辑,根据 `Message` 字段判断返回数据是否符合预期。
156 lines
4.6 KiB
Go
156 lines
4.6 KiB
Go
package main
|
|
|
|
import (
|
|
"encoding/json"
|
|
"fmt"
|
|
"io"
|
|
"log"
|
|
"net"
|
|
"net/http"
|
|
"os"
|
|
"time"
|
|
)
|
|
|
|
// Response 结构体用于存储整个 JSON 响应
|
|
type JSON struct {
|
|
Code int `json:"code"`
|
|
Message string `json:"message"`
|
|
Data Data `json:"data"`
|
|
TraceID string `json:"traceId"`
|
|
Error any `json:"error"`
|
|
}
|
|
|
|
// Data 结构体对应 JSON 里的 "data"
|
|
type Data struct {
|
|
Country string `json:"country"`
|
|
Province string `json:"province"`
|
|
City string `json:"city"`
|
|
ISP string `json:"isp"`
|
|
Scene string `json:"scene"`
|
|
Company string `json:"company"`
|
|
RiskScore string `json:"risk_score"`
|
|
HitRiskNum int `json:"hit_risk_num"`
|
|
QueryIP string `json:"query_ip"`
|
|
Version string `json:"version"`
|
|
}
|
|
|
|
func isValidIP(ip string) bool {
|
|
return net.ParseIP(ip) != nil
|
|
}
|
|
|
|
func SaveBytesToFile(data []byte, filename string, syncToDisk bool) error {
|
|
if filename == "" {
|
|
return fmt.Errorf("filename cannot be empty")
|
|
}
|
|
|
|
file, err := os.OpenFile(filename, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0600)
|
|
if err != nil {
|
|
return fmt.Errorf("failed to open file %q: %w", filename, err)
|
|
}
|
|
defer file.Close()
|
|
|
|
_, err = file.Write(data)
|
|
if err != nil {
|
|
return fmt.Errorf("failed to write to file %q: %w", filename, err)
|
|
}
|
|
|
|
if syncToDisk {
|
|
err = file.Sync()
|
|
if err != nil {
|
|
return fmt.Errorf("failed to sync data to disk for file %q: %w", filename, err)
|
|
}
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func curl_(IP_ADDR string) (string, error) {
|
|
var (
|
|
err error
|
|
URL_ADDR string
|
|
|
|
HTTP_RESP *http.Response
|
|
HTTP_Request *http.Request
|
|
HTTP_BODY []byte
|
|
HTTP_CLIENT *http.Client
|
|
HTPP_JSON JSON
|
|
)
|
|
|
|
if !isValidIP(IP_ADDR) {
|
|
log.Printf("无效的 IP 地址: %s", IP_ADDR)
|
|
}
|
|
|
|
// 目标 URL
|
|
URL_ADDR = "https://qifu.baidu.com/api/v1/ip-portrait/brief-info?ip=" + IP_ADDR
|
|
|
|
// 创建 HTTP 请求
|
|
HTTP_Request, err = http.NewRequest("GET", URL_ADDR, nil)
|
|
if err != nil {
|
|
log.Printf("创建请求时出错: %v", err)
|
|
}
|
|
|
|
Referer := "https://qifu.baidu.com/?activeKey=SEARCH_IP&trace=apistore_ip_aladdin&activeId=SEARCH_IP_ADDRESS&ip=" + IP_ADDR
|
|
|
|
// 设置请求头
|
|
HTTP_Request.Header.Set("User-Agent", "Mozilla/5.0 (Linux; Android 6.0; Nexus 5 Build/MRA58N) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/130.0.0.0 Mobile Safari/537.36")
|
|
HTTP_Request.Header.Set("Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7")
|
|
HTTP_Request.Header.Set("Accept-Encoding", "gzip, deflate, br, zstd")
|
|
HTTP_Request.Header.Set("Accept-Language", "zh-CN,zh;q=0.9,en;q=0.8")
|
|
HTTP_Request.Header.Set("Cache-Control", "max-age=0")
|
|
HTTP_Request.Header.Set("Connection", "keep-alive")
|
|
HTTP_Request.Header.Set("Host", "qifu.baidu.com")
|
|
HTTP_Request.Header.Set("Sec-Ch-Ua", `"Chromium";v="130", "Google Chrome";v="130", "Not?A_Brand";v="99"`)
|
|
HTTP_Request.Header.Set("Sec-Ch-Ua-Mobile", "?1")
|
|
HTTP_Request.Header.Set("Sec-Ch-Ua-Platform", `"Android"`)
|
|
HTTP_Request.Header.Set("Sec-Fetch-Dest", "document")
|
|
HTTP_Request.Header.Set("Sec-Fetch-Mode", "navigate")
|
|
HTTP_Request.Header.Set("Sec-Fetch-Site", "none")
|
|
HTTP_Request.Header.Set("Sec-Fetch-User", "?1")
|
|
HTTP_Request.Header.Set("Upgrade-Insecure-Requests", "1")
|
|
HTTP_Request.Header.Set("Referer", Referer)
|
|
|
|
// 创建 HTTP 客户端并设置超时时间
|
|
HTTP_CLIENT = &http.Client{Timeout: 10 * time.Second}
|
|
|
|
// 发送请求
|
|
HTTP_RESP, err = HTTP_CLIENT.Do(HTTP_Request)
|
|
if err != nil {
|
|
log.Printf("发送请求时出错: %v", err)
|
|
return "", fmt.Errorf("发送请求时出错: %v", err)
|
|
}
|
|
defer HTTP_RESP.Body.Close()
|
|
|
|
// 检查 HTTP 响应状态码
|
|
if HTTP_RESP.StatusCode != http.StatusOK {
|
|
log.Printf("HTTP 请求失败,状态码: %d", HTTP_RESP.StatusCode)
|
|
return "", fmt.Errorf("HTTP 请求失败,状态码: %d", HTTP_RESP.StatusCode)
|
|
}
|
|
|
|
// 读取响应体
|
|
HTTP_BODY, err = io.ReadAll(HTTP_RESP.Body)
|
|
if err != nil {
|
|
log.Printf("读取响应体时出错: %v", err)
|
|
return "", fmt.Errorf("读取响应体时出错: %v", err)
|
|
}
|
|
|
|
// 保存响应体到文件
|
|
if err := SaveBytesToFile(append(HTTP_BODY, '\n'), "response.json", true); err != nil {
|
|
log.Printf("failed to save HTTP response to file: %v", err)
|
|
}
|
|
|
|
// 解析 JSON 数据
|
|
err = json.Unmarshal(HTTP_BODY, &HTPP_JSON)
|
|
if err != nil {
|
|
fmt.Println("Error parsing JSON:", err)
|
|
return "", fmt.Errorf("解析 JSON 失败: %v", err)
|
|
}
|
|
|
|
// 确保数据有效
|
|
if HTPP_JSON.Message != "success" {
|
|
log.Printf("返回数据不符合预期: %d", HTPP_JSON.Code)
|
|
return "", fmt.Errorf("返回数据不符合预期: %d", HTPP_JSON.Code)
|
|
}
|
|
|
|
return fmt.Sprintf("%s%s", HTPP_JSON.Data.Country, HTPP_JSON.Data.Province), err
|
|
}
|