@shaivpidadi/trends-js 0.0.0-beta.3 → 0.0.0-beta.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +34 -34
- package/lib/constants.js +1 -1
- package/lib/helpers/googleTrendsAPI.d.ts +1 -1
- package/lib/helpers/googleTrendsAPI.js +46 -23
- package/lib/helpers/request.d.ts +5 -1
- package/lib/helpers/request.js +67 -2
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -105,11 +105,14 @@ Get interest data by region:
|
|
|
105
105
|
|
|
106
106
|
```typescript
|
|
107
107
|
const result = await GoogleTrendsApi.interestByRegion({
|
|
108
|
-
keyword: 'Stock Market',
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
108
|
+
keyword: 'Stock Market', // Required - string or string[]
|
|
109
|
+
startTime: new Date('2024-01-01'), // Optional - defaults to 2004-01-01
|
|
110
|
+
endTime: new Date(), // Optional - defaults to current date
|
|
111
|
+
geo: 'US', // Optional - string or string[] - defaults to 'US'
|
|
112
|
+
resolution: 'REGION', // Optional - 'COUNTRY' | 'REGION' | 'CITY' | 'DMA'
|
|
113
|
+
hl: 'en-US', // Optional - defaults to 'en-US'
|
|
114
|
+
timezone: -240, // Optional - defaults to local timezone
|
|
115
|
+
category: 0 // Optional - defaults to 0
|
|
113
116
|
});
|
|
114
117
|
|
|
115
118
|
// Result structure:
|
|
@@ -121,12 +124,28 @@ const result = await GoogleTrendsApi.interestByRegion({
|
|
|
121
124
|
// value: number[],
|
|
122
125
|
// formattedValue: string[],
|
|
123
126
|
// maxValueIndex: number,
|
|
124
|
-
// hasData: boolean[]
|
|
127
|
+
// hasData: boolean[],
|
|
128
|
+
// coordinates?: {
|
|
129
|
+
// lat: number,
|
|
130
|
+
// lng: number
|
|
131
|
+
// }
|
|
125
132
|
// }>
|
|
126
133
|
// }
|
|
127
134
|
// }
|
|
128
135
|
```
|
|
129
136
|
|
|
137
|
+
Example with multiple keywords and regions:
|
|
138
|
+
|
|
139
|
+
```typescript
|
|
140
|
+
const result = await GoogleTrendsApi.interestByRegion({
|
|
141
|
+
keyword: ['wine', 'peanuts'],
|
|
142
|
+
geo: ['US-CA', 'US-VA'],
|
|
143
|
+
startTime: new Date('2024-01-01'),
|
|
144
|
+
endTime: new Date(),
|
|
145
|
+
resolution: 'CITY'
|
|
146
|
+
});
|
|
147
|
+
```
|
|
148
|
+
|
|
130
149
|
## API Reference
|
|
131
150
|
|
|
132
151
|
### DailyTrendsOptions
|
|
@@ -164,11 +183,14 @@ interface ExploreOptions {
|
|
|
164
183
|
|
|
165
184
|
```typescript
|
|
166
185
|
interface InterestByRegionOptions {
|
|
167
|
-
keyword: string;
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
186
|
+
keyword: string | string[]; // Required - search term(s)
|
|
187
|
+
startTime?: Date; // Optional - start date
|
|
188
|
+
endTime?: Date; // Optional - end date
|
|
189
|
+
geo?: string | string[]; // Optional - geocode(s)
|
|
190
|
+
resolution?: 'COUNTRY' | 'REGION' | 'CITY' | 'DMA'; // Optional
|
|
191
|
+
hl?: string; // Optional - language code
|
|
192
|
+
timezone?: number; // Optional - timezone offset
|
|
193
|
+
category?: number; // Optional - category number
|
|
172
194
|
}
|
|
173
195
|
```
|
|
174
196
|
|
|
@@ -176,26 +198,4 @@ interface InterestByRegionOptions {
|
|
|
176
198
|
|
|
177
199
|
### Building
|
|
178
200
|
|
|
179
|
-
```
|
|
180
|
-
npm run build
|
|
181
|
-
```
|
|
182
|
-
|
|
183
|
-
### Testing
|
|
184
|
-
|
|
185
|
-
```bash
|
|
186
|
-
npm test
|
|
187
|
-
```
|
|
188
|
-
|
|
189
|
-
### Linting
|
|
190
|
-
|
|
191
|
-
```bash
|
|
192
|
-
npm run lint
|
|
193
|
-
```
|
|
194
|
-
|
|
195
|
-
## License
|
|
196
|
-
|
|
197
|
-
MIT
|
|
198
|
-
|
|
199
|
-
## Author
|
|
200
|
-
|
|
201
|
-
Shaishav Pidadi
|
|
201
|
+
```
|
package/lib/constants.js
CHANGED
|
@@ -23,7 +23,7 @@ exports.GOOGLE_TRENDS_MAPPER = {
|
|
|
23
23
|
},
|
|
24
24
|
["explore" /* GoogleTrendsEndpoints.explore */]: {
|
|
25
25
|
path: '/trends/api/explore',
|
|
26
|
-
method: '
|
|
26
|
+
method: 'POST',
|
|
27
27
|
host: GOOGLE_TRENDS_BASE_URL,
|
|
28
28
|
url: `https://${GOOGLE_TRENDS_BASE_URL}/trends/api/explore`,
|
|
29
29
|
headers: {},
|
|
@@ -4,7 +4,7 @@ export declare class GoogleTrendsApi {
|
|
|
4
4
|
dailyTrends({ geo, lang }: DailyTrendingTopicsOptions): Promise<DailyTrendingTopics>;
|
|
5
5
|
realTimeTrends({ geo, trendingHours }: RealTimeTrendsOptions): Promise<DailyTrendingTopics>;
|
|
6
6
|
explore({ keyword, geo, time, category, property, hl, }: ExploreOptions): Promise<ExploreResponse>;
|
|
7
|
-
interestByRegion({ keyword,
|
|
7
|
+
interestByRegion({ keyword, startTime, endTime, geo, resolution, hl, timezone, category }: InterestByRegionOptions): Promise<InterestByRegionResponse>;
|
|
8
8
|
}
|
|
9
9
|
declare const _default: GoogleTrendsApi;
|
|
10
10
|
export default _default;
|
|
@@ -120,44 +120,68 @@ class GoogleTrendsApi {
|
|
|
120
120
|
}
|
|
121
121
|
});
|
|
122
122
|
}
|
|
123
|
-
|
|
123
|
+
//
|
|
124
|
+
interestByRegion({ keyword, startTime = new Date('2004-01-01'), endTime = new Date(), geo = 'US', resolution = 'REGION', hl = 'en-US', timezone = new Date().getTimezoneOffset(), category = 0 }) {
|
|
124
125
|
return __awaiter(this, void 0, void 0, function* () {
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
126
|
+
const formatDate = (date) => {
|
|
127
|
+
return date.toISOString().split('T')[0];
|
|
128
|
+
};
|
|
129
|
+
const formatTrendsDate = (date) => {
|
|
130
|
+
const pad = (n) => n.toString().padStart(2, '0');
|
|
131
|
+
const yyyy = date.getFullYear();
|
|
132
|
+
const mm = pad(date.getMonth() + 1);
|
|
133
|
+
const dd = pad(date.getDate());
|
|
134
|
+
const hh = pad(date.getHours());
|
|
135
|
+
const min = pad(date.getMinutes());
|
|
136
|
+
const ss = pad(date.getSeconds());
|
|
137
|
+
return `${yyyy}-${mm}-${dd}T${hh}\\:${min}\\:${ss}`;
|
|
138
|
+
};
|
|
139
|
+
const getDateRangeParam = (date) => {
|
|
140
|
+
const yesterday = new Date(date);
|
|
141
|
+
yesterday.setDate(date.getDate() - 1);
|
|
142
|
+
const formattedStart = formatTrendsDate(yesterday);
|
|
143
|
+
const formattedEnd = formatTrendsDate(date);
|
|
144
|
+
return `${formattedStart} ${formattedEnd}`;
|
|
145
|
+
};
|
|
146
|
+
const exploreResponse = yield this.explore({
|
|
147
|
+
keyword: Array.isArray(keyword) ? keyword[0] : keyword,
|
|
148
|
+
geo: Array.isArray(geo) ? geo[0] : geo,
|
|
149
|
+
time: `${getDateRangeParam(startTime)} ${getDateRangeParam(endTime)}`,
|
|
150
|
+
category,
|
|
151
|
+
hl
|
|
152
|
+
});
|
|
153
|
+
const widget = exploreResponse.widgets.find(w => w.id === 'GEO_MAP');
|
|
128
154
|
if (!widget) {
|
|
129
155
|
return { default: { geoMapData: [] } };
|
|
130
156
|
}
|
|
131
157
|
const options = Object.assign(Object.assign({}, constants_1.GOOGLE_TRENDS_MAPPER["interestByRegion" /* GoogleTrendsEndpoints.interestByRegion */]), { qs: {
|
|
132
158
|
hl,
|
|
133
|
-
tz:
|
|
159
|
+
tz: timezone.toString(),
|
|
134
160
|
req: JSON.stringify({
|
|
135
|
-
geo: {
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
161
|
+
geo: {
|
|
162
|
+
country: Array.isArray(geo) ? geo[0] : geo
|
|
163
|
+
},
|
|
164
|
+
comparisonItem: [{
|
|
165
|
+
time: `${formatDate(startTime)} ${formatDate(endTime)}`,
|
|
139
166
|
complexKeywordsRestriction: {
|
|
140
|
-
keyword: [
|
|
141
|
-
{
|
|
167
|
+
keyword: [{
|
|
142
168
|
type: 'BROAD',
|
|
143
|
-
value: keyword
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
},
|
|
148
|
-
],
|
|
169
|
+
value: Array.isArray(keyword) ? keyword[0] : keyword
|
|
170
|
+
}]
|
|
171
|
+
}
|
|
172
|
+
}],
|
|
149
173
|
resolution,
|
|
150
174
|
locale: hl,
|
|
151
175
|
requestOptions: {
|
|
152
176
|
property: '',
|
|
153
|
-
backend: '
|
|
154
|
-
category
|
|
177
|
+
backend: 'CM',
|
|
178
|
+
category
|
|
155
179
|
},
|
|
156
180
|
userConfig: {
|
|
157
|
-
userType: '
|
|
158
|
-
}
|
|
181
|
+
userType: 'USER_TYPE_LEGIT_USER'
|
|
182
|
+
}
|
|
159
183
|
}),
|
|
160
|
-
token: widget.token
|
|
184
|
+
token: widget.token
|
|
161
185
|
} });
|
|
162
186
|
try {
|
|
163
187
|
const response = yield (0, request_1.request)(options.url, options);
|
|
@@ -167,7 +191,6 @@ class GoogleTrendsApi {
|
|
|
167
191
|
return data;
|
|
168
192
|
}
|
|
169
193
|
catch (error) {
|
|
170
|
-
console.error('Interest by region request failed:', error);
|
|
171
194
|
return { default: { geoMapData: [] } };
|
|
172
195
|
}
|
|
173
196
|
});
|
package/lib/helpers/request.d.ts
CHANGED
package/lib/helpers/request.js
CHANGED
|
@@ -8,10 +8,75 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|
|
8
8
|
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
9
|
});
|
|
10
10
|
};
|
|
11
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
12
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
13
|
+
};
|
|
11
14
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
15
|
exports.request = void 0;
|
|
16
|
+
const https_1 = __importDefault(require("https"));
|
|
17
|
+
const querystring_1 = __importDefault(require("querystring"));
|
|
18
|
+
let cookieVal;
|
|
19
|
+
function rereq(options) {
|
|
20
|
+
return new Promise((resolve, reject) => {
|
|
21
|
+
const req = https_1.default.request(options, (res) => {
|
|
22
|
+
let chunk = '';
|
|
23
|
+
res.on('data', (data) => {
|
|
24
|
+
chunk += data;
|
|
25
|
+
});
|
|
26
|
+
res.on('end', () => {
|
|
27
|
+
resolve(chunk.toString());
|
|
28
|
+
});
|
|
29
|
+
});
|
|
30
|
+
req.on('error', (e) => {
|
|
31
|
+
reject(e);
|
|
32
|
+
});
|
|
33
|
+
req.end();
|
|
34
|
+
});
|
|
35
|
+
}
|
|
13
36
|
const request = (url, options) => __awaiter(void 0, void 0, void 0, function* () {
|
|
14
|
-
const
|
|
15
|
-
|
|
37
|
+
const parsedUrl = new URL(url);
|
|
38
|
+
const requestOptions = {
|
|
39
|
+
host: parsedUrl.host,
|
|
40
|
+
method: options.method || 'POST',
|
|
41
|
+
path: `${parsedUrl.pathname}${options.qs ? '?' + querystring_1.default.stringify(options.qs) : ''}`,
|
|
42
|
+
headers: {}
|
|
43
|
+
};
|
|
44
|
+
if (cookieVal) {
|
|
45
|
+
requestOptions.headers = { 'cookie': cookieVal };
|
|
46
|
+
}
|
|
47
|
+
const response = yield new Promise((resolve, reject) => {
|
|
48
|
+
const req = https_1.default.request(requestOptions, (res) => {
|
|
49
|
+
let chunk = '';
|
|
50
|
+
res.on('data', (data) => {
|
|
51
|
+
chunk += data;
|
|
52
|
+
});
|
|
53
|
+
res.on('end', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
54
|
+
if (res.statusCode === 429 && res.headers['set-cookie']) {
|
|
55
|
+
cookieVal = res.headers['set-cookie'][0].split(';')[0];
|
|
56
|
+
requestOptions.headers = { 'cookie': cookieVal };
|
|
57
|
+
try {
|
|
58
|
+
const retryResponse = yield rereq(requestOptions);
|
|
59
|
+
resolve(retryResponse);
|
|
60
|
+
}
|
|
61
|
+
catch (err) {
|
|
62
|
+
reject(err);
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
else {
|
|
66
|
+
resolve(chunk.toString());
|
|
67
|
+
}
|
|
68
|
+
}));
|
|
69
|
+
});
|
|
70
|
+
if (options.body) {
|
|
71
|
+
req.write(options.body);
|
|
72
|
+
}
|
|
73
|
+
req.on('error', (e) => {
|
|
74
|
+
reject(e);
|
|
75
|
+
});
|
|
76
|
+
req.end();
|
|
77
|
+
});
|
|
78
|
+
return {
|
|
79
|
+
text: () => Promise.resolve(response)
|
|
80
|
+
};
|
|
16
81
|
});
|
|
17
82
|
exports.request = request;
|