Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Google Search with Alamofire Fails (iOS, Swift, JSON, HTML)

Please help! I'm stuck for months now trying to perform a simple Google Search on my Swift App and I'm way past smashing my head through the wall!

I've tried both with ALAMOFIRE and With a Regular URLRequest, but since the result seems to be only in HTML Format, I Can't seem to parse the results correctly. Even when you look into the HTML Format, the code is for a Webpage, and it does NOT Include the Search Results.

I Would LOVE to have the search Results into a Simple Dictionary. Here is my Code:

        let googleUrl:String = "https://cse.google.com/cse/publicurl?&output=json&cx=<MyGoogleKey>:<MyGoogleSKey>&q=q=+normal+search"

        // Trying with AlamoFire:

        Alamofire.request(googleUrl).response { response in
            print("Request: \(response.request)")
            print("Response: \(response.response)")
            print("Error: \(response.error)")
        }.responseJSON(completionHandler: { response in
             print("ResponseJSON: \(response)")
        }).responseData(completionHandler: { response in
              print("ResponseData: \(response)")
        }).responseString(completionHandler: { response in
              print("ResponseString: \(response)")
        })

As you See I Try the Response in almost ALL Alamofire supported Types and I GEt NOTHING.

Here is Error #1 (.responseJSON):

The data couldn’t be read because it isn’t in the correct format. ResponseJSON: FAILURE: responseSerializationFailed(Alamofire.AFError.ResponseSerializationFailureReason.jsonSerializationFailed(Error Domain=NSCocoaErrorDomain Code=3840 "Invalid value around character 0." UserInfo={NSDebugDescription=Invalid value around character 0.}))

Here is DATA Response (.responseData): ResponseData: SUCCESS: 4337 bytes

Here is the Response HTML (.responseString)

ResponseString: SUCCESS:

*> Google Custom Search

(function(){var cookie_path='/cse/';var path_copy='/coop/';window._gaq = window._ga...._AND_SO_ON_TILL_FULL_HTML_PAGE_IN_A_STRING....*

* I Only wish I Could have the Search Results in a Simple Dictionary...

Anyone? Please?

like image 576
Hernan Arber Avatar asked Apr 29 '17 20:04

Hernan Arber


1 Answers

You seem to be using the Custom Search API for embedding into web pages.

This documentation is for what you want to do.

Here is an example using stack overflow as the search domain.

import UIKit
import Alamofire

class ViewController: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()

        search(query: "swift") { (results) in

            for result in results {

                dump(result)
            }
        }
    }

    func search(query:String, completion: @escaping (Array<SearchResult>)->()){

        let id = "Custom search engine ID"

        let key = "API key"

        let url = "https://www.googleapis.com/customsearch/v1?key=\(key)&cx=\(id)&q=\(query)"

        Alamofire.request(url).responseJSON { (response) in

            var results = Array<SearchResult>()

            if let dict = response.value as? Dictionary<String,Any> {

                if let items = dict["items"] as? Array<Dictionary<String,Any>> {

                    for item in items {

                        if let result = SearchResult(dict: item) {

                            results.append(result)

                        } else {

                            print("Incomplete search result data.")
                        }
                    }
                }
            }

            completion(results)
        }
    }
}

I have this struct to store the search results better. It doesn't contain all the values that the JSON results does. I just chose these ones for testing.

struct SearchResult {

    var displayLink: String

    var formattedUrl: String

    var htmlFormattedUrl: String

    var htmlSnippet: String

    var htmlTitle: String

    var link: String

    var snippet: String

    var title: String

    init?(dict:Dictionary<String,Any>) {

        guard

            let displayLink = dict["displayLink"] as? String,

            let formattedUrl = dict["formattedUrl"] as? String,

            let htmlFormattedUrl = dict["htmlFormattedUrl"] as? String,

            let htmlSnippet = dict["htmlSnippet"] as? String,

            let htmlTitle = dict["htmlTitle"] as? String,

            let link = dict["link"] as? String,

            let snippet = dict["snippet"] as? String,

            let title = dict["title"] as? String

        else {

            return nil
        }

        self.displayLink = displayLink

        self.formattedUrl = formattedUrl

        self.htmlFormattedUrl = htmlFormattedUrl

        self.htmlSnippet = htmlSnippet

        self.htmlTitle = htmlTitle

        self.link = link

        self.snippet = snippet

        self.title = title
    }
}

This is a couple of results that dump(result) prints out.

▿ CustomGoogleSearch.SearchResult
  - displayLink: "stackoverflow.com"
  - formattedUrl: "https://stackoverflow.com/questions/tagged/swift"
  - htmlFormattedUrl: "https://stackoverflow.com/questions/tagged/<b>swift</b>"
  - htmlSnippet: "<b>Swift</b> is an open-source programming language developed by Apple. Use the tag <br>\nonly for questions about language features, or requiring code in <b>Swift</b>. Use the&nbsp;..."
  - htmlTitle: "Newest &#39;<b>swift</b>&#39; Questions - Stack Overflow"
  - link: "https://stackoverflow.com/questions/tagged/swift"
  - snippet: "Swift is an open-source programming language developed by Apple. Use the tag \nonly for questions about language features, or requiring code in Swift. Use the ..."
  - title: "Newest \'swift\' Questions - Stack Overflow"

▿ CustomGoogleSearch.SearchResult
  - displayLink: "stackoverflow.com"
  - formattedUrl: "stackoverflow.com/documentation/swift/topics"
  - htmlFormattedUrl: "stackoverflow.com/documentation/<b>swift</b>/topics"
  - htmlSnippet: "58 example-focused documentation topics for <b>Swift</b> Language."
  - htmlTitle: "All <b>Swift</b> Language Topics - Stack Overflow"
  - link: "http://stackoverflow.com/documentation/swift/topics"
  - snippet: "58 example-focused documentation topics for Swift Language."
  - title: "All Swift Language Topics - Stack Overflow"

Getting the keys

On this page, click the Get A Key button.

Get API Key Button

You then need to select or create a Google project, then you will be generated an API Key. So copy this an put in here let key = "API key"

For the Search Engine ID, go to your console. Now either select a search engine or create a new one. You'll get to a page like this.

Google Custom Search Engine Settings Page

Click the Search engine ID button, this will display a screen with your id, then put that here let id = "Custom search engine ID"

like image 178
Tristan Beaton Avatar answered Oct 11 '22 23:10

Tristan Beaton