使用本地图像作为输入使用Google图像搜索的脚本

时间:2013-01-31 20:13:57

标签: powershell curl batch-file google-image-search

我正在寻找批处理或Powershell脚本,以使用本地图像作为输入在Google图像上搜索类似的图像。

enter image description here

到目前为止我的研究

使用URL而不是本地文件进行图像搜索的语法如下:
https://www.google.com/searchbyimage?image_url=TEST
其中TEST可以替换为您拥有的任何图像URL。

我使用cURL for windowsimgur作为临时图像保护程序。 我能够通过批量上传文件到imgur。然后,图片网址用于搜索Google上的类似图片。

但我想知道是否可以在不使用任何临时缓存(如imgur或任何其他在线图片服务)的情况下使用它。只是批量,卷曲,谷歌和我。

只是一个想法。 VBS脚本是否能够使用本地文件作为输入在Google图像上进行搜索? 或者像Tineye这样的类似网络服务更适合这项任务?


此PowerShell代码段将打开Goog​​le视频搜索。

$IE= new-object -com InternetExplorer.Application
$IE.navigate2("https://www.google.com/imghp?hl=en")
while ($IE.busy) {
sleep -milliseconds 50
}
$IE.visible=$true

接下来的步骤是获取某些按钮的ID并以编程方式单击它们以选择本地文件。但在这里,我没有足够的经验来实现这一目标。

3 个答案:

答案 0 :(得分:19)

很酷的问题!我花了太多时间来修补它,但我认为最终得到了它:)

简而言之,您必须将图像的原始字节,嵌入并正确格式化以及其他一些内容上传到images.google.com/searchbyimage/upload。对该请求的响应将包含一个新URL,该URL将您发送到实际结果页面。

此功能将返回结果页面网址。您可以随意使用它,但只需在浏览器中打开结果,将其传递给Start-Process

当然,Google可以随时更改此工作流程,因此不要指望此脚本能够永久运行。

function Get-GoogleImageSearchUrl
{
    param(
        [Parameter(Mandatory = $true)]
        [ValidateScript({ Test-Path $_ })]
        [string] $ImagePath
    )

    # extract the image file name, without path
    $fileName = Split-Path $imagePath -Leaf

    # the request body has some boilerplate before the raw image bytes (part1) and some after (part2)
    #   note that $filename is included in part1
    $part1 = @"
-----------------------------7dd2db3297c2202
Content-Disposition: form-data; name="encoded_image"; filename="$fileName"
Content-Type: image/jpeg


"@
    $part2 = @"
-----------------------------7dd2db3297c2202
Content-Disposition: form-data; name="image_content"


-----------------------------7dd2db3297c2202--

"@

    # grab the raw bytes composing the image file
    $imageBytes = [Io.File]::ReadAllBytes($imagePath)

    # the request body should sandwich the image bytes between the 2 boilerplate blocks
    $encoding = New-Object Text.ASCIIEncoding
    $data = $encoding.GetBytes($part1) + $imageBytes + $encoding.GetBytes($part2)

    # create the HTTP request, populate headers
    $request = [Net.HttpWebRequest] ([Net.HttpWebRequest]::Create('http://images.google.com/searchbyimage/upload'))
    $request.Method = "POST"
    $request.ContentType = 'multipart/form-data; boundary=---------------------------7dd2db3297c2202'  # must match the delimiter in the body, above
    $request.ContentLength = $data.Length

    # don't automatically redirect to the results page, just take the response which points to it
    $request.AllowAutoredirect = $false

    # populate the request body
    $stream = $request.GetRequestStream()
    $stream.Write($data, 0, $data.Length)
    $stream.Close()        

    # get response stream, which should contain a 302 redirect to the results page
    $respStream = $request.GetResponse().GetResponseStream()

    # pluck out the results page link that you would otherwise be redirected to
    (New-Object Io.StreamReader $respStream).ReadToEnd() -match 'HREF\="([^"]+)"' | Out-Null
    $matches[1]
}

用法:

$url = Get-GoogleImageSearchUrl 'C:\somepic.jpg'
Start-Process $url

编辑/解释

这里有一些更详细的信息。我基本上只是带你完成我所知道的步骤。

首先,我只是继续进行本地图像搜索。

Google image search

它发送给你的URL很长(在longcat的情况下约为1500个字符),但不足以完全编码图像(60KB)。所以你可以直接说出它比简单地做类似base64编码的事情更复杂。

接下来,我启动了Fiddler并查看了进行本地图像搜索时实际发生的情况。浏览/选择图片后,您会看到images.google.com/searchbyimage/upload的一些流量。详细查看该请求揭示了基本机制。

Fiddler session

  1. 数据以multipart/form-data的格式发送,您需要指定将不同字段(红色框)分隔的字符串。如果您使用Bing / Google,您会发现multipart/form-data是某种Web标准,但对于此示例而言,这无关紧要。
  2. 您需要(或至少应该)包含原始文件名(橙色框)。也许这会影响搜索结果。
  3. 完整的原始图片包含在encoded-image字段(绿色框)中。
  4. 响应不包含实际结果,只是重定向到实际结果页面(紫色框)
  5. 此处未显示几个字段,位于底部。他们并不是非常有趣。

    一旦我弄清楚了基本的工作流程,只需要对其进行编码。我只是尽可能地使用标准的.NET Web请求API复制了我在Fiddler中看到的Web请求。 this SO question的答案演示了您在Web请求中正确编码和发送正文数据所需的API。

    通过一些实验,我发现您只需要我的代码中包含的两个正文字段(encoded_imageimage_content)。浏览Web UI包含更多内容,但显然不需要它们。

    更多实验表明,Fiddler中显示的其他标题或Cookie都不是真正需要的。

    出于我们的目的,我们实际上并不想访问结果页面,只获取指向它的指针。因此,我们应将AllowAutoRedirect设置为$false。这样,Google的302重定向就会直接提供给我们,我们可以从中提取结果页面网址。

    在编写此编辑时,我拍了拍我的额头并意识到Powershell v3具有Invoke-WebRequest cmdlet,这可能会消除对.NET Web API调用的需求。不幸的是,经过10分钟修补后我无法正常工作,所以我放弃了。似乎cmdlet编码数据的方式存在一些问题,但我可能错了。

答案 1 :(得分:1)

function Get-GoogleImageSearchUrl
{
    param(
        [Parameter(Mandatory = $true)]
        [ValidateScript({ Test-Path $_ })]
        [string] $ImagePath
    )

    # extract the image file name, without path
    $fileName = Split-Path $imagePath -Leaf

    # the request body has some boilerplate before the raw image bytes (part1) and some after (part2)
    #   note that $filename is included in part1
    $part1 = @"
--7dd2db3297c2202
Content-Disposition: form-data; name="encoded_image"; filename="$fileName"
Content-Type: application/octet-stream`r`n`r`n
"@
    $part2 = @"
`r`n--7dd2db3297c2202--`r`n
"@

    # grab the raw bytes composing the image file
    $imageBytes = [Io.File]::ReadAllBytes($imagePath)

    # the request body should sandwich the image bytes between the 2 boilerplate blocks
    $encoding = New-Object Text.ASCIIEncoding
    $data = $encoding.GetBytes($part1) + $imageBytes + $encoding.GetBytes($part2)

    # create the HTTP request, populate headers
    $request = [Net.HttpWebRequest] ([Net.HttpWebRequest]::Create('http://images.google.com/searchbyimage/upload'))
    $request.Method = "POST"
    $request.ContentType = 'multipart/form-data; boundary=7dd2db3297c2202'  # must match the delimiter in the body, above

    # don't automatically redirect to the results page, just take the response which points to it
    $request.AllowAutoredirect = $false

    # populate the request body
    $stream = $request.GetRequestStream()
    $stream.Write($data, 0, $data.Length)
    $stream.Close()        

    # get response stream, which should contain a 302 redirect to the results page
    $respStream = $request.GetResponse().GetResponseStream()

    # pluck out the results page link that you would otherwise be redirected to
    (New-Object Io.StreamReader $respStream).ReadToEnd() -match 'HREF\="([^"]+)"' | Out-Null
    $matches[1]
}
$url = Get-GoogleImageSearchUrl 'C:\somepic.jpg'
Start-Process $url

答案 2 :(得分:0)

使用GoogleImageSearch module for PowerShell怎么样?

免责声明: 我是该模块的开发人员,并且使用以前的答案来构建此模块。