Подтвердить что ты не робот

Script использовать Google Image Search с локальным изображением в качестве входного

Я ищу пакет или Powershell script для поиска похожих изображений на изображениях Google, используя локальное изображение в качестве входных данных.

enter image description here

Мои исследования пока

Синтаксис поиска изображений с использованием URL-адреса, а не локального файла, следующий: https://www.google.com/searchbyimage?image_url=TEST
где TEST можно заменить любым URL-адресом изображения.

Я играл с cURL для окон и imgur как временная заставка изображения. Я смог загрузить файл в imgur через партию. Затем URL-адрес изображения использовался для поиска похожих изображений в Google.

Но мне интересно, возможно ли это без использования какого-либо временного кеша, такого как imgur или любой другой онлайн-сервис изображений. Просто пакет, завиток, Google и меня.

Просто мысль. Возможно ли использовать VBS script для поиска в Google Images с локальным файлом в качестве входных данных?
Или аналогичные веб-сервисы, такие как Tineye, лучше подходят для этой задачи?


Этот фрагмент powershell откроет Search Googles Image Search.

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

Следующие шаги состоят в том, чтобы получить идентификаторы некоторых кнопок и щелкнуть их программно, чтобы выбрать локальный файл. Но здесь я недостаточно опытен, чтобы добиться этого.

4b9b3361

Ответ 1

Прохладный вопрос! Я потратил слишком много времени на это, но, думаю, наконец-то понял:)

Вкратце, вы должны загрузить необработанные байты вашего изображения, встроенные и отформатированные вместе с некоторыми другими вещами, в images.google.com/searchbyimage/upload. Ответ на этот запрос будет содержать новый URL-адрес, который отправит вас на страницу фактических результатов.

Эта функция вернет URL страницы результатов. Вы можете делать все, что хотите, но просто открыть результаты в браузере, передать его на Start-Process.

Конечно, Google может изменить рабочий процесс для этого в любое время, поэтому не ожидайте, что этот script будет работать навсегда.

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-адрес, который он отправляет вам, очень длинный (~ 1500 символов в случае longcat), но не достаточно длинный, чтобы полностью кодировать изображение (60 КБ). Таким образом, вы можете сразу сказать, что это сложнее, чем просто делать что-то вроде кодировки base64.

Затем я запустил Fiddler и посмотрел, что происходит, когда вы выполняете локальный поиск изображений. После просмотра/выбора изображения вы увидите трафик на images.google.com/searchbyimage/upload. Подробный просмотр этого запроса показывает основной механизм.

Fiddler session

  • Данные отправляются в формате multipart/form-data, и вам нужно указать, какая строка символов разделяет разные поля (красные поля). Если вы используете Bing/Google, вы обнаружите, что multipart/form-data является своего рода веб-стандартом, но для этого в действительности это не важно.
  • Вам необходимо (или, по крайней мере, должно) включить исходное имя файла (оранжевый ящик). Возможно, это влияет на результаты поиска.
  • Полное, необработанное изображение включено в поле encoded-image (зеленый квадрат).
  • Ответ не содержит фактических результатов, это просто перенаправление на страницу фактических результатов (фиолетовые поля).

Здесь есть несколько полей, которые показаны ниже. Они не очень интересны.

Как только я понял основной рабочий процесс, это было всего лишь вопросом его кодирования. Я просто скопировал веб-запрос, который я видел в Fiddler, насколько это было возможно, используя стандартные API веб-запросов .NET. Ответы на этот вопрос SO демонстрируют необходимые вам API, чтобы правильно кодировать и отправлять данные тела в веб-запрос.

Из некоторых экспериментов я обнаружил, что вам нужны только два поля тела, которые я включил в свой код (encoded_image и image_content). Переход через веб-интерфейс включает в себя больше, но, по-видимому, они не требуются.

Больше экспериментов показало, что ни один из других заголовков или файлов cookie, показанных в Fiddler, действительно не требуется.

Для наших целей мы фактически не хотим получать доступ к странице результатов, а только получаем указатель на нее. Таким образом, мы должны установить AllowAutoRedirect в $false. Таким образом, перенаправление Google 302 предоставляется нам напрямую, и мы можем извлечь URL страницы результатов из него.

Во время написания этого редактирования я ударил меня по лбу и понял, что у Powershell v3 есть командлет Invoke-WebRequest, который потенциально может устранить необходимость в вызовах веб-API.NET. К сожалению, я не мог заставить его работать правильно после того, как поработал в течение 10 минут, поэтому я сдался. Похоже, что некоторые проблемы связаны с тем, как командлет кодирует данные, хотя я могу ошибаться.

Ответ 2

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