Delphi调用Google Lens反向图搜获取手机型号失效问题求助
解决方案:Google Lens反向搜图提取手机型号(Delphi)
问题分析
你的代码依赖固定字符串片段匹配,但Google Lens的页面结构会随内容动态变化,不同图片对应的页面渲染逻辑可能不同,导致原有特征串失效。目标文本通常嵌入在页面的内联JSON数据块中,而非直接的HTML节点,所以普通HTML解析器无法直接定位。
可行方案:解析内联JSON数据
Google Lens的页面会将搜索结果数据放在AF_initDataCallback这样的内联JS变量里,我们可以提取这部分JSON内容并解析,从而稳定获取“相关搜索”的型号文本。
Delphi实现代码
uses System.Net.HttpClient, System.SysUtils, System.JSON, System.StrUtils; function ExtractPhoneModelFromLens(const ImageURL: string): string; var LHTTPClient: TNetHTTPClient; LResponseContent: string; LStartPos, LEndPos: Integer; LJSONStr: string; LJSONValue: TJSONValue; LJSONArray: TJSONArray; LItem: TJSONValue; LQueryObj: TJSONObject; begin Result := ''; LHTTPClient := TNetHTTPClient.Create(nil); try // 模拟浏览器请求头,避免被拦截 LHTTPClient.UserAgent := 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/125.0.0.0 Safari/537.36'; LHTTPClient.AcceptLanguage := 'en-US,en;q=0.5'; LHTTPClient.Accept := 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8'; // 请求Google Lens页面 LResponseContent := LHTTPClient.Get('https://lens.google.com/uploadbyurl?url=' + ImageURL).ContentAsString; // 提取AF_initDataCallback中的JSON数据块 LStartPos := Pos('AF_initDataCallback(', LResponseContent); if LStartPos = 0 then Exit; LStartPos := LStartPos + Length('AF_initDataCallback('); // 匹配对应的闭合括号(处理嵌套) LEndPos := LStartPos; var LBracketCount := 1; while LEndPos <= Length(LResponseContent) do begin case LResponseContent[LEndPos] of '(': Inc(LBracketCount); ')': Dec(LBracketCount); end; if LBracketCount = 0 then Break; Inc(LEndPos); end; if LEndPos >= Length(LResponseContent) then Exit; // 截取JSON字符串并清理(去掉末尾的分号) LJSONStr := Copy(LResponseContent, LStartPos, LEndPos - LStartPos); LJSONStr := Trim(LJSONStr); if EndsStr(';', LJSONStr) then LJSONStr := Copy(LJSONStr, 1, Length(LJSONStr)-1); // 解析JSON LJSONValue := TJSONObject.ParseJSONValue(LJSONStr); if not Assigned(LJSONValue) then Exit; try // 遍历JSON结构,找到相关搜索的query字段(路径可能需根据实际调整) if LJSONValue is TJSONArray then begin LJSONArray := TJSONArray(LJSONValue); // 这里的索引需要根据实际JSON结构调整,示例为常见路径 if LJSONArray.Count > 1 then begin var LInnerArray := LJSONArray.Items[1] as TJSONArray; if Assigned(LInnerArray) and (LInnerArray.Count > 0) then begin var LDataBlock := LInnerArray.Items[0] as TJSONArray; if Assigned(LDataBlock) and (LDataBlock.Count > 5) then begin var LRelatedSearches := LDataBlock.Items[5] as TJSONArray; if Assigned(LRelatedSearches) and (LRelatedSearches.Count > 0) then begin // 取第一个相关搜索的query LItem := LRelatedSearches.Items[0]; if LItem is TJSONArray then begin LQueryObj := TJSONArray(LItem).Items[0] as TJSONObject; if Assigned(LQueryObj) then Result := LQueryObj.GetValue<string>('query'); end; end; end; end; end; end; finally LJSONValue.Free; end; finally LHTTPClient.Free; end; end; // 使用示例 procedure TForm1.Button1Click(Sender: TObject); var Model: string; begin // 测试第二个图片 Model := ExtractPhoneModelFromLens('https://fdn2.gsmarena.com/vv/bigpic/samsung-galaxy-m32-5g-new.jpg'); if Model <> '' then ShowMessage('提取到型号:' + Model) else ShowMessage('未找到型号'); end;
注意事项
- Google的内联JSON结构可能会随时调整,若后续失效,需重新查看页面源码,调整JSON解析的路径索引。
- 若请求被Google拦截,可尝试添加更多请求头(如
Referer),或使用代理IP。 - 不要频繁请求,避免触发Google的反爬机制。
内容的提问来源于stack exchange,提问作者Ismail Dz
相关产品推荐
相关产品推荐

