Search code examples
c#.net-coregoogle-apigoogle-api-dotnet-clientgoogle-custom-search

Why does my call to the Google Custom Search API fail with a Request Error (Invalid Argument)?


I need to get the results of google searches in order to loop through and parse them. With that aim in view, I followed (as best I could) the tutorial on how to do that here

This is my code, based on the sample/example code in the article referenced above:

private void btnRentFlick_Click(object sender, EventArgs e)
{
    OpenBestPageForSearchString("rent amazon movie Will Penny");
}

private void OpenBestPageForSearchString(string searchStr)
{
    try
    {
        const string apiKey = "blaBlaBla"; // "blaBlaBla" stands for my API key
        const string searchEngineId = "bla"; // "bla" stands for various things I tried: my client_id 
            (also called UniqueId), private_key_id (also called KeyId), and project_id. Not having 
             the correct value may be the problem. If so, how do I get it?
        const string query = "rent amazon movie Will Penny"; 
        var customSearchService = new CustomsearchService(new BaseClientService.Initializer { ApiKey 
                                                                                        = apiKey });
        //CseResource.ListRequest listRequest = customSearchService.Cse.List(query); // This is the 
          code in the article, but it won't compile - "no overload for "List" takes one argument"
        // So how is the value in "query" assigned, then?
                
        CseResource.ListRequest listRequest = customSearchService.Cse.List(); 
        listRequest.Cx = searchEngineId;

        List<string> linksReturned = new List<string>();

        IList<Result> paging = new List<Result>();
        var count = 0; // I don't know what the purpose of the counting is, but I'll leave as-is 
            until I get it working at least
        while (paging != null)
        {
            listRequest.Start = count * 10 + 1;
            paging = listRequest.Execute().Items; // this takes several seconds, then it throws an       
                                                     exception
            if (paging != null)
            {
                foreach (var item in paging)
                {
                    linksReturned.Add("Title : " + item.Title + Environment.NewLine + "Link : " + 
                        item.Link +
                        Environment.NewLine + Environment.NewLine);
                }    
            }
            count++;
        }
            MessageBox.Show("Done with google amazon query");
        }
        catch (Exception ex)
        {
            MessageBox.Show(ex.Message);
        }    
    }

As the comment at the end of that line says, this line of code:

paging = listRequest.Execute().Items; 

...works for several seconds, then throws an exception, namely this:

enter image description here

So what is causing this exception? Is it because the searchEngineId value I assigned is bad? Or is it because the search string (assigned to the query variable) has not been provided to the call?

The info about my Ids is contained in a .json file provided by google, and there is no "searchEngineId" value in it. This is what it does contain:

"type": "service_account", "project_id": "flix4famsasinlocator",
"private_key_id": "[my private key id]", "private_key": "-----BEGIN PRIVATE KEY-----. . . PRIVATE KEY-----\n", "client_email": "[bla].gserviceaccount.com", "client_id": "[my client Id]",
"auth_uri": "https://accounts.google.com/o/oauth2/auth",
"token_uri": "https://oauth2.googleapis.com/token",
"auth_provider_x509_cert_url": "https://www.googleapis.com/oauth2/v1/certs",
"client_x509_cert_url": "https://www.googleapis.com/robot/v1/metadata/x509/[bla]gserviceaccount.com"

So though the article previously mentioned purported to be, and at first appeared to be, just what the doctor ordered, I have ran into a wall of considerable dimensions. Does anybody know how to scale this wall - perhaps primarily by providing the search string to the CseResource.ListRequest object?

UPDATE

Trying DalmTo's code first, I used this (not showing his GetService() method, which I copied verbatim):

var query = "rent amazon movie Will Penny";

var service = GetService("theRainInSpainFallsMainlyOnTheDirt");

var request = service.Cse.List();

// add option values to the request here.
request.ExactTerms = query;
request.Q = query;

var response = request.ExecuteAsync();
// my contribution:
List<string> linksReturned = new List<string>();

foreach (var item in response.Result.Items)
{
    //Console.WriteLine(item.Title);
    // next two lines also mine
    MessageBox.Show(string.Format("Title: {0}; Link: {1}; ETag: {2}", item.Title, item.Link, item.ETag));
    linksReturned.Add(item.Link);
}

...but this exception was thrown while in the foreach loop:

enter image description here

UPDATE 2

Yes, this works (adapted from Trekco's answer):

const string apiKey = "gr8GooglyMoogly";
const string searchEngineId = "theRainInSpainFallsMainOnTheDirt"; 
const string query = "rent amazon movie Will Penny";
var customSearchService = new CustomsearchService(new BaseClientService.Initializer { ApiKey = apiKey });
CseResource.ListRequest listRequest = customSearchService.Cse.List();
listRequest.Cx = searchEngineId;
listRequest.Q = query;
List<string> linksReturned = new List<string>();

IList<Result> paging = new List<Result>();
var count = 0; 
while (paging != null)
{
    listRequest.Start = count * 10 + 1;
    paging = listRequest.Execute().Items; 
    if (paging != null)
    {
        foreach (var item in paging)
        {
            linksReturned.Add(item.Link);
        }
    }
    count++;
}

Solution

  • The query is not being send to google. To fix your code you need to tell the api what query to use. After listRequest.Cx = searchEngineId; add listRequest.Q = query;

    var count = 0;
    string apiKey = "THE API KEY";
    string searchEngineId = "THE SEARCH ENGIN ID";
    string query = "rent amazon movie Will Penny";
    
    var customSearchService = new CustomsearchService(new BaseClientService.Initializer
    {
        ApiKey = apiKey
    });
    
    CseResource.ListRequest listRequest = customSearchService.Cse.List();
    listRequest.Cx = searchEngineId;
    listRequest.Q = query; // <---- Add this line
    
    List<string> linksReturned = new List<string>();
    
    while (count < 10) // Google limit you to 100 records
    {
        listRequest.Start = count * 10;
        var paging = listRequest.Execute().Items; 
        
        foreach (var item in paging)
        {
            linksReturned.Add("Title : " + item.Title + Environment.NewLine + "Link : " +
                              item.Link +
                              Environment.NewLine + Environment.NewLine);
        }
    
        count++;
    }
    
    

    In your code you have a comment that you don't know what var count = 0; is for. It is to keep track on how many items you have requested.

    If you look at google's documentation you will see that they will only return 100 results max. After that they will give you a error. That error will also be the same generic message: "INVALID_ARGUMENT"

    You can review the custom search api requirements here: https://developers.google.com/custom-search/v1/reference/rest/v1/cse/list

    The searchEngineId variable is the search Engine id that you generate on the site https://www.google.com/cse/all. The documentation you followed is a bit out of date. you will find the id here:

    enter image description here