blocket-api 0.2.8__tar.gz → 0.2.9__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,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: blocket_api
3
- Version: 0.2.8
3
+ Version: 0.2.9
4
4
  Summary: A python API wrapper for blocket.se
5
5
  Author-email: dunderrrrrr <emil.bjorkroth@gmail.com>
6
6
  Requires-Python: >=3.10
@@ -11,12 +11,13 @@ Requires-Dist: pre-commit>=3.7.1
11
11
  Requires-Dist: pytest>=8.2.2
12
12
  Requires-Dist: respx>=0.21.1
13
13
  Requires-Dist: mypy>=1.15.0
14
- Requires-Dist: ruff>=0.12.4
14
+ Requires-Dist: pydantic>=2.11.7
15
+ Requires-Dist: ruff>=0.13.0
15
16
  Dynamic: license-file
16
17
 
17
18
  # BlocketAPI
18
19
 
19
- [![PyPI version](https://img.shields.io/pypi/v/blocket_api?style=for-the-badge)](https://pypi.org/project/blocket_api/) [![License](https://img.shields.io/badge/license-WTFPL-green?style=for-the-badge)](https://github.com/dunderrrrrr/blocket_api/blob/main/LICENSE) [![Python versions](https://img.shields.io/pypi/pyversions/blocket-api?style=for-the-badge)](https://pypi.org/project/blocket_api/) ![PyPI - Downloads](https://img.shields.io/pypi/dm/blocket_api?style=for-the-badge&color=%23dbce58)
20
+ [![PyPI version](https://img.shields.io/pypi/v/blocket_api?style=for-the-badge)](https://pypi.org/project/blocket_api/) [![License](https://img.shields.io/badge/license-WTFPL-green?style=for-the-badge)](https://github.com/dunderrrrrr/blocket_api/blob/main/LICENSE) ![Python](https://img.shields.io/badge/Python-3.10-blue?style=for-the-badge) ![PyPI - Downloads](https://img.shields.io/pypi/dm/blocket_api?style=for-the-badge&color=%23dbce58)
20
21
 
21
22
  BlocketAPI allows users to query saved searches, known as "Bevakningar", on [blocket.se](https://blocket.se/). This means you can either retrieve results from a specific saved search or list all listings/ads across all saved searches. The results from these queries are returned in a `json` format.
22
23
 
@@ -55,20 +56,20 @@ Some calls require a `bearerToken`. However, some calls are public and don't req
55
56
  [Where token?](#-blocket-api-token)
56
57
 
57
58
 
58
- | Function | Token required | Description |
59
- |---|---|---|
60
- | [`api.saved_searches()`](#saved_searches) | 🔐 Yes | List your saved searches (bevakningar) |
61
- | [`api.get_listings()`](#get_listingssearch_id-limit) | 🔐 Yes | List items related to a saved search |
62
- | [`api.custom_search()`](#custom_searchsearch_query-region-limit) | 👏 No | Search for everything on Blocket and filter by region |
63
- | [`api.motor_search()`](#motor_searchpage-make-fuel-chassi-price-modelyear-milage-gearbox) | 👏 No | Advanced search for car-listings. |
64
- | [`api.price_eval()`](#price_evalregistration_number) | 👏 No | Vehicle purchase valuation and details. |
65
- | [`api.home_search()`](#home_searchcity-type-order_by-ordering-offset) | 👏 No | Query home listings.
66
- | [`api.store_search()`](#store_searchsearch_query-page) | 👏 No | Search for a store.
67
- | [`api.get_store_listings()`](#get_store_listingsstore_id-page) | 👏 No | Get listings from a specific store.
59
+ | Function | Token required | `as_objects` | Description |
60
+ |---|---|---|---|
61
+ | [`api.saved_searches()`](#saved_searches) | 🔐 Yes | - | List your saved searches (bevakningar) |
62
+ | [`api.get_listings()`](#get_listings) | 🔐 Yes | - | List items related to a saved search |
63
+ | [`api.custom_search()`](#custom_search) | 👏 No | Yes | Search for everything on Blocket and filter by region |
64
+ | [`api.motor_search()`](#motor_search) | 👏 No | Yes | Advanced search for car-listings. |
65
+ | [`api.price_eval()`](#price_eval) | 👏 No | - | Vehicle purchase valuation and details. |
66
+ | [`api.home_search()`](#home_search) | 👏 No | - | Query home listings.
67
+ | [`api.store_search()`](#store_search) | 👏 No | Yes | Search for a store.
68
+ | [`api.get_store_listings()`](#get_store_listings) | 👏 No | - | Get listings from a specific store.
68
69
 
69
70
  ## 🤓 Detailed usage
70
71
 
71
- ### saved_searches()
72
+ ### saved_searches
72
73
 
73
74
  Saved searches are your so called "Bevakningar" and can be found [here](https://www.blocket.se/sparade/bevakningar). Each saved search has and unique `id` which can be used as a parameter to `get_listings()`, see below.
74
75
 
@@ -87,7 +88,7 @@ Saved searches are your so called "Bevakningar" and can be found [here](https://
87
88
  ]
88
89
  ```
89
90
 
90
- ### get_listings(search_id, limit)
91
+ ### get_listings
91
92
  Returns all listings related to a saved search.
92
93
 
93
94
  Parameters:
@@ -121,7 +122,7 @@ Parameters:
121
122
  }
122
123
  ```
123
124
 
124
- ### custom_search(search_query, region, limit)
125
+ ### custom_search
125
126
  Make a custom search through out all of blocked. A region can be passed in as parameter for filtering.
126
127
 
127
128
  Parameters:
@@ -129,6 +130,7 @@ Parameters:
129
130
  - `region` (`enum`, optional) - Filter results on a region, default is all of Sweden.
130
131
  - `category` (`enum`, optional) - Filter for a specific category, ex. `Category.for_hemmet`.
131
132
  - `limit` (`int`, optional) - Limit number of results returned, max is 99.
133
+ - `as_objects` (`bool`, optional) - Return results as pydantic models, default is `False`.
132
134
 
133
135
  ```py
134
136
  >>> from blocket_api import Region
@@ -162,7 +164,7 @@ Parameters:
162
164
  }
163
165
  ```
164
166
 
165
- ### motor_search(page, make, fuel, chassi, price, modelYear, milage, gearbox)
167
+ ### motor_search
166
168
  To query listings related to a specific car, supply the following parameters:
167
169
 
168
170
  - `page` (`int`, required) - Results are split in pages, set page number here.
@@ -173,6 +175,8 @@ To query listings related to a specific car, supply the following parameters:
173
175
  - `modelYear` (`Optional[Tuple[int, int]]`) - Set model year range, ex. `(2000, 2020)`.
174
176
  - `milage` (`Optional[Tuple[int, int]]`) - Set milage range, ex. `(1000, 2000)`.
175
177
  - `gearbox` (`Optional[GEARBOX_OPTIONS]`) - Filter a specific gearbox, ex. `Automat`.
178
+ - `as_objects` (`bool`, optional) - Return results as pydantic models, default is `False`.
179
+
176
180
  ```py
177
181
  >>> api.motor_search(
178
182
  make=["Audi", "Ford"],
@@ -184,7 +188,7 @@ To query listings related to a specific car, supply the following parameters:
184
188
  ...
185
189
  ```
186
190
 
187
- ### price_eval(registration_number)
191
+ ### price_eval
188
192
  Query price evaluation for a specific vehicle by using cars registration number (ABC123). This returns company and private estimated prices, car information, and more. The api queries same endpoint as Blockets ["värdera bil"](https://www.blocket.se/tjanster/vardera-bil) service.
189
193
 
190
194
  - `registration_number` (`str`, required) - Registration number of the vehicle.
@@ -203,7 +207,7 @@ Query price evaluation for a specific vehicle by using cars registration number
203
207
  }
204
208
  ```
205
209
 
206
- ### home_search(city, type, order_by, ordering, offset)
210
+ ### home_search
207
211
  Query home listings from [bostad.blocket.se](https://bostad.blocket.se/).
208
212
 
209
213
  - `city` (`str`, required) - City name, ex. Stockholm.
@@ -223,11 +227,13 @@ Query home listings from [bostad.blocket.se](https://bostad.blocket.se/).
223
227
  ...
224
228
  ```
225
229
 
226
- ### store_search(search_query, page)
230
+ ### store_search
227
231
  Search for a store in Blocket stores from [blocket.se/butiker](https://www.blocket.se/butiker).
228
232
 
229
233
  - `search_query` (`str`, required) - The name of the store.
230
234
  - `page` (`int`, optional) - The page number to return.
235
+ - `as_objects` (`bool`, optional) - Return results as pydantic models, default is `False`.
236
+
231
237
 
232
238
  ```py
233
239
  >>> api.store_search("Jannes Car and Kebab")
@@ -243,7 +249,7 @@ Search for a store in Blocket stores from [blocket.se/butiker](https://www.block
243
249
  }
244
250
  ```
245
251
 
246
- ### get_store_listings(store_id, page)
252
+ ### get_store_listings
247
253
  Get listings from a specific store.
248
254
 
249
255
  - `store_id` (`int`, required) - The store id. Can be obtained by calling `store_search()`.
@@ -1,6 +1,6 @@
1
1
  # BlocketAPI
2
2
 
3
- [![PyPI version](https://img.shields.io/pypi/v/blocket_api?style=for-the-badge)](https://pypi.org/project/blocket_api/) [![License](https://img.shields.io/badge/license-WTFPL-green?style=for-the-badge)](https://github.com/dunderrrrrr/blocket_api/blob/main/LICENSE) [![Python versions](https://img.shields.io/pypi/pyversions/blocket-api?style=for-the-badge)](https://pypi.org/project/blocket_api/) ![PyPI - Downloads](https://img.shields.io/pypi/dm/blocket_api?style=for-the-badge&color=%23dbce58)
3
+ [![PyPI version](https://img.shields.io/pypi/v/blocket_api?style=for-the-badge)](https://pypi.org/project/blocket_api/) [![License](https://img.shields.io/badge/license-WTFPL-green?style=for-the-badge)](https://github.com/dunderrrrrr/blocket_api/blob/main/LICENSE) ![Python](https://img.shields.io/badge/Python-3.10-blue?style=for-the-badge) ![PyPI - Downloads](https://img.shields.io/pypi/dm/blocket_api?style=for-the-badge&color=%23dbce58)
4
4
 
5
5
  BlocketAPI allows users to query saved searches, known as "Bevakningar", on [blocket.se](https://blocket.se/). This means you can either retrieve results from a specific saved search or list all listings/ads across all saved searches. The results from these queries are returned in a `json` format.
6
6
 
@@ -39,20 +39,20 @@ Some calls require a `bearerToken`. However, some calls are public and don't req
39
39
  [Where token?](#-blocket-api-token)
40
40
 
41
41
 
42
- | Function | Token required | Description |
43
- |---|---|---|
44
- | [`api.saved_searches()`](#saved_searches) | 🔐 Yes | List your saved searches (bevakningar) |
45
- | [`api.get_listings()`](#get_listingssearch_id-limit) | 🔐 Yes | List items related to a saved search |
46
- | [`api.custom_search()`](#custom_searchsearch_query-region-limit) | 👏 No | Search for everything on Blocket and filter by region |
47
- | [`api.motor_search()`](#motor_searchpage-make-fuel-chassi-price-modelyear-milage-gearbox) | 👏 No | Advanced search for car-listings. |
48
- | [`api.price_eval()`](#price_evalregistration_number) | 👏 No | Vehicle purchase valuation and details. |
49
- | [`api.home_search()`](#home_searchcity-type-order_by-ordering-offset) | 👏 No | Query home listings.
50
- | [`api.store_search()`](#store_searchsearch_query-page) | 👏 No | Search for a store.
51
- | [`api.get_store_listings()`](#get_store_listingsstore_id-page) | 👏 No | Get listings from a specific store.
42
+ | Function | Token required | `as_objects` | Description |
43
+ |---|---|---|---|
44
+ | [`api.saved_searches()`](#saved_searches) | 🔐 Yes | - | List your saved searches (bevakningar) |
45
+ | [`api.get_listings()`](#get_listings) | 🔐 Yes | - | List items related to a saved search |
46
+ | [`api.custom_search()`](#custom_search) | 👏 No | Yes | Search for everything on Blocket and filter by region |
47
+ | [`api.motor_search()`](#motor_search) | 👏 No | Yes | Advanced search for car-listings. |
48
+ | [`api.price_eval()`](#price_eval) | 👏 No | - | Vehicle purchase valuation and details. |
49
+ | [`api.home_search()`](#home_search) | 👏 No | - | Query home listings.
50
+ | [`api.store_search()`](#store_search) | 👏 No | Yes | Search for a store.
51
+ | [`api.get_store_listings()`](#get_store_listings) | 👏 No | - | Get listings from a specific store.
52
52
 
53
53
  ## 🤓 Detailed usage
54
54
 
55
- ### saved_searches()
55
+ ### saved_searches
56
56
 
57
57
  Saved searches are your so called "Bevakningar" and can be found [here](https://www.blocket.se/sparade/bevakningar). Each saved search has and unique `id` which can be used as a parameter to `get_listings()`, see below.
58
58
 
@@ -71,7 +71,7 @@ Saved searches are your so called "Bevakningar" and can be found [here](https://
71
71
  ]
72
72
  ```
73
73
 
74
- ### get_listings(search_id, limit)
74
+ ### get_listings
75
75
  Returns all listings related to a saved search.
76
76
 
77
77
  Parameters:
@@ -105,7 +105,7 @@ Parameters:
105
105
  }
106
106
  ```
107
107
 
108
- ### custom_search(search_query, region, limit)
108
+ ### custom_search
109
109
  Make a custom search through out all of blocked. A region can be passed in as parameter for filtering.
110
110
 
111
111
  Parameters:
@@ -113,6 +113,7 @@ Parameters:
113
113
  - `region` (`enum`, optional) - Filter results on a region, default is all of Sweden.
114
114
  - `category` (`enum`, optional) - Filter for a specific category, ex. `Category.for_hemmet`.
115
115
  - `limit` (`int`, optional) - Limit number of results returned, max is 99.
116
+ - `as_objects` (`bool`, optional) - Return results as pydantic models, default is `False`.
116
117
 
117
118
  ```py
118
119
  >>> from blocket_api import Region
@@ -146,7 +147,7 @@ Parameters:
146
147
  }
147
148
  ```
148
149
 
149
- ### motor_search(page, make, fuel, chassi, price, modelYear, milage, gearbox)
150
+ ### motor_search
150
151
  To query listings related to a specific car, supply the following parameters:
151
152
 
152
153
  - `page` (`int`, required) - Results are split in pages, set page number here.
@@ -157,6 +158,8 @@ To query listings related to a specific car, supply the following parameters:
157
158
  - `modelYear` (`Optional[Tuple[int, int]]`) - Set model year range, ex. `(2000, 2020)`.
158
159
  - `milage` (`Optional[Tuple[int, int]]`) - Set milage range, ex. `(1000, 2000)`.
159
160
  - `gearbox` (`Optional[GEARBOX_OPTIONS]`) - Filter a specific gearbox, ex. `Automat`.
161
+ - `as_objects` (`bool`, optional) - Return results as pydantic models, default is `False`.
162
+
160
163
  ```py
161
164
  >>> api.motor_search(
162
165
  make=["Audi", "Ford"],
@@ -168,7 +171,7 @@ To query listings related to a specific car, supply the following parameters:
168
171
  ...
169
172
  ```
170
173
 
171
- ### price_eval(registration_number)
174
+ ### price_eval
172
175
  Query price evaluation for a specific vehicle by using cars registration number (ABC123). This returns company and private estimated prices, car information, and more. The api queries same endpoint as Blockets ["värdera bil"](https://www.blocket.se/tjanster/vardera-bil) service.
173
176
 
174
177
  - `registration_number` (`str`, required) - Registration number of the vehicle.
@@ -187,7 +190,7 @@ Query price evaluation for a specific vehicle by using cars registration number
187
190
  }
188
191
  ```
189
192
 
190
- ### home_search(city, type, order_by, ordering, offset)
193
+ ### home_search
191
194
  Query home listings from [bostad.blocket.se](https://bostad.blocket.se/).
192
195
 
193
196
  - `city` (`str`, required) - City name, ex. Stockholm.
@@ -207,11 +210,13 @@ Query home listings from [bostad.blocket.se](https://bostad.blocket.se/).
207
210
  ...
208
211
  ```
209
212
 
210
- ### store_search(search_query, page)
213
+ ### store_search
211
214
  Search for a store in Blocket stores from [blocket.se/butiker](https://www.blocket.se/butiker).
212
215
 
213
216
  - `search_query` (`str`, required) - The name of the store.
214
217
  - `page` (`int`, optional) - The page number to return.
218
+ - `as_objects` (`bool`, optional) - Return results as pydantic models, default is `False`.
219
+
215
220
 
216
221
  ```py
217
222
  >>> api.store_search("Jannes Car and Kebab")
@@ -227,7 +232,7 @@ Search for a store in Blocket stores from [blocket.se/butiker](https://www.block
227
232
  }
228
233
  ```
229
234
 
230
- ### get_store_listings(store_id, page)
235
+ ### get_store_listings
231
236
  Get listings from a specific store.
232
237
 
233
238
  - `store_id` (`int`, required) - The store id. Can be obtained by calling `store_search()`.
@@ -1,14 +1,19 @@
1
1
  from __future__ import annotations
2
2
 
3
- from collections.abc import Callable
4
- from functools import wraps
5
3
  import urllib
4
+ from collections.abc import Callable
6
5
  from dataclasses import dataclass
7
6
  from enum import Enum
8
- from typing import TYPE_CHECKING, Any, List, Literal, Optional, Tuple
7
+ from functools import wraps
8
+ from typing import TYPE_CHECKING, Any, List, Literal, Optional, Tuple, Union, overload
9
9
 
10
10
  import httpx
11
11
 
12
+ from blocket_api.models import (
13
+ CustomSearchResults,
14
+ MotorSearchResults,
15
+ StoreSearchResults,
16
+ )
12
17
  from blocket_api.qasa import HOME_SEARCH_ORDERING, HomeType, OrderBy, Qasa
13
18
 
14
19
  if TYPE_CHECKING:
@@ -232,6 +237,39 @@ class BlocketAPI:
232
237
  token=self.token,
233
238
  ).json()
234
239
 
240
+ @overload
241
+ def custom_search(
242
+ self,
243
+ search_query: str,
244
+ region: Region = Region.hela_sverige,
245
+ category: Category | None = None,
246
+ limit: int = 99,
247
+ *,
248
+ as_objects: Literal[True],
249
+ ) -> CustomSearchResults: ...
250
+
251
+ @overload
252
+ def custom_search(
253
+ self,
254
+ search_query: str,
255
+ region: Region = Region.hela_sverige,
256
+ category: Category | None = None,
257
+ limit: int = 99,
258
+ *,
259
+ as_objects: Literal[False] = False,
260
+ ) -> dict: ...
261
+
262
+ @overload
263
+ def custom_search(
264
+ self,
265
+ search_query: str,
266
+ region: Region = Region.hela_sverige,
267
+ category: Category | None = None,
268
+ limit: int = 99,
269
+ *,
270
+ as_objects: bool = False,
271
+ ) -> Union[dict, CustomSearchResults]: ...
272
+
235
273
  @public_token
236
274
  def custom_search(
237
275
  self,
@@ -239,10 +277,11 @@ class BlocketAPI:
239
277
  region: Region = Region.hela_sverige,
240
278
  category: Category | None = None,
241
279
  limit: int = 99,
242
- ) -> dict:
280
+ *,
281
+ as_objects: bool = False,
282
+ ) -> dict | CustomSearchResults:
243
283
  """
244
- Do a custom search through out all of Blocket.
245
- Supply a region for filtering. Default is all of Sweden.
284
+ Do a custom search throughout all of Blocket.
246
285
  """
247
286
  assert self.token
248
287
 
@@ -254,7 +293,53 @@ class BlocketAPI:
254
293
  if category:
255
294
  url += f"&cg={category.value}"
256
295
 
257
- return _make_request(url=url, token=self.token).json()
296
+ response = _make_request(url=url, token=self.token).json()
297
+ return CustomSearchResults.model_validate(response) if as_objects else response
298
+
299
+ @overload
300
+ def motor_search(
301
+ self,
302
+ page: int,
303
+ make: List[MAKE_OPTIONS],
304
+ fuel: Optional[List[FUEL_OPTIONS]] = None,
305
+ chassi: Optional[List[CHASSI_OPTIONS]] = None,
306
+ price: Optional[Tuple[int, int]] = None,
307
+ modelYear: Optional[Tuple[int, int]] = None,
308
+ milage: Optional[Tuple[int, int]] = None,
309
+ gearbox: Optional[GEARBOX_OPTIONS] = None,
310
+ *,
311
+ as_objects: Literal[True],
312
+ ) -> MotorSearchResults: ...
313
+
314
+ @overload
315
+ def motor_search(
316
+ self,
317
+ page: int,
318
+ make: List[MAKE_OPTIONS],
319
+ fuel: Optional[List[FUEL_OPTIONS]] = None,
320
+ chassi: Optional[List[CHASSI_OPTIONS]] = None,
321
+ price: Optional[Tuple[int, int]] = None,
322
+ modelYear: Optional[Tuple[int, int]] = None,
323
+ milage: Optional[Tuple[int, int]] = None,
324
+ gearbox: Optional[GEARBOX_OPTIONS] = None,
325
+ *,
326
+ as_objects: Literal[False] = False,
327
+ ) -> dict: ...
328
+
329
+ @overload
330
+ def motor_search(
331
+ self,
332
+ page: int,
333
+ make: List[MAKE_OPTIONS],
334
+ fuel: Optional[List[FUEL_OPTIONS]] = None,
335
+ chassi: Optional[List[CHASSI_OPTIONS]] = None,
336
+ price: Optional[Tuple[int, int]] = None,
337
+ modelYear: Optional[Tuple[int, int]] = None,
338
+ milage: Optional[Tuple[int, int]] = None,
339
+ gearbox: Optional[GEARBOX_OPTIONS] = None,
340
+ *,
341
+ as_objects: bool = False,
342
+ ) -> Union[dict, MotorSearchResults]: ...
258
343
 
259
344
  @public_token
260
345
  def motor_search(
@@ -267,7 +352,9 @@ class BlocketAPI:
267
352
  modelYear: Optional[Tuple[int, int]] = None,
268
353
  milage: Optional[Tuple[int, int]] = None,
269
354
  gearbox: Optional[GEARBOX_OPTIONS] = None,
270
- ) -> dict:
355
+ *,
356
+ as_objects: bool = False,
357
+ ) -> dict | MotorSearchResults:
271
358
  """
272
359
  Search specifically in the car section of Blocket
273
360
  with set optional parameters for filtering.
@@ -278,7 +365,8 @@ class BlocketAPI:
278
365
  set_params = {
279
366
  key: value
280
367
  for key, value in locals().items()
281
- if key not in ["self", "page", "range_params"] and value is not None
368
+ if key not in ["self", "page", "range_params", "as_objects"]
369
+ and value is not None
282
370
  }
283
371
 
284
372
  filters = []
@@ -298,7 +386,8 @@ class BlocketAPI:
298
386
  filters_str = "&".join([f"filter={f}" for f in filters])
299
387
  url = f"{motor_base_url}?{filters_str}&page={page}"
300
388
 
301
- return _make_request(url=f"{url}", token=self.token).json()
389
+ response = _make_request(url=f"{url}", token=self.token).json()
390
+ return MotorSearchResults.model_validate(response) if as_objects else response
302
391
 
303
392
  @public_token
304
393
  def price_eval(
@@ -335,18 +424,54 @@ class BlocketAPI:
335
424
  offset=offset,
336
425
  ).search()
337
426
 
427
+ @overload
428
+ def search_store(
429
+ self,
430
+ search_query: str,
431
+ page: int = 0,
432
+ *,
433
+ as_objects: Literal[True],
434
+ ) -> StoreSearchResults: ...
435
+
436
+ @overload
437
+ def search_store(
438
+ self,
439
+ search_query: str,
440
+ page: int = 0,
441
+ *,
442
+ as_objects: Literal[False] = False,
443
+ ) -> dict: ...
444
+
445
+ @overload
446
+ def search_store(
447
+ self,
448
+ page: int,
449
+ make: List[MAKE_OPTIONS],
450
+ fuel: Optional[List[FUEL_OPTIONS]] = None,
451
+ chassi: Optional[List[CHASSI_OPTIONS]] = None,
452
+ price: Optional[Tuple[int, int]] = None,
453
+ modelYear: Optional[Tuple[int, int]] = None,
454
+ milage: Optional[Tuple[int, int]] = None,
455
+ gearbox: Optional[GEARBOX_OPTIONS] = None,
456
+ *,
457
+ as_objects: bool = False,
458
+ ) -> Union[dict, StoreSearchResults]: ...
459
+
338
460
  @public_token
339
461
  def search_store(
340
462
  self,
341
463
  search_query: str,
342
464
  page: int = 0,
343
- ) -> dict:
465
+ *,
466
+ as_objects: bool = False,
467
+ ) -> dict | StoreSearchResults:
344
468
  """
345
469
  Searching through Blocket stores from https://www.blocket.se/butiker.
346
470
  The store_id is used for get_store_listings().
347
471
  """
348
472
  url = f"{BASE_URL}/search_bff/v1/stores?q={search_query}&page={page}"
349
- return _make_request(url=f"{url}", token=self.token).json()
473
+ response = _make_request(url=f"{url}", token=self.token).json()
474
+ return StoreSearchResults.model_validate(response) if as_objects else response
350
475
 
351
476
  @public_token
352
477
  def get_store_listings(
@@ -0,0 +1,151 @@
1
+ import datetime
2
+
3
+ from pydantic import BaseModel
4
+
5
+ ### CustomSearch ###
6
+
7
+
8
+ class CustomSearchPrice(BaseModel):
9
+ suffix: str
10
+ value: int
11
+
12
+
13
+ class CustomSearchLocation(BaseModel):
14
+ image_url: str
15
+ label: str
16
+ query_key: str | None = None
17
+
18
+
19
+ class CustomSearchImage(BaseModel):
20
+ height: int
21
+ type: str
22
+ url: str
23
+ width: int
24
+
25
+
26
+ class CustomSearchCategory(BaseModel):
27
+ id: str
28
+ name: str
29
+
30
+
31
+ class CustomSearchResult(BaseModel):
32
+ ad_id: str
33
+ ad_status: str
34
+ body: str
35
+ category: list[CustomSearchCategory]
36
+ images: list[CustomSearchImage] = []
37
+ list_id: str
38
+ list_time: datetime.datetime
39
+ map: CustomSearchLocation | None = None
40
+ map_url: str | None = None
41
+ price: CustomSearchPrice
42
+ share_url: str
43
+ state_id: str
44
+ subject: str
45
+ type: str
46
+ zipcode: str | None = None
47
+
48
+
49
+ class CustomSearchResults(BaseModel):
50
+ data: list[CustomSearchResult]
51
+ total_count: int
52
+
53
+
54
+ ### MotorSearch ###
55
+
56
+
57
+ class MotorSearchCarEquipment(BaseModel):
58
+ label: str
59
+
60
+
61
+ class MotorSearchCarLocation(BaseModel):
62
+ region: str
63
+ municipality: str
64
+ area: str
65
+
66
+
67
+ class MotorSearchCarImage(BaseModel):
68
+ height: int
69
+ width: int
70
+ image: str
71
+
72
+
73
+ class MotorSearchCar(BaseModel):
74
+ images: list[MotorSearchCarImage]
75
+ location: MotorSearchCarLocation
76
+ fuel: str
77
+ gearbox: str
78
+ regDate: int
79
+ mileage: int
80
+ equipment: list[MotorSearchCarEquipment] | None = None
81
+
82
+
83
+ class MotorSearchPrice(BaseModel):
84
+ amount: str
85
+ billingPeriod: str
86
+ oldPrice: str | None = None
87
+
88
+
89
+ class MotorSearchSeller(BaseModel):
90
+ type: str
91
+ name: str
92
+ id: str
93
+
94
+
95
+ class MotorSearchResult(BaseModel):
96
+ dealId: str
97
+ link: str
98
+ listTime: datetime.datetime
99
+ originalListTime: datetime.datetime
100
+ seller: MotorSearchSeller
101
+ heading: str
102
+ price: MotorSearchPrice
103
+ thumbnail: str
104
+ car: MotorSearchCar
105
+ description: str
106
+
107
+
108
+ class MotorSearchResults(BaseModel):
109
+ cars: list[MotorSearchResult]
110
+ hits: int
111
+ pages: int
112
+
113
+
114
+ ### StoreSearch ###
115
+
116
+
117
+ class StoreSearchLocation(BaseModel):
118
+ longitude: float
119
+ latitude: float
120
+
121
+
122
+ class StoreSearchImage(BaseModel):
123
+ height: int
124
+ width: int
125
+ url: str
126
+
127
+
128
+ class StoreSearchLogotype(BaseModel):
129
+ height: int
130
+ width: int
131
+ url: str
132
+
133
+
134
+ class StoreSearchResult(BaseModel):
135
+ address: str | None = None
136
+ id: str
137
+ logotype: StoreSearchLogotype
138
+ image: StoreSearchImage | None = None
139
+ description: str
140
+ external_store_url: str | None = None
141
+ location: StoreSearchLocation | None = None
142
+ name: str
143
+ title: str
144
+ ad_count: int
145
+ category: str
146
+
147
+
148
+ class StoreSearchResults(BaseModel):
149
+ data: list[StoreSearchResult]
150
+ total_count: int
151
+ total_page_count: int
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: blocket_api
3
- Version: 0.2.8
3
+ Version: 0.2.9
4
4
  Summary: A python API wrapper for blocket.se
5
5
  Author-email: dunderrrrrr <emil.bjorkroth@gmail.com>
6
6
  Requires-Python: >=3.10
@@ -11,12 +11,13 @@ Requires-Dist: pre-commit>=3.7.1
11
11
  Requires-Dist: pytest>=8.2.2
12
12
  Requires-Dist: respx>=0.21.1
13
13
  Requires-Dist: mypy>=1.15.0
14
- Requires-Dist: ruff>=0.12.4
14
+ Requires-Dist: pydantic>=2.11.7
15
+ Requires-Dist: ruff>=0.13.0
15
16
  Dynamic: license-file
16
17
 
17
18
  # BlocketAPI
18
19
 
19
- [![PyPI version](https://img.shields.io/pypi/v/blocket_api?style=for-the-badge)](https://pypi.org/project/blocket_api/) [![License](https://img.shields.io/badge/license-WTFPL-green?style=for-the-badge)](https://github.com/dunderrrrrr/blocket_api/blob/main/LICENSE) [![Python versions](https://img.shields.io/pypi/pyversions/blocket-api?style=for-the-badge)](https://pypi.org/project/blocket_api/) ![PyPI - Downloads](https://img.shields.io/pypi/dm/blocket_api?style=for-the-badge&color=%23dbce58)
20
+ [![PyPI version](https://img.shields.io/pypi/v/blocket_api?style=for-the-badge)](https://pypi.org/project/blocket_api/) [![License](https://img.shields.io/badge/license-WTFPL-green?style=for-the-badge)](https://github.com/dunderrrrrr/blocket_api/blob/main/LICENSE) ![Python](https://img.shields.io/badge/Python-3.10-blue?style=for-the-badge) ![PyPI - Downloads](https://img.shields.io/pypi/dm/blocket_api?style=for-the-badge&color=%23dbce58)
20
21
 
21
22
  BlocketAPI allows users to query saved searches, known as "Bevakningar", on [blocket.se](https://blocket.se/). This means you can either retrieve results from a specific saved search or list all listings/ads across all saved searches. The results from these queries are returned in a `json` format.
22
23
 
@@ -55,20 +56,20 @@ Some calls require a `bearerToken`. However, some calls are public and don't req
55
56
  [Where token?](#-blocket-api-token)
56
57
 
57
58
 
58
- | Function | Token required | Description |
59
- |---|---|---|
60
- | [`api.saved_searches()`](#saved_searches) | 🔐 Yes | List your saved searches (bevakningar) |
61
- | [`api.get_listings()`](#get_listingssearch_id-limit) | 🔐 Yes | List items related to a saved search |
62
- | [`api.custom_search()`](#custom_searchsearch_query-region-limit) | 👏 No | Search for everything on Blocket and filter by region |
63
- | [`api.motor_search()`](#motor_searchpage-make-fuel-chassi-price-modelyear-milage-gearbox) | 👏 No | Advanced search for car-listings. |
64
- | [`api.price_eval()`](#price_evalregistration_number) | 👏 No | Vehicle purchase valuation and details. |
65
- | [`api.home_search()`](#home_searchcity-type-order_by-ordering-offset) | 👏 No | Query home listings.
66
- | [`api.store_search()`](#store_searchsearch_query-page) | 👏 No | Search for a store.
67
- | [`api.get_store_listings()`](#get_store_listingsstore_id-page) | 👏 No | Get listings from a specific store.
59
+ | Function | Token required | `as_objects` | Description |
60
+ |---|---|---|---|
61
+ | [`api.saved_searches()`](#saved_searches) | 🔐 Yes | - | List your saved searches (bevakningar) |
62
+ | [`api.get_listings()`](#get_listings) | 🔐 Yes | - | List items related to a saved search |
63
+ | [`api.custom_search()`](#custom_search) | 👏 No | Yes | Search for everything on Blocket and filter by region |
64
+ | [`api.motor_search()`](#motor_search) | 👏 No | Yes | Advanced search for car-listings. |
65
+ | [`api.price_eval()`](#price_eval) | 👏 No | - | Vehicle purchase valuation and details. |
66
+ | [`api.home_search()`](#home_search) | 👏 No | - | Query home listings.
67
+ | [`api.store_search()`](#store_search) | 👏 No | Yes | Search for a store.
68
+ | [`api.get_store_listings()`](#get_store_listings) | 👏 No | - | Get listings from a specific store.
68
69
 
69
70
  ## 🤓 Detailed usage
70
71
 
71
- ### saved_searches()
72
+ ### saved_searches
72
73
 
73
74
  Saved searches are your so called "Bevakningar" and can be found [here](https://www.blocket.se/sparade/bevakningar). Each saved search has and unique `id` which can be used as a parameter to `get_listings()`, see below.
74
75
 
@@ -87,7 +88,7 @@ Saved searches are your so called "Bevakningar" and can be found [here](https://
87
88
  ]
88
89
  ```
89
90
 
90
- ### get_listings(search_id, limit)
91
+ ### get_listings
91
92
  Returns all listings related to a saved search.
92
93
 
93
94
  Parameters:
@@ -121,7 +122,7 @@ Parameters:
121
122
  }
122
123
  ```
123
124
 
124
- ### custom_search(search_query, region, limit)
125
+ ### custom_search
125
126
  Make a custom search through out all of blocked. A region can be passed in as parameter for filtering.
126
127
 
127
128
  Parameters:
@@ -129,6 +130,7 @@ Parameters:
129
130
  - `region` (`enum`, optional) - Filter results on a region, default is all of Sweden.
130
131
  - `category` (`enum`, optional) - Filter for a specific category, ex. `Category.for_hemmet`.
131
132
  - `limit` (`int`, optional) - Limit number of results returned, max is 99.
133
+ - `as_objects` (`bool`, optional) - Return results as pydantic models, default is `False`.
132
134
 
133
135
  ```py
134
136
  >>> from blocket_api import Region
@@ -162,7 +164,7 @@ Parameters:
162
164
  }
163
165
  ```
164
166
 
165
- ### motor_search(page, make, fuel, chassi, price, modelYear, milage, gearbox)
167
+ ### motor_search
166
168
  To query listings related to a specific car, supply the following parameters:
167
169
 
168
170
  - `page` (`int`, required) - Results are split in pages, set page number here.
@@ -173,6 +175,8 @@ To query listings related to a specific car, supply the following parameters:
173
175
  - `modelYear` (`Optional[Tuple[int, int]]`) - Set model year range, ex. `(2000, 2020)`.
174
176
  - `milage` (`Optional[Tuple[int, int]]`) - Set milage range, ex. `(1000, 2000)`.
175
177
  - `gearbox` (`Optional[GEARBOX_OPTIONS]`) - Filter a specific gearbox, ex. `Automat`.
178
+ - `as_objects` (`bool`, optional) - Return results as pydantic models, default is `False`.
179
+
176
180
  ```py
177
181
  >>> api.motor_search(
178
182
  make=["Audi", "Ford"],
@@ -184,7 +188,7 @@ To query listings related to a specific car, supply the following parameters:
184
188
  ...
185
189
  ```
186
190
 
187
- ### price_eval(registration_number)
191
+ ### price_eval
188
192
  Query price evaluation for a specific vehicle by using cars registration number (ABC123). This returns company and private estimated prices, car information, and more. The api queries same endpoint as Blockets ["värdera bil"](https://www.blocket.se/tjanster/vardera-bil) service.
189
193
 
190
194
  - `registration_number` (`str`, required) - Registration number of the vehicle.
@@ -203,7 +207,7 @@ Query price evaluation for a specific vehicle by using cars registration number
203
207
  }
204
208
  ```
205
209
 
206
- ### home_search(city, type, order_by, ordering, offset)
210
+ ### home_search
207
211
  Query home listings from [bostad.blocket.se](https://bostad.blocket.se/).
208
212
 
209
213
  - `city` (`str`, required) - City name, ex. Stockholm.
@@ -223,11 +227,13 @@ Query home listings from [bostad.blocket.se](https://bostad.blocket.se/).
223
227
  ...
224
228
  ```
225
229
 
226
- ### store_search(search_query, page)
230
+ ### store_search
227
231
  Search for a store in Blocket stores from [blocket.se/butiker](https://www.blocket.se/butiker).
228
232
 
229
233
  - `search_query` (`str`, required) - The name of the store.
230
234
  - `page` (`int`, optional) - The page number to return.
235
+ - `as_objects` (`bool`, optional) - Return results as pydantic models, default is `False`.
236
+
231
237
 
232
238
  ```py
233
239
  >>> api.store_search("Jannes Car and Kebab")
@@ -243,7 +249,7 @@ Search for a store in Blocket stores from [blocket.se/butiker](https://www.block
243
249
  }
244
250
  ```
245
251
 
246
- ### get_store_listings(store_id, page)
252
+ ### get_store_listings
247
253
  Get listings from a specific store.
248
254
 
249
255
  - `store_id` (`int`, required) - The store id. Can be obtained by calling `store_search()`.
@@ -3,6 +3,7 @@ README.md
3
3
  pyproject.toml
4
4
  blocket_api/__init__.py
5
5
  blocket_api/blocket.py
6
+ blocket_api/models.py
6
7
  blocket_api/qasa.py
7
8
  blocket_api.egg-info/PKG-INFO
8
9
  blocket_api.egg-info/SOURCES.txt
@@ -3,4 +3,5 @@ pre-commit>=3.7.1
3
3
  pytest>=8.2.2
4
4
  respx>=0.21.1
5
5
  mypy>=1.15.0
6
- ruff>=0.12.4
6
+ pydantic>=2.11.7
7
+ ruff>=0.13.0
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "blocket_api"
3
- version = "0.2.8"
3
+ version = "0.2.9"
4
4
  description = "A python API wrapper for blocket.se"
5
5
  authors = [{name = "dunderrrrrr", email = "emil.bjorkroth@gmail.com"}]
6
6
  readme = "README.md"
@@ -11,7 +11,8 @@ dependencies = [
11
11
  "pytest>=8.2.2",
12
12
  "respx>=0.21.1",
13
13
  "mypy>=1.15.0",
14
- "ruff>=0.12.4",
14
+ "pydantic>=2.11.7",
15
+ "ruff>=0.13.0",
15
16
  ]
16
17
 
17
18
 
File without changes
File without changes