new net files powershell curl batch-file google-image-search

powershell - net - Script para usar Google Image Search con imagen local como entrada



system net webclient downloadfile powershell (2)

Estoy buscando un script por lotes o Powershell para buscar imágenes similares en Google images usando una imagen local como entrada.

Mi investigación hasta el momento

La sintaxis para una búsqueda de imágenes usando una URL en lugar de un archivo local es la siguiente:
https://www.google.com/searchbyimage?image_url=TEST
donde TEST se puede reemplazar con cualquier URL de imagen que tengas.

Jugué con cURL para Windows e imgur como protector de imagen temporal. Pude subir un archivo a imgur por lote. La URL de la imagen se utilizó para buscar imágenes similares en Google.

Pero me pregunto si es posible sin usar ningún caché temporal como imgur o cualquier otro servicio de imágenes en línea. Solo un lote, curl, Google y yo.

Solo un pensamiento. ¿Es posible que un script VBS sea capaz de buscar en Google Images con un archivo local como entrada?
¿O servicios web similares como Tineye son más adecuados para esa tarea?

Este fragmento de PowerShell abrirá la búsqueda de imágenes de Google.

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

Los próximos pasos serían obtener las ID de algunos botones y hacer clic en ellos programáticamente para seleccionar el archivo local. Pero aquí no tengo la experiencia suficiente para lograr esto.


Buena pregunta! Pasé demasiado tiempo jugando con esto, pero creo que finalmente lo consiguió :)

En pocas palabras, debe cargar los bytes sin formato de la imagen, incrustados y formateados correctamente junto con otras cosas, en images.google.com/searchbyimage/upload . La respuesta a esa solicitud contendrá una nueva URL que lo enviará a la página de resultados reales.

Esta función devolverá la URL de la página de resultados. Puede hacer lo que quiera con él, pero para simplemente abrir los resultados en un navegador, páselo a Start-Process .

Por supuesto, Google podría cambiar el flujo de trabajo para esto en cualquier momento, así que no espere que este script funcione para siempre.

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] }

Uso:

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

Editar / Explicación

Aquí hay más detalles. Básicamente, solo te guiaré por los pasos que tomé mientras me daba cuenta de esto.

Primero, seguí adelante e hice una búsqueda de imágenes local.

La URL a la que lo envía es muy larga (~ 1500 caracteres en el caso de longcat), pero no lo suficientemente larga como para codificar completamente la imagen (60 KB). Así que puedes decir de inmediato que es más complejo que simplemente hacer algo como una codificación base64.

A continuación, activé Fiddler y analicé lo que sucede realmente cuando haces una búsqueda local de imágenes. Después de navegar / seleccionar la imagen, ve algo de tráfico en images.google.com/searchbyimage/upload . Ver esa solicitud en detalle revela el mecanismo básico.

  1. Los datos se envían en el formato de multipart/form-data , y debe especificar qué cadena de caracteres separa los diferentes campos (recuadros rojos). Si tiene Bing / Google, encontrará que multipart/form-data es algún tipo de estándar web, pero realmente no importa para este ejemplo.
  2. Necesita (o al menos debería) incluir el nombre del archivo original (cuadro naranja). Tal vez esto influye en los resultados de búsqueda.
  3. La imagen completa en bruto se incluye en el campo de encoded-image (cuadro verde).
  4. La respuesta no contiene los resultados reales, es simplemente un redireccionamiento a la página de resultados reales (cuadros de color púrpura)

Hay algunos campos que no se muestran aquí, muy abajo. No son súper interesantes.

Una vez que descubrí el flujo de trabajo básico, solo fue cuestión de codificarlo. Acabo de copiar la solicitud web que vi en Fiddler lo más que pude, utilizando las API de solicitud web .NET estándar. Las respuestas a esta pregunta SO demuestran las API que necesita para codificar y enviar datos corporales correctamente en una solicitud web.

De alguna experimentación, descubrí que solo necesitas los dos campos corporales que encoded_image en mi código ( encoded_image e image_content ). Ir a través de la interfaz de usuario web incluye más, pero aparentemente no son necesarios.

Más experimentación reveló que ninguno de los otros encabezados o cookies que se muestran en Fiddler son realmente necesarios.

Para nuestros propósitos, en realidad no queremos acceder a la página de resultados, solo obtener un puntero a ella. Por lo tanto, deberíamos configurar AllowAutoRedirect en $false . De esta forma, la redirección 302 de Google se nos proporciona directamente y podemos extraer la URL de la página de resultados de la misma.

Al escribir esta edición, me di una palmada en la frente y me di cuenta de que Powershell v3 tiene el cmdlet Invoke-WebRequest , que podría eliminar la necesidad de las llamadas a la API web de .NET. Desafortunadamente, no pude hacer que funcionara correctamente después de retocar durante 10 minutos, así que me di por vencido. Parece un problema con la forma en que el cmdlet está codificando los datos, aunque podría estar equivocado.


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