serpex 2.2.0__tar.gz → 2.3.0__tar.gz

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.
@@ -1,8 +1,8 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: serpex
3
- Version: 2.2.0
3
+ Version: 2.3.0
4
4
  Summary: Official Python SDK for Serpex Search API - Fetch search results in JSON format
5
- Home-page: https://github.com/divyeshradadiya/serp-frontend
5
+ Home-page: https://github.com/divyeshradadiya/serpex-sdk-python
6
6
  Author: Serpex Team
7
7
  Author-email: Serpex Team <support@serpex.dev>
8
8
  License: MIT
@@ -162,16 +162,34 @@ class SearchParams:
162
162
  # Optional: Engine selection (defaults to 'auto')
163
163
  engine: Optional[str] = 'auto'
164
164
 
165
- # Optional: Search category (currently only 'web' supported)
166
- category: Optional[str] = 'web'
165
+ # Optional: Search category ('web' for general search, 'news' for news articles - always returns latest news)
166
+ category: Optional[str] = 'web' # Supports: 'web', 'news'
167
167
 
168
- # Optional: Time range filter
168
+ # Optional: Time range filter (only applicable for 'web' category, ignored for 'news')
169
169
  time_range: Optional[str] = 'all'
170
170
 
171
171
  # Optional: Response format
172
172
  format: Optional[str] = 'json'
173
173
  ```
174
174
 
175
+ ### News Search Example
176
+
177
+ News search always returns the latest news articles. The `time_range` parameter is ignored for news searches.
178
+
179
+ ```python
180
+ # Search for latest news articles
181
+ news_results = client.search({
182
+ 'q': 'artificial intelligence',
183
+ 'engine': 'google',
184
+ 'category': 'news' # Always returns latest news
185
+ })
186
+
187
+ print(news_results.results[0].title)
188
+ print(news_results.results[0].published_date)
189
+ ```
190
+
191
+ ````
192
+
175
193
  ## Supported Engines
176
194
 
177
195
  - **auto**: Automatically routes to the best available search engine
@@ -196,7 +214,7 @@ class SearchResponse:
196
214
  corrections: List[str]
197
215
  infoboxes: List[Any]
198
216
  suggestions: List[str]
199
- ```
217
+ ````
200
218
 
201
219
  ## Error Handling
202
220
 
@@ -216,6 +234,7 @@ except SerpApiException as e:
216
234
  ## Examples
217
235
 
218
236
  ### Basic Search
237
+
219
238
  ```python
220
239
  results = client.search({
221
240
  'q': 'coffee shops near me'
@@ -223,6 +242,7 @@ results = client.search({
223
242
  ```
224
243
 
225
244
  ### Advanced Search with Filters
245
+
226
246
  ```python
227
247
  results = client.search({
228
248
  'q': 'latest AI news',
@@ -233,6 +253,7 @@ results = client.search({
233
253
  ```
234
254
 
235
255
  ### Using SearchParams Object
256
+
236
257
  ```python
237
258
  from serpex import SearchParams
238
259
 
@@ -247,6 +268,7 @@ results = client.search(params)
247
268
  ### Extract Web Content to LLM-Ready Data
248
269
 
249
270
  #### Extract from a Single URL
271
+
250
272
  ```python
251
273
  # Extract content from one website
252
274
  result = client.extract({
@@ -259,6 +281,7 @@ if result.results[0].success:
259
281
  ```
260
282
 
261
283
  #### Extract from Multiple URLs (up to 10 at once)
284
+
262
285
  ```python
263
286
  # Extract content from multiple websites (up to 10 URLs)
264
287
  extract_results = client.extract({
@@ -281,6 +304,7 @@ for result in extract_results.results:
281
304
  ```
282
305
 
283
306
  #### Sample Response
307
+
284
308
  ```python
285
309
  # Example response structure
286
310
  {
@@ -306,6 +330,7 @@ for result in extract_results.results:
306
330
  ```
307
331
 
308
332
  ### Using ExtractParams Object
333
+
309
334
  ```python
310
335
  from serpex import ExtractParams
311
336
 
@@ -127,16 +127,34 @@ class SearchParams:
127
127
  # Optional: Engine selection (defaults to 'auto')
128
128
  engine: Optional[str] = 'auto'
129
129
 
130
- # Optional: Search category (currently only 'web' supported)
131
- category: Optional[str] = 'web'
130
+ # Optional: Search category ('web' for general search, 'news' for news articles - always returns latest news)
131
+ category: Optional[str] = 'web' # Supports: 'web', 'news'
132
132
 
133
- # Optional: Time range filter
133
+ # Optional: Time range filter (only applicable for 'web' category, ignored for 'news')
134
134
  time_range: Optional[str] = 'all'
135
135
 
136
136
  # Optional: Response format
137
137
  format: Optional[str] = 'json'
138
138
  ```
139
139
 
140
+ ### News Search Example
141
+
142
+ News search always returns the latest news articles. The `time_range` parameter is ignored for news searches.
143
+
144
+ ```python
145
+ # Search for latest news articles
146
+ news_results = client.search({
147
+ 'q': 'artificial intelligence',
148
+ 'engine': 'google',
149
+ 'category': 'news' # Always returns latest news
150
+ })
151
+
152
+ print(news_results.results[0].title)
153
+ print(news_results.results[0].published_date)
154
+ ```
155
+
156
+ ````
157
+
140
158
  ## Supported Engines
141
159
 
142
160
  - **auto**: Automatically routes to the best available search engine
@@ -161,7 +179,7 @@ class SearchResponse:
161
179
  corrections: List[str]
162
180
  infoboxes: List[Any]
163
181
  suggestions: List[str]
164
- ```
182
+ ````
165
183
 
166
184
  ## Error Handling
167
185
 
@@ -181,6 +199,7 @@ except SerpApiException as e:
181
199
  ## Examples
182
200
 
183
201
  ### Basic Search
202
+
184
203
  ```python
185
204
  results = client.search({
186
205
  'q': 'coffee shops near me'
@@ -188,6 +207,7 @@ results = client.search({
188
207
  ```
189
208
 
190
209
  ### Advanced Search with Filters
210
+
191
211
  ```python
192
212
  results = client.search({
193
213
  'q': 'latest AI news',
@@ -198,6 +218,7 @@ results = client.search({
198
218
  ```
199
219
 
200
220
  ### Using SearchParams Object
221
+
201
222
  ```python
202
223
  from serpex import SearchParams
203
224
 
@@ -212,6 +233,7 @@ results = client.search(params)
212
233
  ### Extract Web Content to LLM-Ready Data
213
234
 
214
235
  #### Extract from a Single URL
236
+
215
237
  ```python
216
238
  # Extract content from one website
217
239
  result = client.extract({
@@ -224,6 +246,7 @@ if result.results[0].success:
224
246
  ```
225
247
 
226
248
  #### Extract from Multiple URLs (up to 10 at once)
249
+
227
250
  ```python
228
251
  # Extract content from multiple websites (up to 10 URLs)
229
252
  extract_results = client.extract({
@@ -246,6 +269,7 @@ for result in extract_results.results:
246
269
  ```
247
270
 
248
271
  #### Sample Response
272
+
249
273
  ```python
250
274
  # Example response structure
251
275
  {
@@ -271,6 +295,7 @@ for result in extract_results.results:
271
295
  ```
272
296
 
273
297
  ### Using ExtractParams Object
298
+
274
299
  ```python
275
300
  from serpex import ExtractParams
276
301
 
@@ -288,4 +313,4 @@ results = client.extract(params)
288
313
 
289
314
  ## License
290
315
 
291
- MIT
316
+ MIT
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "serpex"
7
- version = "2.2.0"
7
+ version = "2.3.0"
8
8
  description = "Official Python SDK for Serpex Search API - Fetch search results in JSON format"
9
9
  authors = [
10
10
  {name = "Serpex Team", email = "support@serpex.dev"}
@@ -5,13 +5,13 @@ with open("README.md", "r", encoding="utf-8") as fh:
5
5
 
6
6
  setup(
7
7
  name="serpex",
8
- version="2.2.0",
8
+ version="2.3.0",
9
9
  author="Serpex Team",
10
10
  author_email="support@serpex.dev",
11
11
  description="Official Python SDK for Serpex SERP API - Fetch search results in JSON format",
12
12
  long_description=long_description,
13
13
  long_description_content_type="text/markdown",
14
- url="https://github.com/divyeshradadiya/serp-frontend",
14
+ url="https://github.com/divyeshradadiya/serpex-sdk-python",
15
15
  packages=find_packages(where="src"),
16
16
  package_dir={"": "src"},
17
17
  classifiers=[
@@ -45,8 +45,8 @@ setup(
45
45
  },
46
46
  keywords="serp search api google search-results seo python sdk",
47
47
  project_urls={
48
- "Bug Reports": "https://github.com/divyeshradadiya/serp-frontend/issues",
49
- "Source": "https://github.com/divyeshradadiya/serp-frontend",
50
- "Documentation": "https://github.com/divyeshradadiya/serp-frontend#readme",
48
+ "Bug Reports": "https://github.com/divyeshradadiya/serpex-sdk-python/issues",
49
+ "Source": "https://github.com/divyeshradadiya/serpex-sdk-python",
50
+ "Documentation": "https://github.com/divyeshradadiya/serpex-sdk-python#readme",
51
51
  },
52
- )
52
+ )
@@ -1,8 +1,8 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: serpex
3
- Version: 2.2.0
3
+ Version: 2.3.0
4
4
  Summary: Official Python SDK for Serpex Search API - Fetch search results in JSON format
5
- Home-page: https://github.com/divyeshradadiya/serp-frontend
5
+ Home-page: https://github.com/divyeshradadiya/serpex-sdk-python
6
6
  Author: Serpex Team
7
7
  Author-email: Serpex Team <support@serpex.dev>
8
8
  License: MIT
@@ -162,16 +162,34 @@ class SearchParams:
162
162
  # Optional: Engine selection (defaults to 'auto')
163
163
  engine: Optional[str] = 'auto'
164
164
 
165
- # Optional: Search category (currently only 'web' supported)
166
- category: Optional[str] = 'web'
165
+ # Optional: Search category ('web' for general search, 'news' for news articles - always returns latest news)
166
+ category: Optional[str] = 'web' # Supports: 'web', 'news'
167
167
 
168
- # Optional: Time range filter
168
+ # Optional: Time range filter (only applicable for 'web' category, ignored for 'news')
169
169
  time_range: Optional[str] = 'all'
170
170
 
171
171
  # Optional: Response format
172
172
  format: Optional[str] = 'json'
173
173
  ```
174
174
 
175
+ ### News Search Example
176
+
177
+ News search always returns the latest news articles. The `time_range` parameter is ignored for news searches.
178
+
179
+ ```python
180
+ # Search for latest news articles
181
+ news_results = client.search({
182
+ 'q': 'artificial intelligence',
183
+ 'engine': 'google',
184
+ 'category': 'news' # Always returns latest news
185
+ })
186
+
187
+ print(news_results.results[0].title)
188
+ print(news_results.results[0].published_date)
189
+ ```
190
+
191
+ ````
192
+
175
193
  ## Supported Engines
176
194
 
177
195
  - **auto**: Automatically routes to the best available search engine
@@ -196,7 +214,7 @@ class SearchResponse:
196
214
  corrections: List[str]
197
215
  infoboxes: List[Any]
198
216
  suggestions: List[str]
199
- ```
217
+ ````
200
218
 
201
219
  ## Error Handling
202
220
 
@@ -216,6 +234,7 @@ except SerpApiException as e:
216
234
  ## Examples
217
235
 
218
236
  ### Basic Search
237
+
219
238
  ```python
220
239
  results = client.search({
221
240
  'q': 'coffee shops near me'
@@ -223,6 +242,7 @@ results = client.search({
223
242
  ```
224
243
 
225
244
  ### Advanced Search with Filters
245
+
226
246
  ```python
227
247
  results = client.search({
228
248
  'q': 'latest AI news',
@@ -233,6 +253,7 @@ results = client.search({
233
253
  ```
234
254
 
235
255
  ### Using SearchParams Object
256
+
236
257
  ```python
237
258
  from serpex import SearchParams
238
259
 
@@ -247,6 +268,7 @@ results = client.search(params)
247
268
  ### Extract Web Content to LLM-Ready Data
248
269
 
249
270
  #### Extract from a Single URL
271
+
250
272
  ```python
251
273
  # Extract content from one website
252
274
  result = client.extract({
@@ -259,6 +281,7 @@ if result.results[0].success:
259
281
  ```
260
282
 
261
283
  #### Extract from Multiple URLs (up to 10 at once)
284
+
262
285
  ```python
263
286
  # Extract content from multiple websites (up to 10 URLs)
264
287
  extract_results = client.extract({
@@ -281,6 +304,7 @@ for result in extract_results.results:
281
304
  ```
282
305
 
283
306
  #### Sample Response
307
+
284
308
  ```python
285
309
  # Example response structure
286
310
  {
@@ -306,6 +330,7 @@ for result in extract_results.results:
306
330
  ```
307
331
 
308
332
  ### Using ExtractParams Object
333
+
309
334
  ```python
310
335
  from serpex import ExtractParams
311
336
 
@@ -6,7 +6,14 @@ import requests
6
6
  from typing import Optional, Dict, Any, Union
7
7
  from urllib.parse import urlencode
8
8
 
9
- from .types import SearchResponse, SearchParams, ExtractResponse, ExtractParams, ExtractResult, ExtractMetadata
9
+ from .types import (
10
+ SearchResponse,
11
+ SearchParams,
12
+ ExtractResponse,
13
+ ExtractParams,
14
+ ExtractResult,
15
+ ExtractMetadata,
16
+ )
10
17
  from .exceptions import SerpApiException
11
18
 
12
19
 
@@ -35,12 +42,16 @@ class SerpexClient:
35
42
  self.api_key = api_key
36
43
  self.base_url = base_url.rstrip("/")
37
44
  self.session = requests.Session()
38
- self.session.headers.update({
39
- "Authorization": f"Bearer {self.api_key}",
40
- "Content-Type": "application/json",
41
- })
45
+ self.session.headers.update(
46
+ {
47
+ "Authorization": f"Bearer {self.api_key}",
48
+ "Content-Type": "application/json",
49
+ }
50
+ )
42
51
 
43
- def _make_request(self, params: Dict[str, Any], endpoint: str = "/api/search", method: str = "GET") -> Dict[str, Any]:
52
+ def _make_request(
53
+ self, params: Dict[str, Any], endpoint: str = "/api/search", method: str = "GET"
54
+ ) -> Dict[str, Any]:
44
55
  """
45
56
  Make an authenticated request to the API.
46
57
 
@@ -77,7 +88,7 @@ class SerpexClient:
77
88
  query_string = urlencode(filtered_params, doseq=True)
78
89
  final_url = f"{url}?{query_string}" if query_string else url
79
90
  response = self.session.get(final_url, timeout=30)
80
-
91
+
81
92
  return self._handle_response(response)
82
93
  except requests.RequestException as e:
83
94
  raise SerpApiException(f"Request failed: {str(e)}")
@@ -105,9 +116,7 @@ class SerpexClient:
105
116
  try:
106
117
  data = response.json()
107
118
  raise SerpApiException(
108
- data.get("error", "Validation error"),
109
- status_code=400,
110
- details=data
119
+ data.get("error", "Validation error"), status_code=400, details=data
111
120
  )
112
121
  except ValueError:
113
122
  raise SerpApiException("Bad request", status_code=400)
@@ -117,12 +126,11 @@ class SerpexClient:
117
126
  raise SerpApiException(
118
127
  data.get("error", f"API error: {response.reason}"),
119
128
  status_code=response.status_code,
120
- details=data
129
+ details=data,
121
130
  )
122
131
  except ValueError:
123
132
  raise SerpApiException(
124
- f"API error: {response.reason}",
125
- status_code=response.status_code
133
+ f"API error: {response.reason}", status_code=response.status_code
126
134
  )
127
135
 
128
136
  try:
@@ -150,21 +158,30 @@ class SerpexClient:
150
158
 
151
159
  # Validate required parameters
152
160
  if not params.q or not isinstance(params.q, str) or not params.q.strip():
153
- raise ValueError("Query parameter (q) is required and must be a non-empty string")
161
+ raise ValueError(
162
+ "Query parameter (q) is required and must be a non-empty string"
163
+ )
154
164
 
155
165
  if len(params.q) > 500:
156
166
  raise ValueError("Query too long (max 500 characters)")
157
167
 
168
+ # Determine endpoint based on category
169
+ category = params.category or "web"
170
+ endpoint = "/api/search/news" if category == "news" else "/api/search"
171
+
158
172
  # Prepare request parameters with only supported params
159
173
  request_params = {
160
- 'q': params.q,
161
- 'engine': params.engine or 'auto',
162
- 'category': params.category or 'web',
163
- 'time_range': params.time_range or 'all',
164
- 'format': params.format or 'json'
174
+ "q": params.q,
175
+ "engine": params.engine or "auto",
176
+ "format": params.format or "json",
165
177
  }
166
178
 
167
- data = self._make_request(request_params)
179
+ # Add category for web search, omit for news (news endpoint doesn't need it)
180
+ if category == "web":
181
+ request_params["category"] = "web"
182
+ request_params["time_range"] = params.time_range or "all"
183
+
184
+ data = self._make_request(request_params, endpoint=endpoint)
168
185
 
169
186
  # Convert response to SearchResponse object
170
187
  from .types import SearchResult, SearchMetadata
@@ -178,10 +195,10 @@ class SerpexClient:
178
195
  query=data["query"],
179
196
  engines=data["engines"],
180
197
  results=results,
181
- answers=data["answers"],
182
- corrections=data["corrections"],
183
- infoboxes=data["infoboxes"],
184
- suggestions=data["suggestions"],
198
+ answers=data.get("answers", []),
199
+ corrections=data.get("corrections", []),
200
+ infoboxes=data.get("infoboxes", []),
201
+ suggestions=data.get("suggestions", []),
185
202
  )
186
203
 
187
204
  def extract(self, params: Union[ExtractParams, Dict[str, Any]]) -> ExtractResponse:
@@ -203,7 +220,11 @@ class SerpexClient:
203
220
  params = ExtractParams(**params)
204
221
 
205
222
  # Validate required parameters
206
- if not params.urls or not isinstance(params.urls, list) or len(params.urls) == 0:
223
+ if (
224
+ not params.urls
225
+ or not isinstance(params.urls, list)
226
+ or len(params.urls) == 0
227
+ ):
207
228
  raise ValueError("URLs list is required and must contain at least one URL")
208
229
 
209
230
  if len(params.urls) > 10:
@@ -217,6 +238,7 @@ class SerpexClient:
217
238
  continue
218
239
  try:
219
240
  from urllib.parse import urlparse
241
+
220
242
  parsed = urlparse(url)
221
243
  if not parsed.scheme or not parsed.netloc:
222
244
  invalid_urls.append(url)
@@ -227,11 +249,9 @@ class SerpexClient:
227
249
  raise ValueError(f"Invalid URLs provided: {invalid_urls}")
228
250
 
229
251
  # Prepare request parameters
230
- request_params = {
231
- 'urls': params.urls
232
- }
252
+ request_params = {"urls": params.urls}
233
253
 
234
- data = self._make_request(request_params, endpoint='/api/crawl', method='POST')
254
+ data = self._make_request(request_params, endpoint="/api/crawl", method="POST")
235
255
 
236
256
  # Convert response to ExtractResponse object
237
257
  metadata = ExtractMetadata(**data["metadata"])
@@ -241,4 +261,4 @@ class SerpexClient:
241
261
  success=data["success"],
242
262
  results=results,
243
263
  metadata=metadata,
244
- )
264
+ )
@@ -9,6 +9,7 @@ from dataclasses import dataclass
9
9
  @dataclass
10
10
  class SearchResult:
11
11
  """Represents a single search result."""
12
+
12
13
  title: str
13
14
  url: str
14
15
  snippet: str
@@ -23,15 +24,18 @@ class SearchResult:
23
24
  @dataclass
24
25
  class SearchMetadata:
25
26
  """Metadata for search results."""
27
+
26
28
  number_of_results: int
27
29
  response_time: int
28
30
  timestamp: str
29
31
  credits_used: int
32
+ category: Optional[str] = None # Optional category field for news searches
30
33
 
31
34
 
32
35
  @dataclass
33
36
  class SearchResponse:
34
37
  """Complete search response."""
38
+
35
39
  metadata: SearchMetadata
36
40
  id: str
37
41
  query: str
@@ -46,6 +50,7 @@ class SearchResponse:
46
50
  @dataclass
47
51
  class ExtractResult:
48
52
  """Represents a single extraction result."""
53
+
49
54
  url: str
50
55
  success: bool
51
56
  markdown: Optional[str] = None
@@ -59,6 +64,7 @@ class ExtractResult:
59
64
  @dataclass
60
65
  class ExtractMetadata:
61
66
  """Metadata for extraction results."""
67
+
62
68
  total_urls: int
63
69
  processed_urls: int
64
70
  successful_crawls: int
@@ -71,6 +77,7 @@ class ExtractMetadata:
71
77
  @dataclass
72
78
  class ExtractResponse:
73
79
  """Complete extraction response."""
80
+
74
81
  success: bool
75
82
  results: List[ExtractResult]
76
83
  metadata: ExtractMetadata
@@ -79,6 +86,7 @@ class ExtractResponse:
79
86
  @dataclass
80
87
  class ExtractParams:
81
88
  """Parameters for extraction requests."""
89
+
82
90
  # Required: URLs to extract (max 10)
83
91
  urls: List[str]
84
92
 
@@ -86,17 +94,18 @@ class ExtractParams:
86
94
  @dataclass
87
95
  class SearchParams:
88
96
  """Parameters for search requests."""
97
+
89
98
  # Required: search query
90
99
  q: str
91
100
 
92
101
  # Optional: Engine selection (defaults to 'auto')
93
- engine: Optional[str] = 'auto'
102
+ engine: Optional[str] = "auto"
94
103
 
95
- # Optional: Search category (currently only 'web' supported)
96
- category: Optional[str] = 'web'
104
+ # Optional: Search category ('web' for general search, 'news' for news articles - always returns latest news)
105
+ category: Optional[str] = "web" # Supports: 'web', 'news'
97
106
 
98
- # Optional: Time range filter
99
- time_range: Optional[str] = 'all'
107
+ # Optional: Time range filter (only applicable for 'web' category, ignored for 'news')
108
+ time_range: Optional[str] = "all"
100
109
 
101
110
  # Optional: Response format
102
- format: Optional[str] = 'json'
111
+ format: Optional[str] = "json"
File without changes
File without changes