google-search-results-nodejs
Advanced tools
Comparing version 0.1.0 to 1.2.0
const client = require('https'); | ||
const querystring = require('querystring'); | ||
const LOCATION_API = "/locations.json" | ||
/*** | ||
* Google search results with SerpApi.com | ||
* Google search results with serpapi.com | ||
*/ | ||
class GoogleSearchResults { | ||
constructor(serp_api_key = null) | ||
{ | ||
if(serp_api_key != null) | ||
{ | ||
this.serp_api_key = serp_api_key; | ||
constructor(api_key = null) { | ||
if (api_key != null) { | ||
this.api_key = api_key | ||
} | ||
this.defaultTimeout = 60000 | ||
} | ||
buildUrl(parameter, output, serp_api_key) | ||
{ | ||
// build url on the fly | ||
// private | ||
buildUrl(path, parameter, output) { | ||
// Set language | ||
parameter["source"] = "nodejs" | ||
// Set format | ||
parameter["output"] = output | ||
// Add serp_api_key | ||
if(serp_api_key) | ||
{ | ||
parameter["serp_api_key"] = serp_api_key | ||
if (output != null) { | ||
parameter["output"] = output | ||
} | ||
else if(this.serp_api_key) | ||
{ | ||
parameter["serp_api_key"] = this.serp_api_key | ||
// Add api_key | ||
if(parameter["api_key"] == null) { | ||
if (this.api_key != null) { | ||
parameter["api_key"] = this.api_key | ||
} | ||
else if (path == LOCATION_API) { | ||
// skip free api | ||
} | ||
else { | ||
throw new Error("api_key is required. copy it from: https://serpapi.com/dashboard ") | ||
} | ||
} | ||
else | ||
{ | ||
throw "SERP_API_KEY is not defined" | ||
} | ||
// build url | ||
return "https://serpapi.com/search?" + querystring.stringify(parameter) | ||
return "https://serpapi.com" + path + "?" + querystring.stringify(parameter) | ||
} | ||
/*** | ||
* run google search | ||
* setTimeout | ||
* @param timeout maximum time to wait the http response in ms (default: 60000ms) | ||
*/ | ||
setTimeout(timeout) { | ||
this.defaultTimeout = timeout | ||
} | ||
/*** | ||
* execute | ||
* | ||
* @param [Map] parameter (see: serpapi.com) | ||
* @param [Function] callback | ||
* @param [String] (optional) serp api user key | ||
* @param path URL path | ||
* @param parameter query | ||
* @param callback handle next step | ||
* @param output format json|html | ||
*/ | ||
search(parameter, output, callback, serp_api_key = null) | ||
{ | ||
let url = this.buildUrl(parameter, output, serp_api_key) | ||
client.timeout = 60000 | ||
execute(path, parameter, callback, output) { | ||
let url = this.buildUrl(path, parameter, output) | ||
client.timeout = this.defaultTimeout | ||
client.get(url, (resp) => { | ||
let data = ''; | ||
let data = '' | ||
// A chunk of data has been recieved. | ||
resp.on('data', (chunk) => { | ||
data += chunk; | ||
}); | ||
data += chunk | ||
}) | ||
// The whole response has been received. Print out the result. | ||
resp.on('end', () => { | ||
if(resp.statusCode == 200) | ||
{ | ||
if (resp.statusCode == 200) { | ||
callback(data) | ||
return | ||
} | ||
throw new Error(JSON.parse(data).error) | ||
let msg = JSON.parse(data) | ||
throw new Error(msg.error) | ||
}); | ||
}).on("error", (err) => { | ||
@@ -77,32 +87,90 @@ console.log("Error: " + err.message); | ||
} | ||
/*** | ||
* json | ||
* Run raw search query | ||
* | ||
* @param [Map] parameter (see: serpapi.com) | ||
* @param [Function] callback | ||
*/ | ||
search(parameter, output, callback) { | ||
this.execute("/search", parameter, callback, output) | ||
} | ||
/*** | ||
* Provide json search result in the callback | ||
* | ||
* @param [Map] parameter | ||
* @param [Function] callback with json as argument | ||
* @param [String] serp_api_key | ||
* @param [Map] parameter query | ||
* @param [Function] callback with search result as json | ||
*/ | ||
json(parameter, callback, serp_api_key = null) | ||
{ | ||
json(parameter, callback) { | ||
this.search(parameter, "json", (data) => { | ||
callback(JSON.parse(data)) | ||
}, serp_api_key) | ||
}) | ||
} | ||
/*** | ||
* @deprecated | ||
* Provide json search result in the callback | ||
* | ||
* @param [Map] parameter query | ||
* @param [Function] callback with search result as json | ||
* @param [String] api_key | ||
*/ | ||
json(parameter, callback, api_key = null) { | ||
parameter["api_key"] = api_key | ||
this.search(parameter, "json", (data) => { | ||
callback(JSON.parse(data)) | ||
}) | ||
} | ||
/*** | ||
* html | ||
* Provide html search result in the callback | ||
* | ||
* @param [Map] parameter | ||
* @param [Function] callback with json as argument | ||
* @param [String] serp_api_key | ||
* @param [String] api_key | ||
*/ | ||
html(parameter, callback, serp_api_key = null) | ||
{ | ||
html(parameter, callback, api_key = null) { | ||
this.search(parameter, "html", (data) => { | ||
callback(data) | ||
}, serp_api_key) | ||
}, api_key) | ||
} | ||
/*** | ||
* Location API returns matching location in the callback | ||
*/ | ||
location(q, limit, callback) { | ||
let query = { | ||
q: q, | ||
limit: limit | ||
} | ||
this.execute(LOCATION_API, query, (data) => { | ||
callback(JSON.parse(data)) | ||
}, null, null) | ||
} | ||
/*** | ||
* Account API returns account information in the callback | ||
*/ | ||
account(callback) { | ||
this.execute("/account", {}, (data) => { | ||
callback(JSON.parse(data)) | ||
}, null, null) | ||
} | ||
/*** | ||
* Search Archive API returns search result from the archive | ||
* @param search_id previous search result = search_metadata.id | ||
* @param callback handle next step | ||
* @param api_key user secret key | ||
*/ | ||
search_archive(search_id, callback, api_key = null) { | ||
this.execute("/searches/" + search_id + ".json", {}, (data) => { | ||
callback(JSON.parse(data)) | ||
}, null, api_key) | ||
} | ||
} | ||
module.exports.GoogleSearchResults = GoogleSearchResults; |
{ | ||
"name": "google-search-results-nodejs", | ||
"version": "0.1.0", | ||
"version": "1.2.0", | ||
"description": "Google Search Results Node JS API via SerpApi.com", | ||
@@ -24,3 +24,8 @@ "main": "lib/GoogleSearchResults.js", | ||
"automated", | ||
"localization" | ||
"localization", | ||
"serp", | ||
"serpapi", | ||
"image", | ||
"news", | ||
"seo" | ||
], | ||
@@ -37,5 +42,3 @@ "devDependencies": { | ||
"homepage": "https://github.com/serpapi/google-search-results-nodejs#readme", | ||
"dependencies": { | ||
"npm": "^5.8.0" | ||
} | ||
"dependencies": {} | ||
} |
213
README.md
@@ -7,2 +7,11 @@ # Google Search Results Node.js | ||
This Ruby Gem is meant to scrape and parse Google results using [SerpApi](https://serpapi.com). | ||
The following services are provided: | ||
* [Search API](https://serpapi.com/search-api) | ||
* [Location API](https://serpapi.com/locations-api) | ||
* [Search Archive API](https://serpapi.com/search-archive-api) | ||
* [Account API](https://serpapi.com/account-api) | ||
Serp API provides a [script builder](https://serpapi.com/demo) to get you started quickly. | ||
[The full documentation is available here.](https://serpapi.com/search-api) | ||
@@ -18,2 +27,4 @@ | ||
NPM 7+ | ||
```bash | ||
@@ -23,8 +34,10 @@ $ npm install google-search-results-nodejs | ||
## Simple Example | ||
[Link to npm package](https://www.npmjs.com/package/google-search-results-nodejs) | ||
## Quick start | ||
```javascript | ||
var gsr = require('GoogleSearchResults') | ||
let serp = new gsr.GoogleSearchResults("Your Private Key") | ||
serp.json({ | ||
const GSR = require('google-search-results-nodejs') | ||
const client = new GSR.GoogleSearchResults("Your Private Key") | ||
client.json({ | ||
q: "Coffee", | ||
@@ -36,24 +49,47 @@ location: "Austin, TX" | ||
``` | ||
This example runs a search about "coffee" using your secret api key. | ||
## Set SERP API key | ||
The Serp API service (backend) | ||
- searches on Google using the client: q = "coffee" | ||
- parses the messy HTML responses | ||
- return a standardizes JSON response | ||
The Ruby class GoogleSearchResults | ||
- Format the request to Serp API server | ||
- Execute GET http request | ||
- Parse JSON into Ruby Hash using JSON standard library provided by Ruby | ||
Et voila.. | ||
## Example | ||
* [How to set SERP API key](#how-to-set-serp-api-key) | ||
* [Search API capability](#search-api-capability) | ||
* [Example by specification](#example-by-specification) | ||
* [Location API](#location-api) | ||
* [Search Archive API](#search-archive-api) | ||
* [Account API](#account-api) | ||
* [Promise and callback](#Promise-and-callback) | ||
* [Coding style](#coding-style) | ||
### How to set SERP API key | ||
The Serp API key can be set globally using a singleton pattern. | ||
```javascript | ||
var gsr = require('GoogleSearchResults') | ||
let serp = new gsr.GoogleSearchResults("Your Private Key") | ||
const GSR = require('google-search-results-nodejs') | ||
let client = new GSR.GoogleSearchResults("Your Private Key") | ||
``` | ||
Or | ||
The Serp API key can be provided for each request | ||
```javascript | ||
var gsr = require('GoogleSearchResults') | ||
let serp = new gsr.GoogleSearchResults() | ||
let result = serp.json({ | ||
q: "Coffee", | ||
location: "Austin, TX", | ||
const GSR = require('google-search-results-nodejs') | ||
let client = new GSR.GoogleSearchResults() | ||
let result = client.json({ | ||
api_key: "Your private key", | ||
q: "Coffee", // search query | ||
location: "Austin, TX", // location | ||
}, (data) => { | ||
console.log(data) | ||
}, "Your Private Key") | ||
}) | ||
``` | ||
## Example with all params and all outputs | ||
### Search API capability | ||
```javascript | ||
var gsr = require('GoogleSearchResults') | ||
let serp = new gsr.GoogleSearchResults() | ||
query_params = { | ||
@@ -69,6 +105,14 @@ q: "query", | ||
start: "Pagination Offset", | ||
serp_api_key: "Your SERP API Key" | ||
api_key: "Your SERP API Key", // https://serpapi.com/dashboard | ||
tbm: "nws|isch|shop", | ||
tbs: "custom to be search criteria", | ||
async: true|false, // allow async query | ||
output: "json|html", // output format | ||
} | ||
callback = function(data) { | ||
const GSR = require('google-search-results-nodejs') | ||
const client = new GSR.GoogleSearchResults() | ||
// create a callback | ||
callback = (data) => { | ||
console.log(data) | ||
@@ -78,9 +122,119 @@ } | ||
// Show result as JSON | ||
serp.json(query_params, callback) | ||
client.json(query_params, callback) | ||
// Show result as HTML file | ||
serp.html(query_params, callback) | ||
client.html(query_params, callback) | ||
``` | ||
This service supports Google Images, News, Shopping. | ||
(the full documentation)[https://serpapi.com/search-api] | ||
see below for more hands on examples. | ||
### Example by specification | ||
We love true open source, continuous integration and Test Drive Development (TDD). | ||
We are using RSpec to test [our infrastructure around the clock](https://travis-ci.org/serpapi/google-search-results-ruby) to achieve the best QoS (Quality Of Service). | ||
The directory test/ includes specification/examples. | ||
Set your api key. | ||
```bash | ||
export API_KEY="your secret key" | ||
``` | ||
Run all tests | ||
```npm test``` | ||
### Location API | ||
```javascript | ||
const client = new GSR.GoogleSearchResults(api_key) | ||
client.location("Austin", 3, (data) => { | ||
console.log(data) | ||
}) | ||
``` | ||
it prints the first 3 location matching Austin (Texas, Texas, Rochester) | ||
```javascript | ||
[ { id: '585069bdee19ad271e9bc072', | ||
google_id: 200635, | ||
google_parent_id: 21176, | ||
name: 'Austin, TX', | ||
canonical_name: 'Austin,TX,Texas,United States', | ||
country_code: 'US', | ||
target_type: 'DMA Region', | ||
reach: 5560000, | ||
gps: [ -97.7430608, 30.267153 ], | ||
keys: [ 'austin', 'tx', 'texas', 'united', 'states' ] }, | ||
...] | ||
``` | ||
### Search Archive API | ||
The first search result returns a search_id which can be provided to get the search result from the archive. | ||
```javascript | ||
var client = new GSR.GoogleSearchResults(api_key) | ||
client.json({q: "Coffee", location: "Portland" }, (search_result) => { | ||
// search in archive for the search just returned | ||
client.search_archive(search_result.search_metadata.id, (archived_search) => { | ||
console.log(archived_search) | ||
}) | ||
}) | ||
``` | ||
it prints the search from the archive. | ||
### Account API | ||
```javascript | ||
const client = new GSR.GoogleSearchResults(api_key) | ||
client.account((data) => { | ||
console.log(data) | ||
}) | ||
``` | ||
it prints your account information. | ||
## Promise and callback | ||
This API was developped using basic callback to handle response. | ||
And exception are just throw away with interceptor. | ||
if you want to take advantage of the promise to block the request. | ||
here is how I will do. | ||
```javascript | ||
const util = require('util') | ||
function getJson(parameter, resolve, reject) { | ||
const client = new gsr.GoogleSearchResults(api_key) | ||
try { | ||
client.json(parameter, resolve) | ||
} catch (e) { | ||
reject(e) | ||
} | ||
} | ||
const blockFn = util.promisify(getJson) | ||
blockFn[util.promisify.custom](parameter).then((data) => { | ||
expect(data.local_results[0].title.length).toBeGreaterThan(5) | ||
done() | ||
}).catch((error) => { | ||
console.error(error) | ||
done() | ||
}) | ||
``` | ||
Reference: | ||
* test: test/ExampleSpec.js | ||
* documentation: https://nodejs.org/docs/latest-v8.x/api/util.html#util_util_promisify_original | ||
## Coding style | ||
This API is using callback to run in non-blocking code. | ||
Here we are trying to follow the spirit of NodeJS. | ||
For reference you can read this article: | ||
* https://nodejs.org/en/docs/guides/blocking-vs-non-blocking/ | ||
* https://nodejs.org/en/docs/guides/dont-block-the-event-loop/ | ||
For pratical example, you can see the test located under test/. | ||
## Conclusion | ||
Serp API supports Google Images, News, Shopping and more.. | ||
To enable a type of search, the field tbm (to be matched) must be set to: | ||
@@ -92,6 +246,17 @@ | ||
* any other Google service should work out of the box. | ||
* (no tbm parameter): regular Google Search. | ||
* (no tbm parameter): regular Google client. | ||
The field `tbs` allows to customize the search even more. | ||
[The full documentation is available here.](https://serpapi.com/search-api) | ||
For pratical example, you can see the test located under test/. | ||
## Contributing | ||
Contributions are welcome, feel to submit a pull request! | ||
To run the tests: | ||
```bash | ||
export API_KEY="your api key" | ||
make test | ||
``` |
@@ -1,33 +0,40 @@ | ||
var expect = require('expect'); | ||
var gsr = require('./../lib/GoogleSearchResults'); | ||
const expect = require('expect'); | ||
const GSR = require('./../lib/GoogleSearchResults'); | ||
describe('Google Search Results', function() | ||
{ | ||
let p; | ||
beforeEach(function() | ||
{ | ||
p = {q: "Coffee", location: "Austin, Texas"} | ||
describe('Google Search Results', () => { | ||
let p, api_key; | ||
beforeEach(() => { | ||
p = { | ||
q: "Coffee", | ||
location: "Austin, Texas" | ||
} | ||
// Copy your secret api_key from https://serpapi.com/dashboard | ||
api_key = process.env.API_KEY || "demo" | ||
}); | ||
it('fail:buildUrl', () => { | ||
let serp = new gsr.GoogleSearchResults() | ||
it('fail:buildUrl', (done) => { | ||
let client = new GSR.GoogleSearchResults() | ||
expect(() => { | ||
serp.buildUrl({}, "json", null) | ||
}).toThrow(/SERP_API/) | ||
client.buildUrl('/path', {}, "json", null) | ||
}).toThrow(/api_key/) | ||
done() | ||
}) | ||
it('buildUrl', function() { | ||
let serp = new gsr.GoogleSearchResults() | ||
expect(serp.buildUrl(p, "json", "demo")).toBe("https://serpapi.com/search?q=Coffee&location=Austin%2C%20Texas&source=nodejs&output=json&serp_api_key=demo") | ||
it('buildUrl', (done) => { | ||
let client = new GSR.GoogleSearchResults('demo') | ||
expect(client.buildUrl('/path', {q: 'Coffee', location: 'Austin, Texas', api_key: 'beta'}, "json")).toMatch(/https:\/\/serpapi.com\/path\?q=Coffee&location=Austin%2C%20Texas&api_key=beta&source=nodejs&output=json/) | ||
done() | ||
}) | ||
it('buildUrl with key in constructor', function() { | ||
let serp = new gsr.GoogleSearchResults("demo") | ||
expect(serp.buildUrl(p, "json")).toBe("https://serpapi.com/search?q=Coffee&location=Austin%2C%20Texas&source=nodejs&output=json&serp_api_key=demo") | ||
it('buildUrl without api_key', (done) => { | ||
let client = new GSR.GoogleSearchResults('demo') | ||
expect(client.buildUrl('/path', {q: 'Coffee', location: 'Austin, Texas'}, "json")).toMatch(/https:\/\/serpapi.com\/path\?q=Coffee&location=Austin%2C%20Texas&source=nodejs&output=json&api_key=demo/) | ||
done() | ||
}) | ||
it("search", (done) => { | ||
let serp = new gsr.GoogleSearchResults("demo") | ||
serp.search(p, "json", (raw) => { | ||
let client = new GSR.GoogleSearchResults(api_key) | ||
client.setTimeout(6000); | ||
client.search(p, "json", (raw) => { | ||
let data = JSON.parse(raw) | ||
@@ -38,6 +45,6 @@ expect(data.local_results[0].title.length).toBeGreaterThan(5) | ||
}) | ||
it("json", (done) => { | ||
let serp = new gsr.GoogleSearchResults("demo") | ||
serp.json(p, (data) => { | ||
let client = new GSR.GoogleSearchResults(api_key) | ||
client.json(p, (data) => { | ||
expect(data.local_results[0].title.length).toBeGreaterThan(5) | ||
@@ -47,6 +54,6 @@ done() | ||
}) | ||
it("html", (done) => { | ||
let serp = new gsr.GoogleSearchResults("demo") | ||
serp.html(p, (body) => { | ||
let client = new GSR.GoogleSearchResults(api_key) | ||
client.html(p, (body) => { | ||
expect(body).toMatch(/<\/html>/) | ||
@@ -56,13 +63,15 @@ done() | ||
}) | ||
it("fail:json", () => { | ||
let serp = new gsr.GoogleSearchResults("demo") | ||
xit("fail:json", (done) => { | ||
try { | ||
serp.json({}, (data) => { | ||
let client = new GSR.GoogleSearchResults(api_key) | ||
let fn = (data) => { | ||
done() | ||
}) | ||
} catch(ex) { | ||
} | ||
client.json({}, fn) | ||
} catch (ex) { | ||
expect(ex.message).toBe("Error: Missing query `q` parameter") | ||
done() | ||
} | ||
}) | ||
}); |
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
Environment variable access
Supply chain riskPackage accesses environment variables, which may be a sign of credential stuffing or data theft.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
No v1
QualityPackage is not semver >=1. This means it is not stable and does not support ^ ranges.
Found 1 instance in 1 package
17813
0
10
332
0
255
6
2
- Removednpm@^5.8.0
- Removednpm@5.10.0(transitive)