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

Viewed 1435

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++;
}
2 Answers

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

If you check the doucmntation cse.list I think you will find that the list method has no required fields which means that you need to add the option values in the following manner.

I think ExactTerms may be the one you are looking for. But it could also be Q i think you should read though the option values and decide which one is best for your purpose.

        var query = "rent amazon movie Will Penny";
        
        var service = GetService("MYKEY");

        var request = service.Cse.List();

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


        var response = request.ExecuteAsync();

        foreach (var item in response.Result.Items)
        {
            Console.WriteLine(item.Title);
        }

My get service method

  public static CustomsearchService GetService(string apiKey)
    {
        try
        {
            if (string.IsNullOrEmpty(apiKey))
                throw new ArgumentNullException("api Key");

            return new CustomsearchService(new BaseClientService.Initializer()
            {
                ApiKey = apiKey,
                ApplicationName = string.Format("{0} API key example", System.Diagnostics.Process.GetCurrentProcess().ProcessName),
            });
        }
        catch (Exception ex)
        {
            throw new Exception("Failed to create new Customsearch Service", ex);
        }
    }
Related