14

ローカル画像を入力として使用して、Google 画像で類似の画像を検索するためのバッチまたは Powershell スクリプトを探しています。

ここに画像の説明を入力

これまでの私の研究

ローカル ファイルではなく URL を使用した画像検索の構文は次のとおりです。
https://www.google.com/searchbyimage?image_url=TEST
ここで、TEST は任意の画像 URL に置き換えることができます。

Windows 用の cURLとimgurを一時的なイメージ セーバーとして使用しましたバッチ経由でファイルを imgur にアップロードできました。次に、画像の URL を使用して、Google で類似の画像を検索しました。

しかし、imgur や他のオンライン画像サービスのような一時キャッシュを使用せずに、それが可能かどうか疑問に思います。バッチ、curl、Google、そして私。

ちょっとした考え。VBS スクリプトは、ローカル ファイルを入力として Google 画像を検索できるのでしょうか? それとも、 Tineye
のような同様の Web サービスがそのタスクにより適しているのでしょうか?


この PowerShell スニペットは、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

次の手順では、いくつかのボタンの ID を取得し、プログラムでクリックしてローカル ファイルを選択します。しかし、ここではこれを達成するのに十分な経験がありません。

4

3 に答える 3

24

かっこいい質問です!私はこれをいじくり回すのにあまりにも多くの時間を費やしました、しかし私はついにそれを手に入れたと思います:)

一言で言えば、他のものと一緒に埋め込まれ、適切にフォーマットされた画像の生のバイトをにアップロードする必要があります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画像検索

送信先のURLは非常に長いですが(longcatの場合は約1500文字)、画像を完全にエンコードするのに十分な長さではありません(60KB)。したがって、base64エンコーディングのようなことを行うよりも複雑であることがすぐにわかります。

次に、Fiddlerを起動して、ローカル画像検索を実行したときに実際に何が起こっているかを調べました。画像を閲覧/選択すると、へのトラフィックが表示されimages.google.com/searchbyimage/uploadます。そのリクエストを詳細に表示すると、基本的なメカニズムが明らかになります。

フィドラーセッション

  1. データはの形式で送信されておりmultipart/form-data、さまざまなフィールド(赤いボックス)を区切る文字列を指定する必要があります。multipart/form-dataBing / Googleを使用している場合、それはある種のWeb標準であることがわかりますが、この例では実際には問題ではありません。
  2. 元のファイル名(オレンジ色のボックス)を含める必要があります(または少なくとも含める必要があります)。おそらく、これが検索結果に影響します。
  3. 完全な生の画像がencoded-imageフィールド(緑色のボックス)に含まれています。
  4. 応答には実際の結果は含まれていません。実際の結果ページ(紫色のボックス)へのリダイレクトにすぎません。

ここに表示されていないフィールドがいくつかあります。彼らはあまり面白くありません。

基本的なワークフローを理解したら、それをコーディングするだけでした。標準の.NETWebリクエストAPIを使用して、Fiddlerで見たWebリクエストを可能な限り忠実にコピーしました。このSOの質問に対する回答は、Webリクエストで本文データを適切にエンコードして送信するために必要なAPIを示しています。

encoded_imageいくつかの実験から、コードに含めた2つのbodyフィールド(と)だけが必要であることがわかりましたimage_content。Web UIを通過することにはさらに多くのことが含まれますが、明らかにそれらは必須ではありません。

さらに実験を重ねた結果、Fiddlerに表示されている他のヘッダーやCookieは実際には必要ないことが明らかになりました。

私たちの目的では、実際には結果ページにアクセスするのではなく、そのページへのポインタを取得するだけです。したがって、に設定AllowAutoRedirectする必要があり$falseます。そうすれば、Googleの302リダイレクトが直接提供され、そこから結果ページのURLを抽出できます。

この編集を書いているときに、額を叩いて、Powershell v3にInvoke-WebRequestコマンドレットがあることに気付きました。これにより、.NETWebAPI呼び出しが不要になる可能性があります。残念ながら、10分間いじった後、正しく動作させることができなかったので、あきらめました。私は間違っているかもしれませんが、コマンドレットがデータをエンコードする方法に問題があるようです。

于 2013-02-16T02:10:35.993 に答える
0

PowerShell の GoogleImageSearch モジュールを使用するのはどうですか?

免責事項:私はこのモジュールの開発者であり、以前の回答を使用してこのモジュールを構築しました。

于 2019-11-30T07:52:34.480 に答える