From 0548d69d9a301af486c1654fa00c53d4323a7351 Mon Sep 17 00:00:00 2001 From: Patrick Trasborg Date: Fri, 11 Mar 2016 10:16:40 -0500 Subject: [PATCH 1/2] obtaining trend data for a keyword --- examples.js | 27 +++++++++++++++++++++------ src/resources/htmlParser.js | 15 ++++++++++++++- src/utils/index.js | 1 + src/utils/topRelated.js | 2 +- src/utils/trendData.js | 30 ++++++++++++++++++++++++++++++ 5 files changed, 67 insertions(+), 8 deletions(-) create mode 100644 src/utils/trendData.js diff --git a/examples.js b/examples.js index 7aa9c23..672b9f2 100644 --- a/examples.js +++ b/examples.js @@ -1,9 +1,24 @@ +'use strict'; + var googleTrends = require(__dirname + '/'); var util = require('util'); //uncomment the code within each example to run it - /* ~=~=~=~=~=~=~=~=~=~= EXAMPLE 1 =~=~=~=~=~=~=~=~=~=~ */ +/* ~=~=~=~=~=~=~=~=~=~= trendData =~=~=~=~=~=~=~=~=~=~ */ +// // Parameters: array of key words (required) +// // optionally as the first argument pass an object: {keywords: ['dog']} +// googleTrends.trendData({keywords: 'OJ Simpson'}) +// .then(function(trendData){ +// console.log("here is the trendData", trendData); +// }) +// .catch(function(err){ +// console.log("there was an error", err); +// return err; +// }); + + +/* ~=~=~=~=~=~=~=~=~=~= EXAMPLE 2 =~=~=~=~=~=~=~=~=~=~ */ /* ~=~=~=~=~=~=~=~=~=~= topRelated =~=~=~=~=~=~=~=~=~=~ */ // // Parameters: array of key words (required), country as a string (optional, 'US' is default) // // optionally as the first argument pass an object: {keywords: ['dog'], geo: 'US'} @@ -18,7 +33,7 @@ var util = require('util'); -/* ~=~=~=~=~=~=~=~=~=~= EXAMPLE 2 =~=~=~=~=~=~=~=~=~=~ */ +/* ~=~=~=~=~=~=~=~=~=~= EXAMPLE 3 =~=~=~=~=~=~=~=~=~=~ */ /* ~=~=~=~=~=~=~=~=~=~= hotTrends =~=~=~=~=~=~=~=~=~=~ */ // //Parameters: takes a country as a string (optional, 'US' is default) // // optionally as the first argument pass an object: {geo: 'US'} @@ -31,7 +46,7 @@ var util = require('util'); // }); -/* ~=~=~=~=~=~=~=~=~=~= EXAMPLE 3 =~=~=~=~=~=~=~=~=~=~ */ +/* ~=~=~=~=~=~=~=~=~=~= EXAMPLE 4 =~=~=~=~=~=~=~=~=~=~ */ /* ~=~=~=~=~=~=~=~=~=~= hotTrendsDetail =~=~=~=~=~=~=~=~=~=~ */ // //Parameters: takes a country as a string (optional, 'US' is default) // // optionally as the first argument pass an object: {geo: 'US'} @@ -44,7 +59,7 @@ var util = require('util'); // }); -/* ~=~=~=~=~=~=~=~=~=~= EXAMPLE 4 =~=~=~=~=~=~=~=~=~=~ */ +/* ~=~=~=~=~=~=~=~=~=~= EXAMPLE 5 =~=~=~=~=~=~=~=~=~=~ */ /* ~=~=~=~=~=~=~=~=~=~= top30in30 =~=~=~=~=~=~=~=~=~=~ */ // //Parameters: none // googleTrends.top30in30() @@ -57,7 +72,7 @@ var util = require('util'); -/* ~=~=~=~=~=~=~=~=~=~= EXAMPLE 5 =~=~=~=~=~=~=~=~=~=~ */ +/* ~=~=~=~=~=~=~=~=~=~= EXAMPLE 6 =~=~=~=~=~=~=~=~=~=~ */ /* ~=~=~=~=~=~=~=~=~=~= allTopCharts =~=~=~=~=~=~=~=~=~=~ */ // // Parameters: date in format yyyymm where January is 01 (optional, today's date is default), country code as string (optional, 'US' is default) // // optionally as the first argument pass an object: {geo: 'US', date: '201601'} @@ -71,7 +86,7 @@ var util = require('util'); -/* ~=~=~=~=~=~=~=~=~=~= EXAMPLE 6 =~=~=~=~=~=~=~=~=~=~ */ +/* ~=~=~=~=~=~=~=~=~=~= EXAMPLE 7 =~=~=~=~=~=~=~=~=~=~ */ /* ~=~=~=~=~=~=~=~=~=~= categoryTopCharts =~=~=~=~=~=~=~=~=~=~ */ // //Parameters: category (required), date in format yyyymm where January is 01 (optional, today's date is default), country code as string (optional, 'US' is default) // // optionally as the first argument pass an object: {category: 'actors', geo: 'US', date:'201601'} diff --git a/src/resources/htmlParser.js b/src/resources/htmlParser.js index fc617a7..dc85d59 100644 --- a/src/resources/htmlParser.js +++ b/src/resources/htmlParser.js @@ -30,4 +30,17 @@ function removeWhiteSpace(arr){ }, []); } -module.exports = parseHtml; \ No newline at end of file +function parseJSON(htmlString){ + var dates = htmlString.match(/\"f\"\:\"\w+ \d{4}\"/g); + var data = htmlString.match(/\"f\"\:\"\d+\"/g); + + return dates.reduce(function(acc, curr, index){ + acc.push({date: curr.split('"')[3], value: data[index].split('"')[3]}); + return acc; + },[]); +} + +module.exports = { + parseHtml: parseHtml, + parseJSON: parseJSON +}; \ No newline at end of file diff --git a/src/utils/index.js b/src/utils/index.js index 07bc9d8..bfa2015 100644 --- a/src/utils/index.js +++ b/src/utils/index.js @@ -1,4 +1,5 @@ module.exports = { + trendData: require(__dirname + '/trendData.js'), topRelated: require(__dirname + '/topRelated.js'), hotTrends: require(__dirname + '/hotTrends.js'), hotTrendsDetail: require(__dirname + '/hotTrendsDetail.js'), diff --git a/src/utils/topRelated.js b/src/utils/topRelated.js index 6fae4ea..ed543b5 100644 --- a/src/utils/topRelated.js +++ b/src/utils/topRelated.js @@ -3,7 +3,7 @@ var rp = require('request-promise'); var createObj = require(__dirname + '/../resources/callbacks.js'); var checkErrors = require(__dirname + '/../resources/errorHandling.js'); -var parseHtml = require(__dirname + '/../resources/htmlParser.js'); +var parseHtml = require(__dirname + '/../resources/htmlParser.js').parseHtml; module.exports = function request(keywords, geo, cbFunc){ var obj = createObj(arguments, request); diff --git a/src/utils/trendData.js b/src/utils/trendData.js new file mode 100644 index 0000000..ace7a01 --- /dev/null +++ b/src/utils/trendData.js @@ -0,0 +1,30 @@ +'use strict'; + +var rp = require('request-promise'); +var createObj = require(__dirname + '/../resources/callbacks.js'); +var checkErrors = require(__dirname + '/../resources/errorHandling.js'); +var parseJSON = require(__dirname + '/../resources/htmlParser.js').parseJSON; + +module.exports = function request(keywords, cbFunc){ + var obj = createObj(arguments, request); + + var error = checkErrors(obj); + if(error instanceof Error) return Promise.reject(obj.cbFunc(error)); + + return Promise.all(promiseArr(obj.keywords)) + .then(function(results){ + return obj.cbFunc(null, results); + }) + .catch(function(err){ + return Promise.reject(obj.cbFunc(err)); + }); +}; + +function promiseArr(keywords){ + return keywords.map(function(keyword){ + return rp(`http://www.google.com/trends/fetchComponent?q="${keyword}"&cid=TIMESERIES_GRAPH_0&export=3`) + .then(function(htmlString){ + return parseJSON(htmlString); + }); + }); +} \ No newline at end of file From 43e1db44bbd64dba03eb116d63af7f08a0b21dde Mon Sep 17 00:00:00 2001 From: Patrick Trasborg Date: Fri, 11 Mar 2016 10:44:25 -0500 Subject: [PATCH 2/2] updated README and adding tests for htmlParser and trendData --- README.md | 58 +++++++++++++++++++++++++++++-- src/resources/htmlParser.js | 6 ++-- test/resources/htmlParser.test.js | 25 +++++++++++++ test/resources/index.js | 7 ++-- test/utils/index.js | 1 + test/utils/topRelated.test.js | 3 ++ test/utils/trendData.test.js | 15 ++++++++ 7 files changed, 108 insertions(+), 7 deletions(-) create mode 100644 test/resources/htmlParser.test.js create mode 100644 test/utils/trendData.test.js diff --git a/README.md b/README.md index fdd3e9d..ffd6ee3 100644 --- a/README.md +++ b/README.md @@ -38,6 +38,7 @@ googleTrends.apiMethod(options) * [Callbacks](#callbacks) * [Examples](#examples) * [API Methods](#api-methods) + * [trendData](#trenddata) * [topRelated](#toprelated) * [hotTrends](#hottrends) * [hotTrendsDetail](#hottrendsdetail) @@ -121,6 +122,7 @@ The examples shown for each API method can be run by changing into the home `goo ### API Methods The following API methods are available: +* [trendData](#trenddata): returns the historical trend data to a provided keyword or an array of keywords. * [topRelated](#toprelated): returns the top related keywords to a provided keyword or an array of keywords along with it's percentage of correlation. * [hotTrends](#hottrends): returns the current top 20 trending searches for a given location. * [hotTrendsDetail](#hottrendsdetail): same as the [hotTrends](#hottrends) results except with more detail such as links, publication date, approximate traffic, etc. @@ -139,6 +141,58 @@ For each of the API methods, rather than providing the parameters to the functio
+#### trendData() +*Returns the historical trend data to a provided keyword or an array of keywords.* + +#####Syntax +`googleTrends.trendData(['keywords'])` + +* `['keywords']` - either an array of keywords as strings or a string with one keyword. If keywords is an array, the results will be returned in an array of the same order as the input. Entering a keyword is **required**. + +#####Example +The following example provides the historical trend data for 'OJ Simpson'. Optionally, the input could have been provided as `googleTrends.trendData({keywords: 'OJ Simpson'})`. Any other keys provided in the object will be ignore. + +######Input +```js +googleTrends.trendData('OJ Simpson') +.then(function(results){ + console.log(results); +}) +.catch(function(err){ + console.error(err); +}); +``` + +######Output +```js +[ [ { 'May 2014': '10' }, + { 'June 2014': '3' }, + { 'July 2014': '3' }, + { 'August 2014': '3' }, + { 'September 2014': '5' }, + { 'October 2014': '4' }, + { 'November 2014': '3' }, + { 'December 2014': '4' }, + { 'January 2015': '4' }, + { 'February 2015': '3' }, + { 'March 2015': '4' }, + { 'April 2015': '4' }, + { 'May 2015': '4' }, + { 'June 2015': '3' }, + { 'July 2015': '3' }, + { 'August 2015': '8' }, + { 'September 2015': '12' }, + { 'October 2015': '5' }, + { 'November 2015': '7' }, + { 'December 2015': '14' }, + { 'January 2016': '72' }, + { 'February 2016': '100' } ] ] +``` + +[back to top](#introduction) + +
+ #### topRelated() *Returns the top related keywords for a provided keyword or an array of keywords* @@ -156,10 +210,10 @@ The following example provides the top related keywords to 'dog house' in the 'U ```js googleTrends.topRelated('dog house', 'US') .then(function(results){ - console.log(results); + console.log(results); }) .catch(function(err){ - console.error(err); + console.error(err); }); ``` diff --git a/src/resources/htmlParser.js b/src/resources/htmlParser.js index dc85d59..d720fac 100644 --- a/src/resources/htmlParser.js +++ b/src/resources/htmlParser.js @@ -35,8 +35,10 @@ function parseJSON(htmlString){ var data = htmlString.match(/\"f\"\:\"\d+\"/g); return dates.reduce(function(acc, curr, index){ - acc.push({date: curr.split('"')[3], value: data[index].split('"')[3]}); - return acc; + var obj = {}; + obj[curr.split('"')[3]] = data[index].split('"')[3]; + acc.push(obj); + return acc; },[]); } diff --git a/test/resources/htmlParser.test.js b/test/resources/htmlParser.test.js new file mode 100644 index 0000000..8a3404c --- /dev/null +++ b/test/resources/htmlParser.test.js @@ -0,0 +1,25 @@ +'use strict'; + +var chai = require('chai'); +var chaiAsPromised = require('chai-as-promised'); +chai.use(chaiAsPromised); +var expect = chai.expect; +var assert = chai.assert; + +var htmlParser = require(__dirname + '/../../lib/resources/htmlParser.js'); + +module.exports = +describe('htmlParser.test.js', function(){ + + describe('htmlParser.parseHtml', function(){ + it('has method', function(){ + assert.isFunction(htmlParser.parseHtml); + }); + }); + + describe('htmlParse.parseJSON', function(){ + it('has method', function(){ + assert.isFunction(htmlParser.parseJSON); + }); + }); +}); \ No newline at end of file diff --git a/test/resources/index.js b/test/resources/index.js index 6412a2c..9fb6280 100644 --- a/test/resources/index.js +++ b/test/resources/index.js @@ -1,8 +1,9 @@ 'use strict'; module.exports = { - dateValidate: require(__dirname + '/dateValidate.test.js'), - countryCodes: require(__dirname + '/countryCodes.test.js'), callbacks: require(__dirname + '/callbacks.test.js'), - errorHandling: require(__dirname + '/errorHandling.test.js') + countryCodes: require(__dirname + '/countryCodes.test.js'), + dateValidate: require(__dirname + '/dateValidate.test.js'), + errorHandling: require(__dirname + '/errorHandling.test.js'), + htmlParser: require(__dirname + '/htmlParser.test.js') }; \ No newline at end of file diff --git a/test/utils/index.js b/test/utils/index.js index d91e5e2..9cc84ab 100644 --- a/test/utils/index.js +++ b/test/utils/index.js @@ -7,4 +7,5 @@ module.exports = { hotTrendsDetail: require(__dirname + '/hotTrendsDetail.test.js'), top30in30: require(__dirname + '/top30in30.test.js'), topRelated: require(__dirname + '/topRelated.test.js'), + trendData: require(__dirname + '/trendData.test.js') }; \ No newline at end of file diff --git a/test/utils/topRelated.test.js b/test/utils/topRelated.test.js index 3b8ddb6..d077760 100644 --- a/test/utils/topRelated.test.js +++ b/test/utils/topRelated.test.js @@ -12,4 +12,7 @@ describe('topRelated.js', function(){ it('should reject if country is invalid', function(){ return topRelated('dogs', 'ZZ').should.be.rejectedWith('Could not locate country'); }); + it('should reject if no keyword is provided', function(){ + return topRelated().should.be.rejectedWith('Keywords must be provided'); + }); }); \ No newline at end of file diff --git a/test/utils/trendData.test.js b/test/utils/trendData.test.js new file mode 100644 index 0000000..4f08293 --- /dev/null +++ b/test/utils/trendData.test.js @@ -0,0 +1,15 @@ +'use strict'; + +var chai = require('chai'); +var chaiAsPromised = require('chai-as-promised'); +chai.use(chaiAsPromised); +var should = chai.should(); + +var trendData = require(__dirname + '/../../lib/utils/trendData.js'); + +module.exports = +describe('trendData.js', function(){ + it('should reject if no keyword is provided', function(){ + return trendData().should.be.rejectedWith('Keywords must be provided'); + }); +}); \ No newline at end of file