Skip to content

SERPAPI - Config

user_serpapi.config¤

SerpAPIConfig ¤

Config for downloading trends

Parameters:

Name Type Description Default
trend_params

params for SingleTrend

required
path_params PathParams

params to build the path

required
Source code in sm_trendy/use_serpapi/config.py
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
class SerpAPIConfig:
    """
    Config for downloading trends

    :param trend_params: params for SingleTrend
    :param path_params: params to build the path
    """

    def __init__(
        self,
        serpapi_params: SerpAPIParams,
        path_params: PathParams,
        extra_metadata: Optional[Dict] = {},
    ):
        self.serpapi_params = serpapi_params
        self.path_params = path_params
        self.extra_metadata = extra_metadata

    @classmethod
    def from_dict(cls, config: Dict) -> SerpAPIConfig:
        """
        Load config from a dictionary

        ```python
        raw_config = {
            "serpapi": {
                "date": "today 5-y",
                "cat": "0",
                "geo": "DE",
                "q": "phone case",
                "tz": "120"
            }
        }
        ```

        :param config: config dictionary that contains
            the key and values to build the params
        """

        serpapi_params = SerpAPIParams(**config["serpapi"])
        path_params = PathParams(
            **{
                "keyword": serpapi_params.q,
                "cat": serpapi_params.cat,
                "geo": serpapi_params.geo,
                "timeframe": serpapi_params.date,
            }
        )
        extra_metadata = config["serpapi"]

        return SerpAPIConfig(
            serpapi_params=serpapi_params,
            path_params=path_params,
            extra_metadata=extra_metadata,
        )

    def _validate(self):
        assert (
            self.serpapi_params.q == self.path_params.keyword
        ), "trend keyword and path keyword should match"

        assert (
            self.serpapi_params.geo == self.path_params.geo
        ), "trend geo and path geo should match"

        assert hasattr(self.serpapi_params, "q"), "serpapi_params should have q"
        assert hasattr(self.serpapi_params, "geo"), "serpapi_params should have geo"

from_dict(config) classmethod ¤

Load config from a dictionary

raw_config = {
    "serpapi": {
        "date": "today 5-y",
        "cat": "0",
        "geo": "DE",
        "q": "phone case",
        "tz": "120"
    }
}

Parameters:

Name Type Description Default
config Dict

config dictionary that contains the key and values to build the params

required
Source code in sm_trendy/use_serpapi/config.py
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
@classmethod
def from_dict(cls, config: Dict) -> SerpAPIConfig:
    """
    Load config from a dictionary

    ```python
    raw_config = {
        "serpapi": {
            "date": "today 5-y",
            "cat": "0",
            "geo": "DE",
            "q": "phone case",
            "tz": "120"
        }
    }
    ```

    :param config: config dictionary that contains
        the key and values to build the params
    """

    serpapi_params = SerpAPIParams(**config["serpapi"])
    path_params = PathParams(
        **{
            "keyword": serpapi_params.q,
            "cat": serpapi_params.cat,
            "geo": serpapi_params.geo,
            "timeframe": serpapi_params.date,
        }
    )
    extra_metadata = config["serpapi"]

    return SerpAPIConfig(
        serpapi_params=serpapi_params,
        path_params=path_params,
        extra_metadata=extra_metadata,
    )

SerpAPIConfigBundle ¤

Build a list of configs from file

Parameters:

Name Type Description Default
file_path AnyPath

path to the file

required
Source code in sm_trendy/use_serpapi/config.py
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
class SerpAPIConfigBundle:
    """Build a list of configs from file

    :param file_path: path to the file
    """

    def __init__(self, file_path: AnyPath, serpapi_key: Optional[str] = None):
        self.file_path = file_path
        self.serpapi_key = serpapi_key
        self.raw_configs = self._load_json(self.file_path)

    @property
    def configs(self) -> List[SerpAPIConfig]:

        return self._combine_configs(raw_configs=self.raw_configs)

    @property
    def global_config(self) -> Dict:
        return self._transform_raw_global_config(self.raw_configs["global"])

    def _combine_configs(self, raw_configs: Dict) -> List[SerpAPIConfig]:
        global_config = self._transform_raw_global_config(raw_configs["global"])

        combined_configs = [
            self._combine_with_global(
                global_config=global_config,
                keyword_config=k,
                serpapi_key=self.serpapi_key,
            )
            for k in raw_configs["keywords"]
        ]

        return combined_configs

    @staticmethod
    def _transform_raw_global_config(raw_global_config: Dict) -> Dict:
        """
        Convert string to path object if exist
        """
        global_config = copy.deepcopy(raw_global_config)

        if "path" in global_config:
            global_config["path"] = convert_path(global_config["path"])

        return global_config

    @staticmethod
    def _combine_with_global(
        global_config: Dict, keyword_config: Dict, serpapi_key: Optional[str] = None
    ) -> SerpAPIConfig:
        new_keyword_config = {}

        for key in ["serpapi"]:
            new_keyword_config[key] = keyword_config.get(key, {}) | global_config.get(
                key, {}
            )
            if serpapi_key is not None:
                new_keyword_config[key]["api_key"] = serpapi_key

        return SerpAPIConfig.from_dict(new_keyword_config)

    @staticmethod
    def _load_json(file_path: AnyPath) -> Dict:

        with open(file_path, "r") as fp:
            data = json.load(fp)

        return data

    def __getitem__(self, idx: int) -> SerpAPIConfig:
        return self.configs[idx]

    def __len__(self) -> int:
        return len(self.configs)

    def __iter__(self):
        for item in self.configs:
            yield item

    def __add__(self, o: List[Dict]):
        keywords = self.raw_configs["keywords"]
        keywords.extend(o)
        self.raw_configs["keywords"] = keywords

    def save_json(self, target_file_path: AnyPath):
        """save raw config to path

        :param target_file_path: where to save the json file
        """
        logger.info(f"Saving to path {target_file_path}")
        with open(target_file_path, "w") as fp:
            json.dump(self.raw_configs, fp)

save_json(target_file_path) ¤

save raw config to path

Parameters:

Name Type Description Default
target_file_path AnyPath

where to save the json file

required
Source code in sm_trendy/use_serpapi/config.py
230
231
232
233
234
235
236
237
def save_json(self, target_file_path: AnyPath):
    """save raw config to path

    :param target_file_path: where to save the json file
    """
    logger.info(f"Saving to path {target_file_path}")
    with open(target_file_path, "w") as fp:
        json.dump(self.raw_configs, fp)

SerpAPIParams ¤

Bases: BaseModel

SerpAPI docs: https://serpapi.com/google-trends-api

sc = SerpAPIParams(
    **{
        "api_key": "",
        "q": "Coffee",
        "geo": "DE",
        "data_type": "TIMESERIES",
        "tz": "120",
    }
)

# Convert the config to python dictionary
sc.dict(exclude_none=True)
Source code in sm_trendy/use_serpapi/config.py
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
class SerpAPIParams(BaseModel):
    """

    SerpAPI docs:
    https://serpapi.com/google-trends-api

    ```python
    sc = SerpAPIParams(
        **{
            "api_key": "",
            "q": "Coffee",
            "geo": "DE",
            "data_type": "TIMESERIES",
            "tz": "120",
        }
    )

    # Convert the config to python dictionary
    sc.dict(exclude_none=True)
    ```
    """

    api_key: str
    engine: str = "google_trends"
    q: str
    geo: Optional[str] = None
    data_type: Literal[
        "TIMESERIES", "GEO_MAP", "GEO_MAP_0", "RELATED_TOPICS", "RELATED_QUERIES"
    ] = "TIMESERIES"
    tz: Optional[str] = "120"
    cat: Optional[Literal["0"]] = None
    date: Literal[
        "now 1-H",
        "now 4-H",
        "now 1-d",
        "now 7-d",
        "today 1-m",
        "today 3-m",
        "today 12-m",
        "today 5-y",
        "all",
    ] = "today 5-y"

    @field_validator("date")
    @classmethod
    def date_match_allowed(cls, v: str, info: FieldValidationInfo):
        allowed = [
            "now 1-H",
            "now 4-H",
            "now 1-d",
            "now 7-d",
            "today 1-m",
            "today 3-m",
            "today 12-m",
            "today 5-y",
            "all",
        ]
        if v not in allowed:
            raise ValueError(f"date must be one of {allowed}")

        return v