google-sr
Version:
Fast and efficient Package for scraping Google search results without the need for an API key
193 lines (187 loc) • 7.47 kB
text/typescript
import { AxiosRequestConfig } from 'axios';
import { CheerioAPI } from 'cheerio';
/**
* @internal
* Internal type for creating a node with a `type` field
* and any additional field as a string or null.
*
* @typeParam T - The value for the `type` property.
* @typeParam K - Key name of the additional string (or null) fields.
*/
type ResultNodeTyper<T, K extends string> = {
type: T;
} & Record<K, string | null>;
/**
* Internal utility type to convert a array type (T[]) to a single type (T)
* if T is not an array, it will return T
* @private
*/
type AsArrayElement<T> = T extends Array<infer U> ? U : T;
/**
* Internal utility type to get a record without null and undefined values
* @private
*/
type NonNullableRecord<T> = {
[K in keyof T]: NonNullable<T[K]>;
};
/**
* Generic type for the search results, derives the resultTypes from selector array.
*/
type SearchResultTypeFromSelector<R extends ResultSelector, S extends boolean = false> = S extends true ? NonNullableRecord<NonNullable<AsArrayElement<ReturnType<R>>>> : NonNullable<AsArrayElement<ReturnType<R>>>;
declare const ResultTypes: {
readonly OrganicResult: "ORGANIC";
readonly TranslateResult: "TRANSLATE";
readonly DictionaryResult: "DICTIONARY";
readonly TimeResult: "TIME";
readonly CurrencyResult: "CURRENCY";
readonly KnowledgePanelResult: "KNOWLEDGE_PANEL";
};
type OrganicResultNode = ResultNodeTyper<typeof ResultTypes.OrganicResult, "title" | "description" | "link">;
type TranslateResultNode = ResultNodeTyper<typeof ResultTypes.TranslateResult, "sourceLanguage" | "translationLanguage" | "sourceText" | "translatedText">;
interface DictionaryDefinition {
definition: string;
example?: string;
synonyms?: string[];
}
interface DictionaryMeaning {
partOfSpeech: string;
definitions: DictionaryDefinition[];
}
type DictionaryResultNode = ResultNodeTyper<typeof ResultTypes.DictionaryResult, "phonetic" | "word"> & {
meanings: DictionaryMeaning[];
};
type TimeResultNode = ResultNodeTyper<typeof ResultTypes.TimeResult, "location" | "time" | "timeInWords">;
type CurrencyResultNode = ResultNodeTyper<typeof ResultTypes.CurrencyResult, "from" | "to">;
interface KnowledgePanelMetadata {
label: string;
value: string;
}
type KnowledgePanelResultNode = ResultNodeTyper<typeof ResultTypes.KnowledgePanelResult, "label" | "title" | "description" | "sourceLink" | "imageLink"> & {
metadata: KnowledgePanelMetadata[];
};
type SearchResultNode = OrganicResultNode | TranslateResultNode | DictionaryResultNode | TimeResultNode | CurrencyResultNode | KnowledgePanelResultNode;
interface SearchResultNodeLike {
type: string;
}
type ResultSelector<R extends SearchResultNodeLike = SearchResultNodeLike> = (cheerio: CheerioAPI, strictSelector: boolean) => R[] | R | null;
/**
* Search options for single page search
*/
interface SearchOptions<R extends ResultSelector = ResultSelector> {
/**
* Search query
*/
query: string;
/**
* Control the type of results returned (can have a significant performance impact)
*/
resultTypes?: R[];
/**
* when true, will only return resultNodes that do not contain any undefined/empty properties
*/
strictSelector?: boolean;
/**
* Custom request configuration to be sent with the request
*/
requestConfig?: AxiosRequestConfig;
}
/**
* Search options for multiple pages search
*/
interface SearchOptionsWithPages<R extends ResultSelector = ResultSelector> extends SearchOptions<R> {
/**
* Total number of pages to search or an array of specific pages to search
*
* google search uses cursor-based pagination.
*
* Specific page numbers are incremented by 10 starting from 0 (page 1)
*
* If total number of pages is provided, cursor will be created according to: start = page * 10
*/
pages: number | number[];
/**
* Delay between each request in milliseconds. helps to avoid rate limiting issues.
*
* Default is 1000 ms (1 second). set to 0 to disable delay.
*/
delay?: number;
}
declare const TranslateSourceTextRegex: RegExp;
/**
* Parses regular non-ads search results.
* @returns Array of OrganicSearchResultNodes
*/
declare const OrganicResult: ResultSelector<OrganicResultNode>;
/**
* Parses translation search results.
* @returns Array of TranslateSearchResultNodes
*/
declare const TranslateResult: ResultSelector<TranslateResultNode>;
/**
* Parses dictionary search results.
* @returns Array of DictionaryResultNode
*/
declare const DictionaryResult: ResultSelector<DictionaryResultNode>;
/**
* Parses time search results.
* @returns Array of TimeResultNode
*/
declare const TimeResult: ResultSelector<TimeResultNode>;
/**
* Parses currency convert search results.
* @returns Array of CurrencyResultNode
*/
declare const CurrencyResult: ResultSelector<CurrencyResultNode>;
/**
* Parses knowledge panel search results.
* @param $
* @param strictSelector
* @returns KnowledgePanelResultNode
*/
declare const KnowledgePanelResult: ResultSelector<KnowledgePanelResultNode>;
/**
* Search google with the given query, only 1 page is returned
* @param options Search options
* @returns Search results as an array of SearchResultNodes
*/
declare function search<R extends ResultSelector = typeof OrganicResult>(options: SearchOptions<R> & {
strictSelector?: false;
}): Promise<SearchResultTypeFromSelector<R>[]>;
declare function search<R extends ResultSelector = typeof OrganicResult>(options: SearchOptions<R> & {
strictSelector: true;
}): Promise<SearchResultTypeFromSelector<R, true>[]>;
/**
* Searches google with the given query, returns results for multiple pages.
* google uses cursor-based pagination (using param start=number).
*
* Therefore, when providing the specific page numbers, make sure to provide it in 10 increments.
*
* @example
* ```ts
* // search the first 5 pages
* const results = await searchWithPages({
* query: "hello world",
* pages: 5,
* });
*
* // or provide the specific page numbers
* const results = await searchWithPages({
* query: "hello world",
* pages: [0, 10, 20, 30, 40],
* });
*
* // pages can be skipped or be out of order
* const results = await searchWithPages({
* query: "hello world",
* pages: [10, 0, 20],
* });
* ```
* @returns Search results as an array of SearchResultNodes or an array of arrays of SearchResultNodes
*/
declare function searchWithPages<R extends ResultSelector = typeof OrganicResult>(options: SearchOptionsWithPages<R> & {
strictSelector?: false;
}): Promise<SearchResultTypeFromSelector<R>[][]>;
declare function searchWithPages<R extends ResultSelector = typeof OrganicResult>(options: SearchOptionsWithPages<R> & {
strictSelector: true;
}): Promise<SearchResultTypeFromSelector<R, true>[][]>;
export { CurrencyResult, type CurrencyResultNode, type DictionaryDefinition, type DictionaryMeaning, DictionaryResult, type DictionaryResultNode, type KnowledgePanelMetadata, KnowledgePanelResult, type KnowledgePanelResultNode, OrganicResult, type OrganicResultNode, type ResultNodeTyper, type ResultSelector, ResultTypes, type SearchOptions, type SearchOptionsWithPages, type SearchResultNode, type SearchResultNodeLike, type SearchResultTypeFromSelector, TimeResult, type TimeResultNode, TranslateResult, type TranslateResultNode, TranslateSourceTextRegex, search, searchWithPages };