1

そのため、現在、指定された画像をハードディスクから Google の逆画像検索に POST し、応答を処理する小さなアプリに取り組んでいます。問題は、私が得ている応答が期待したものではないことです。私は POST リクエストの構造を複製するために自分でできる限りのことをしましたが、私の人生では、期待する応答が得られない理由を理解できません。200 レスポンス コードが返されますが、HTML 出力は何らかの Google エラーです (画像による検索は利用できません。数時間後にもう一度お試しください)。私は Fiddler を使用してリクエストの構造を把握しました。私が知る限り、私のアプリから生成されたものは、Cookie ヘッダーがないことを除けば、実質的に同じです (それでしょうか?)。その場合、Cookie を作成してリクエストに組み込むにはどうすればよいですか?

これは、Google のアップロード サービスを通じて行われたリクエストです。

これが私のアプリからのリクエストです。

ここに私のコードがあります:基本機能)

    String^ url = "https://www.google.com/searchbyimage/upload";
    HttpWebRequest^ request = (HttpWebRequest^) WebRequest::Create(url);
    request->Method = "POST";
    request->UserAgent = "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:16.0) Gecko/20100101 Firefox/16.0";
    request->Accept = "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8";
    request->Headers["Accept-Language"] = "en-US,en;q=0.5";
    request->Headers["Accept-Encoding"] = "gzip, deflate";
    String^ boundary = "-----------------------------23281168279961";
    request->ContentType = "multipart/form-data; boundary=" + boundary;
    request->Referer = "https://www.google.com/imghp?hl=en&tab=wi";

    String^ header = boundary + "\n";
    header += "Content-Disposition: form-data; name=\"image_url\"\n\n\n";

    header += boundary + "\n";
    header += "Content-Disposition: form-data; name=\"encoded_image\"; filename=\"2010-04-09-ec52529.png\"\n";
    header += "Content-Type: image/png\n\n";

    String^ footer = "\n" + boundary + "\n";
    footer += "Content-Disposition: form-data; name=\"image_content\"\n\n\n";

    footer += boundary + "\n";
    footer += "Content-Disposition: form-data; name=\"filename\"\n\n\n";

    footer += boundary + "\n";
    footer += "Content-Disposition: form-data; name=\"num\"\n\n";
    footer += "10\n";

    footer += boundary + "\n";
    footer += "Content-Disposition: form-data; name=\"hl\"\n\n";
    footer += "en\n";

    footer += boundary + "\n";
    footer += "Content-Disposition: form-data; name=\"safe\"\n\n";
    footer += "off\n";

    footer += boundary + "\n";
    footer += "Content-Disposition: form-data; name=\"bih\"\n\n";
    footer += "578\n";

    footer += boundary + "\n";
    footer += "Content-Disposition: form-data; name=\"biw\"\n\n";
    footer += "1366\n";
    footer += boundary + "--\n";

    array<Byte>^ headerData = Encoding::ASCII->GetBytes(header);
    array<Byte>^ imageData = File::ReadAllBytes(oldImage);
    array<Byte>^ footerData = Encoding::ASCII->GetBytes(footer);

    request->ContentLength = headerData->Length + imageData->Length + footerData->Length;

    Stream^ reqStream = request->GetRequestStream();

    reqStream->Write(headerData, 0, headerData->Length);
    reqStream->Write(imageData, 0, imageData->Length);
    reqStream->Write(footerData, 0, footerData->Length);

    HttpWebResponse^ response = (HttpWebResponse^) request->GetResponse();
    StreamReader^ reader = gcnew StreamReader(response->GetResponseStream());
    String^ things = reader->ReadToEnd();
4

1 に答える 1

1

Google はリクエスト ヘッダーの処理に少しうるさいことがわかりました。私が遭遇した3つの問題があります:

  • 画像は base64 でエンコードされ、 に+置き換えられ-、 に/置き換えられます_
  • Content-Type境界パラメーターは引用符で囲んではいけません
  • Content-Disposition名前パラメータは引用符で囲む必要があります

C# を使用している場合は、これらの癖を処理するためのドロップイン置換がここにあります。コードはここMultipartFormDataContentから適応されます:

public class MultipartFormDataContentCompat : MultipartContent
{
    public MultipartFormDataContentCompat() : base("form-data")
    {
        FixBoundaryParameter();
    }

    public MultipartFormDataContentCompat(string boundary) : base("form-data", boundary)
    {
        FixBoundaryParameter();
    }

    public override void Add(HttpContent content)
    {
        base.Add(content);
        AddContentDisposition(content, null, null);
    }

    public void Add(HttpContent content, string name)
    {
        base.Add(content);
        AddContentDisposition(content, name, null);
    }

    public void Add(HttpContent content, string name, string fileName)
    {
        base.Add(content);
        AddContentDisposition(content, name, fileName);
    }

    private void AddContentDisposition(HttpContent content, string name, string fileName)
    {
        var headers = content.Headers;
        if (headers.ContentDisposition != null)
            return;
        headers.ContentDisposition = new ContentDispositionHeaderValue("form-data")
        {
            Name = QuoteString(name),
            FileName = QuoteString(fileName)
        };
    }

    private string QuoteString(string str)
    {
        return '"' + str + '"';
    }

    private void FixBoundaryParameter()
    {
        var boundary = Headers.ContentType.Parameters.Single(p => p.Name == "boundary");
        boundary.Value = boundary.Value.Trim('"');
    }
}

画像をアップロードするには:

private static string FileToBase64(string imagePath)
{
    byte[] content = File.ReadAllBytes(imagePath);
    string base64 = Convert.ToBase64String(content).Replace('+', '-').Replace('/', '_');
    return base64;
}

public static void UploadImage(string imagePath)
{
    using (var client = new HttpClient())
    {
        var form = new MultipartFormDataContentCompat();
        form.Add(new StringContent(FileToBase64(imagePath)), "image_content");
        form.Add(new StringContent(Path.GetFileName(imagePath)), "filename");
        var response = client.PostAsync("https://images.google.com/searchbyimage/upload", form).Result;
        // Do whatever you want with the response
    }
}
于 2016-07-08T08:20:05.350 に答える