blocket-api 0.2.9__tar.gz → 0.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.
- {blocket_api-0.2.9 → blocket_api-0.3.0}/PKG-INFO +39 -7
- {blocket_api-0.2.9 → blocket_api-0.3.0}/README.md +37 -5
- {blocket_api-0.2.9 → blocket_api-0.3.0}/blocket_api/blocket.py +82 -4
- blocket_api-0.3.0/blocket_api/models.py +536 -0
- {blocket_api-0.2.9 → blocket_api-0.3.0}/blocket_api.egg-info/PKG-INFO +39 -7
- {blocket_api-0.2.9 → blocket_api-0.3.0}/blocket_api.egg-info/requires.txt +1 -1
- {blocket_api-0.2.9 → blocket_api-0.3.0}/pyproject.toml +2 -2
- blocket_api-0.2.9/blocket_api/models.py +0 -151
- {blocket_api-0.2.9 → blocket_api-0.3.0}/LICENSE +0 -0
- {blocket_api-0.2.9 → blocket_api-0.3.0}/blocket_api/__init__.py +0 -0
- {blocket_api-0.2.9 → blocket_api-0.3.0}/blocket_api/qasa.py +0 -0
- {blocket_api-0.2.9 → blocket_api-0.3.0}/blocket_api.egg-info/SOURCES.txt +0 -0
- {blocket_api-0.2.9 → blocket_api-0.3.0}/blocket_api.egg-info/dependency_links.txt +0 -0
- {blocket_api-0.2.9 → blocket_api-0.3.0}/blocket_api.egg-info/top_level.txt +0 -0
- {blocket_api-0.2.9 → blocket_api-0.3.0}/setup.cfg +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: blocket_api
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.3.0
|
|
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
|
|
@@ -12,14 +12,14 @@ Requires-Dist: pytest>=8.2.2
|
|
|
12
12
|
Requires-Dist: respx>=0.21.1
|
|
13
13
|
Requires-Dist: mypy>=1.15.0
|
|
14
14
|
Requires-Dist: pydantic>=2.11.7
|
|
15
|
-
Requires-Dist: ruff>=0.13.
|
|
15
|
+
Requires-Dist: ruff>=0.13.1
|
|
16
16
|
Dynamic: license-file
|
|
17
17
|
|
|
18
18
|
# BlocketAPI
|
|
19
19
|
|
|
20
20
|
[](https://pypi.org/project/blocket_api/) [](https://github.com/dunderrrrrr/blocket_api/blob/main/LICENSE)  
|
|
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
|
+
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 or as cleaned pydantic objects.
|
|
23
23
|
|
|
24
24
|
> Blocket is one of Sweden's largest online marketplaces. It was founded in 1996 and allows users to buy and sell a wide range of items, including cars, real estate, jobs, services, and second-hand goods. The platform is known for its extensive reach and user-friendly interface, making it a popular choice for Swedes looking to purchase or sell items quickly and efficiently.
|
|
25
25
|
|
|
@@ -34,12 +34,14 @@ BlocketAPI allows users to query saved searches, known as "Bevakningar", on [blo
|
|
|
34
34
|
|
|
35
35
|
## 🧑💻️ Install
|
|
36
36
|
|
|
37
|
-
BlocketAPI
|
|
37
|
+
Install BlocketAPI via PyPI...
|
|
38
38
|
|
|
39
39
|
```sh
|
|
40
40
|
pip install blocket-api
|
|
41
41
|
```
|
|
42
42
|
|
|
43
|
+
or use [blocket-api.se](https://blocket-api.se) without installing anything!
|
|
44
|
+
|
|
43
45
|
## 💁♀️ Usage
|
|
44
46
|
|
|
45
47
|
```py
|
|
@@ -63,9 +65,11 @@ Some calls require a `bearerToken`. However, some calls are public and don't req
|
|
|
63
65
|
| [`api.custom_search()`](#custom_search) | 👏 No | Yes | Search for everything on Blocket and filter by region |
|
|
64
66
|
| [`api.motor_search()`](#motor_search) | 👏 No | Yes | Advanced search for car-listings. |
|
|
65
67
|
| [`api.price_eval()`](#price_eval) | 👏 No | - | Vehicle purchase valuation and details. |
|
|
66
|
-
| [`api.home_search()`](#home_search) | 👏 No |
|
|
68
|
+
| [`api.home_search()`](#home_search) | 👏 No | Yes | Query home listings.
|
|
67
69
|
| [`api.store_search()`](#store_search) | 👏 No | Yes | Search for a store.
|
|
68
|
-
| [`api.get_store_listings()`](#get_store_listings) | 👏 No |
|
|
70
|
+
| [`api.get_store_listings()`](#get_store_listings) | 👏 No | Yes | Get listings from a specific store.
|
|
71
|
+
| [`api.get_ad_by_id()`](#get_ad_by_id) | 👏 No | Yes | Get ad data from id.
|
|
72
|
+
|
|
69
73
|
|
|
70
74
|
## 🤓 Detailed usage
|
|
71
75
|
|
|
@@ -133,7 +137,7 @@ Parameters:
|
|
|
133
137
|
- `as_objects` (`bool`, optional) - Return results as pydantic models, default is `False`.
|
|
134
138
|
|
|
135
139
|
```py
|
|
136
|
-
>>> from blocket_api import Region
|
|
140
|
+
>>> from blocket_api.blocket import Region, Category
|
|
137
141
|
>>> api.custom_search("saab", Region.blekinge) # search for term "saab" in region of "Blekinge"
|
|
138
142
|
{
|
|
139
143
|
"data":[
|
|
@@ -215,6 +219,7 @@ Query home listings from [bostad.blocket.se](https://bostad.blocket.se/).
|
|
|
215
219
|
- `order_by` (`OrderBy`, optional) - Sorting order, ex. `OrderBy.price`.
|
|
216
220
|
- `ordering` (`HOME_SEARCH_ORDERING`, optional) - Sorting order, ex. `"descending"`.
|
|
217
221
|
- `offset` (`int`, optional) - Offset for results, ex. `60`.
|
|
222
|
+
- `as_objects` (`bool`, optional) - Return results as pydantic models, default is False.
|
|
218
223
|
|
|
219
224
|
```py
|
|
220
225
|
>>> from blocket_api.qasa import HomeType, OrderBy
|
|
@@ -254,6 +259,8 @@ Get listings from a specific store.
|
|
|
254
259
|
|
|
255
260
|
- `store_id` (`int`, required) - The store id. Can be obtained by calling `store_search()`.
|
|
256
261
|
- `page` (`int`, optional) - The page number to return.
|
|
262
|
+
- `as_objects` (`bool`, optional) - Return results as pydantic models, default is `False`.
|
|
263
|
+
|
|
257
264
|
|
|
258
265
|
```py
|
|
259
266
|
>>> api.get_store_listings(1234)
|
|
@@ -271,6 +278,30 @@ Get listings from a specific store.
|
|
|
271
278
|
}
|
|
272
279
|
```
|
|
273
280
|
|
|
281
|
+
### get_ad_by_id
|
|
282
|
+
Get ad data from a specific ad id.
|
|
283
|
+
|
|
284
|
+
- `ad_id` (`int`, required) - The ad id. Can be found by calling any other method or from ad url.
|
|
285
|
+
- `as_objects` (`bool`, optional) - Return results as pydantic models, default is `False`.
|
|
286
|
+
|
|
287
|
+
|
|
288
|
+
```py
|
|
289
|
+
>>> api.get_ad_by_id(1234)
|
|
290
|
+
{
|
|
291
|
+
"data": {
|
|
292
|
+
"ad_id": "1234",
|
|
293
|
+
"ad_status": "active",
|
|
294
|
+
"advertiser": {...},
|
|
295
|
+
"body": "A nice ad.",
|
|
296
|
+
"category": [
|
|
297
|
+
{"id": "4000", "name": "Personligt"},
|
|
298
|
+
{"id": "4080", "name": "Kläder & skor"},
|
|
299
|
+
],
|
|
300
|
+
...
|
|
301
|
+
}
|
|
302
|
+
}
|
|
303
|
+
```
|
|
304
|
+
|
|
274
305
|
## 🔐 Blocket API token
|
|
275
306
|
|
|
276
307
|
There are two ways to acquire your token:
|
|
@@ -295,5 +326,6 @@ My token has never expired or changed during this project. However, if your're m
|
|
|
295
326
|
|
|
296
327
|
## 📝 Notes
|
|
297
328
|
|
|
329
|
+
- REST API: https://blocket-api.se
|
|
298
330
|
- Source repo: https://github.com/dunderrrrrr/blocket_api
|
|
299
331
|
- PyPI: https://pypi.org/project/blocket-api/
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
[](https://pypi.org/project/blocket_api/) [](https://github.com/dunderrrrrr/blocket_api/blob/main/LICENSE)  
|
|
4
4
|
|
|
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.
|
|
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 or as cleaned pydantic objects.
|
|
6
6
|
|
|
7
7
|
> Blocket is one of Sweden's largest online marketplaces. It was founded in 1996 and allows users to buy and sell a wide range of items, including cars, real estate, jobs, services, and second-hand goods. The platform is known for its extensive reach and user-friendly interface, making it a popular choice for Swedes looking to purchase or sell items quickly and efficiently.
|
|
8
8
|
|
|
@@ -17,12 +17,14 @@ BlocketAPI allows users to query saved searches, known as "Bevakningar", on [blo
|
|
|
17
17
|
|
|
18
18
|
## 🧑💻️ Install
|
|
19
19
|
|
|
20
|
-
BlocketAPI
|
|
20
|
+
Install BlocketAPI via PyPI...
|
|
21
21
|
|
|
22
22
|
```sh
|
|
23
23
|
pip install blocket-api
|
|
24
24
|
```
|
|
25
25
|
|
|
26
|
+
or use [blocket-api.se](https://blocket-api.se) without installing anything!
|
|
27
|
+
|
|
26
28
|
## 💁♀️ Usage
|
|
27
29
|
|
|
28
30
|
```py
|
|
@@ -46,9 +48,11 @@ Some calls require a `bearerToken`. However, some calls are public and don't req
|
|
|
46
48
|
| [`api.custom_search()`](#custom_search) | 👏 No | Yes | Search for everything on Blocket and filter by region |
|
|
47
49
|
| [`api.motor_search()`](#motor_search) | 👏 No | Yes | Advanced search for car-listings. |
|
|
48
50
|
| [`api.price_eval()`](#price_eval) | 👏 No | - | Vehicle purchase valuation and details. |
|
|
49
|
-
| [`api.home_search()`](#home_search) | 👏 No |
|
|
51
|
+
| [`api.home_search()`](#home_search) | 👏 No | Yes | Query home listings.
|
|
50
52
|
| [`api.store_search()`](#store_search) | 👏 No | Yes | Search for a store.
|
|
51
|
-
| [`api.get_store_listings()`](#get_store_listings) | 👏 No |
|
|
53
|
+
| [`api.get_store_listings()`](#get_store_listings) | 👏 No | Yes | Get listings from a specific store.
|
|
54
|
+
| [`api.get_ad_by_id()`](#get_ad_by_id) | 👏 No | Yes | Get ad data from id.
|
|
55
|
+
|
|
52
56
|
|
|
53
57
|
## 🤓 Detailed usage
|
|
54
58
|
|
|
@@ -116,7 +120,7 @@ Parameters:
|
|
|
116
120
|
- `as_objects` (`bool`, optional) - Return results as pydantic models, default is `False`.
|
|
117
121
|
|
|
118
122
|
```py
|
|
119
|
-
>>> from blocket_api import Region
|
|
123
|
+
>>> from blocket_api.blocket import Region, Category
|
|
120
124
|
>>> api.custom_search("saab", Region.blekinge) # search for term "saab" in region of "Blekinge"
|
|
121
125
|
{
|
|
122
126
|
"data":[
|
|
@@ -198,6 +202,7 @@ Query home listings from [bostad.blocket.se](https://bostad.blocket.se/).
|
|
|
198
202
|
- `order_by` (`OrderBy`, optional) - Sorting order, ex. `OrderBy.price`.
|
|
199
203
|
- `ordering` (`HOME_SEARCH_ORDERING`, optional) - Sorting order, ex. `"descending"`.
|
|
200
204
|
- `offset` (`int`, optional) - Offset for results, ex. `60`.
|
|
205
|
+
- `as_objects` (`bool`, optional) - Return results as pydantic models, default is False.
|
|
201
206
|
|
|
202
207
|
```py
|
|
203
208
|
>>> from blocket_api.qasa import HomeType, OrderBy
|
|
@@ -237,6 +242,8 @@ Get listings from a specific store.
|
|
|
237
242
|
|
|
238
243
|
- `store_id` (`int`, required) - The store id. Can be obtained by calling `store_search()`.
|
|
239
244
|
- `page` (`int`, optional) - The page number to return.
|
|
245
|
+
- `as_objects` (`bool`, optional) - Return results as pydantic models, default is `False`.
|
|
246
|
+
|
|
240
247
|
|
|
241
248
|
```py
|
|
242
249
|
>>> api.get_store_listings(1234)
|
|
@@ -254,6 +261,30 @@ Get listings from a specific store.
|
|
|
254
261
|
}
|
|
255
262
|
```
|
|
256
263
|
|
|
264
|
+
### get_ad_by_id
|
|
265
|
+
Get ad data from a specific ad id.
|
|
266
|
+
|
|
267
|
+
- `ad_id` (`int`, required) - The ad id. Can be found by calling any other method or from ad url.
|
|
268
|
+
- `as_objects` (`bool`, optional) - Return results as pydantic models, default is `False`.
|
|
269
|
+
|
|
270
|
+
|
|
271
|
+
```py
|
|
272
|
+
>>> api.get_ad_by_id(1234)
|
|
273
|
+
{
|
|
274
|
+
"data": {
|
|
275
|
+
"ad_id": "1234",
|
|
276
|
+
"ad_status": "active",
|
|
277
|
+
"advertiser": {...},
|
|
278
|
+
"body": "A nice ad.",
|
|
279
|
+
"category": [
|
|
280
|
+
{"id": "4000", "name": "Personligt"},
|
|
281
|
+
{"id": "4080", "name": "Kläder & skor"},
|
|
282
|
+
],
|
|
283
|
+
...
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
```
|
|
287
|
+
|
|
257
288
|
## 🔐 Blocket API token
|
|
258
289
|
|
|
259
290
|
There are two ways to acquire your token:
|
|
@@ -278,5 +309,6 @@ My token has never expired or changed during this project. However, if your're m
|
|
|
278
309
|
|
|
279
310
|
## 📝 Notes
|
|
280
311
|
|
|
312
|
+
- REST API: https://blocket-api.se
|
|
281
313
|
- Source repo: https://github.com/dunderrrrrr/blocket_api
|
|
282
314
|
- PyPI: https://pypi.org/project/blocket-api/
|
|
@@ -10,8 +10,11 @@ from typing import TYPE_CHECKING, Any, List, Literal, Optional, Tuple, Union, ov
|
|
|
10
10
|
import httpx
|
|
11
11
|
|
|
12
12
|
from blocket_api.models import (
|
|
13
|
+
AdByIdResults,
|
|
13
14
|
CustomSearchResults,
|
|
15
|
+
HomeSearchResults,
|
|
14
16
|
MotorSearchResults,
|
|
17
|
+
StoreListings,
|
|
15
18
|
StoreSearchResults,
|
|
16
19
|
)
|
|
17
20
|
from blocket_api.qasa import HOME_SEARCH_ORDERING, HomeType, OrderBy, Qasa
|
|
@@ -403,6 +406,7 @@ class BlocketAPI:
|
|
|
403
406
|
url = f"{BYTBIL_URL}/blocket-basedata-api/v3/vehicle-data/{registration_number}"
|
|
404
407
|
return _make_request(url=f"{url}", token=None).json()
|
|
405
408
|
|
|
409
|
+
@overload
|
|
406
410
|
def home_search(
|
|
407
411
|
self,
|
|
408
412
|
city: str,
|
|
@@ -410,19 +414,45 @@ class BlocketAPI:
|
|
|
410
414
|
order_by: OrderBy = OrderBy.published_at,
|
|
411
415
|
ordering: HOME_SEARCH_ORDERING = "descending",
|
|
412
416
|
offset: int = 0,
|
|
413
|
-
|
|
417
|
+
*,
|
|
418
|
+
as_objects: Literal[True],
|
|
419
|
+
) -> HomeSearchResults: ...
|
|
420
|
+
|
|
421
|
+
@overload
|
|
422
|
+
def home_search(
|
|
423
|
+
self,
|
|
424
|
+
city: str,
|
|
425
|
+
type: HomeType,
|
|
426
|
+
order_by: OrderBy = OrderBy.published_at,
|
|
427
|
+
ordering: HOME_SEARCH_ORDERING = "descending",
|
|
428
|
+
offset: int = 0,
|
|
429
|
+
*,
|
|
430
|
+
as_objects: Literal[False] = False,
|
|
431
|
+
) -> dict: ...
|
|
432
|
+
|
|
433
|
+
def home_search(
|
|
434
|
+
self,
|
|
435
|
+
city: str,
|
|
436
|
+
type: HomeType,
|
|
437
|
+
order_by: OrderBy = OrderBy.published_at,
|
|
438
|
+
ordering: HOME_SEARCH_ORDERING = "descending",
|
|
439
|
+
offset: int = 0,
|
|
440
|
+
*,
|
|
441
|
+
as_objects: bool = False,
|
|
442
|
+
) -> dict | HomeSearchResults:
|
|
414
443
|
"""
|
|
415
444
|
This returns all available home listings available at
|
|
416
445
|
https://bostad.blocket.se/. Specify offset to get next page. Each page contains
|
|
417
446
|
60 items, which is max items returned per api query.
|
|
418
447
|
"""
|
|
419
|
-
|
|
448
|
+
response = Qasa(
|
|
420
449
|
city=city,
|
|
421
450
|
home_type=type,
|
|
422
451
|
order_by=order_by,
|
|
423
452
|
ordering=ordering,
|
|
424
453
|
offset=offset,
|
|
425
454
|
).search()
|
|
455
|
+
return HomeSearchResults.model_validate(response) if as_objects else response
|
|
426
456
|
|
|
427
457
|
@overload
|
|
428
458
|
def search_store(
|
|
@@ -473,12 +503,32 @@ class BlocketAPI:
|
|
|
473
503
|
response = _make_request(url=f"{url}", token=self.token).json()
|
|
474
504
|
return StoreSearchResults.model_validate(response) if as_objects else response
|
|
475
505
|
|
|
506
|
+
@overload
|
|
507
|
+
def get_store_listings(
|
|
508
|
+
self,
|
|
509
|
+
store_id: int,
|
|
510
|
+
page: int = 0,
|
|
511
|
+
*,
|
|
512
|
+
as_objects: Literal[True],
|
|
513
|
+
) -> StoreListings: ...
|
|
514
|
+
|
|
515
|
+
@overload
|
|
516
|
+
def get_store_listings(
|
|
517
|
+
self,
|
|
518
|
+
store_id: int,
|
|
519
|
+
page: int = 0,
|
|
520
|
+
*,
|
|
521
|
+
as_objects: Literal[False] = False,
|
|
522
|
+
) -> dict: ...
|
|
523
|
+
|
|
476
524
|
@public_token
|
|
477
525
|
def get_store_listings(
|
|
478
526
|
self,
|
|
479
527
|
store_id: int,
|
|
480
528
|
page: int = 0,
|
|
481
|
-
|
|
529
|
+
*,
|
|
530
|
+
as_objects: bool = False,
|
|
531
|
+
) -> dict | StoreListings:
|
|
482
532
|
"""
|
|
483
533
|
Return all listings from a specific store from https://www.blocket.se/butik/<store>.
|
|
484
534
|
The store_id can be found by searching for the store with search_store().
|
|
@@ -487,4 +537,32 @@ class BlocketAPI:
|
|
|
487
537
|
f"{BASE_URL}/search_bff/v2/content?lim=60&page={page}&sort=rel&store_id={store_id}"
|
|
488
538
|
"&status=active&gl=3&include=extend_with_shipping"
|
|
489
539
|
)
|
|
490
|
-
|
|
540
|
+
response = _make_request(url=f"{url}", token=self.token).json()
|
|
541
|
+
return StoreListings.model_validate(response) if as_objects else response
|
|
542
|
+
|
|
543
|
+
@overload
|
|
544
|
+
def get_ad_by_id(
|
|
545
|
+
self,
|
|
546
|
+
ad_id: int,
|
|
547
|
+
*,
|
|
548
|
+
as_objects: Literal[True],
|
|
549
|
+
) -> AdByIdResults: ...
|
|
550
|
+
|
|
551
|
+
@overload
|
|
552
|
+
def get_ad_by_id(
|
|
553
|
+
self,
|
|
554
|
+
ad_id: int,
|
|
555
|
+
*,
|
|
556
|
+
as_objects: Literal[False] = False,
|
|
557
|
+
) -> dict: ...
|
|
558
|
+
|
|
559
|
+
@public_token
|
|
560
|
+
def get_ad_by_id(
|
|
561
|
+
self,
|
|
562
|
+
ad_id: int,
|
|
563
|
+
*,
|
|
564
|
+
as_objects: bool = False,
|
|
565
|
+
) -> dict | AdByIdResults:
|
|
566
|
+
url = f"{BASE_URL}/search_bff/v2/content/{ad_id}"
|
|
567
|
+
response = _make_request(url=f"{url}", token=self.token).json()
|
|
568
|
+
return AdByIdResults.model_validate(response) if as_objects else response
|
|
@@ -0,0 +1,536 @@
|
|
|
1
|
+
import datetime
|
|
2
|
+
from typing import Any
|
|
3
|
+
|
|
4
|
+
from pydantic import BaseModel
|
|
5
|
+
|
|
6
|
+
### CustomSearch ###
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class CustomSearchPrice(BaseModel):
|
|
10
|
+
suffix: str
|
|
11
|
+
value: int
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class CustomSearchLocation(BaseModel):
|
|
15
|
+
image_url: str
|
|
16
|
+
label: str
|
|
17
|
+
query_key: str | None = None
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
class CustomSearchImage(BaseModel):
|
|
21
|
+
height: int
|
|
22
|
+
type: str
|
|
23
|
+
url: str
|
|
24
|
+
width: int
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
class CustomSearchCategory(BaseModel):
|
|
28
|
+
id: str
|
|
29
|
+
name: str
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
class CustomSearchResult(BaseModel):
|
|
33
|
+
ad_id: str
|
|
34
|
+
ad_status: str
|
|
35
|
+
body: str
|
|
36
|
+
category: list[CustomSearchCategory]
|
|
37
|
+
images: list[CustomSearchImage] = []
|
|
38
|
+
list_id: str
|
|
39
|
+
list_time: datetime.datetime
|
|
40
|
+
map: CustomSearchLocation | None = None
|
|
41
|
+
map_url: str | None = None
|
|
42
|
+
price: CustomSearchPrice
|
|
43
|
+
share_url: str
|
|
44
|
+
state_id: str
|
|
45
|
+
subject: str
|
|
46
|
+
type: str
|
|
47
|
+
zipcode: str | None = None
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
class CustomSearchResults(BaseModel):
|
|
51
|
+
data: list[CustomSearchResult]
|
|
52
|
+
total_count: int
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
### MotorSearch ###
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
class MotorSearchCarEquipment(BaseModel):
|
|
59
|
+
label: str
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
class MotorSearchCarLocation(BaseModel):
|
|
63
|
+
region: str
|
|
64
|
+
municipality: str
|
|
65
|
+
area: str
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
class MotorSearchCarImage(BaseModel):
|
|
69
|
+
height: int
|
|
70
|
+
width: int
|
|
71
|
+
image: str
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
class MotorSearchCar(BaseModel):
|
|
75
|
+
images: list[MotorSearchCarImage]
|
|
76
|
+
location: MotorSearchCarLocation
|
|
77
|
+
fuel: str
|
|
78
|
+
gearbox: str
|
|
79
|
+
regDate: int
|
|
80
|
+
mileage: int
|
|
81
|
+
equipment: list[MotorSearchCarEquipment] | None = None
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
class MotorSearchPrice(BaseModel):
|
|
85
|
+
amount: str
|
|
86
|
+
billingPeriod: str
|
|
87
|
+
oldPrice: str | None = None
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
class MotorSearchSeller(BaseModel):
|
|
91
|
+
type: str
|
|
92
|
+
name: str
|
|
93
|
+
id: str
|
|
94
|
+
|
|
95
|
+
|
|
96
|
+
class MotorSearchResult(BaseModel):
|
|
97
|
+
dealId: str
|
|
98
|
+
link: str
|
|
99
|
+
listTime: datetime.datetime
|
|
100
|
+
originalListTime: datetime.datetime
|
|
101
|
+
seller: MotorSearchSeller
|
|
102
|
+
heading: str
|
|
103
|
+
price: MotorSearchPrice
|
|
104
|
+
thumbnail: str
|
|
105
|
+
car: MotorSearchCar
|
|
106
|
+
description: str
|
|
107
|
+
|
|
108
|
+
|
|
109
|
+
class MotorSearchResults(BaseModel):
|
|
110
|
+
cars: list[MotorSearchResult]
|
|
111
|
+
hits: int
|
|
112
|
+
pages: int
|
|
113
|
+
|
|
114
|
+
|
|
115
|
+
### StoreSearch ###
|
|
116
|
+
|
|
117
|
+
|
|
118
|
+
class StoreSearchLocation(BaseModel):
|
|
119
|
+
longitude: float
|
|
120
|
+
latitude: float
|
|
121
|
+
|
|
122
|
+
|
|
123
|
+
class StoreSearchImage(BaseModel):
|
|
124
|
+
height: int
|
|
125
|
+
width: int
|
|
126
|
+
url: str
|
|
127
|
+
|
|
128
|
+
|
|
129
|
+
class StoreSearchLogotype(BaseModel):
|
|
130
|
+
height: int
|
|
131
|
+
width: int
|
|
132
|
+
url: str
|
|
133
|
+
|
|
134
|
+
|
|
135
|
+
class StoreSearchResult(BaseModel):
|
|
136
|
+
address: str | None = None
|
|
137
|
+
id: str
|
|
138
|
+
logotype: StoreSearchLogotype
|
|
139
|
+
image: StoreSearchImage | None = None
|
|
140
|
+
description: str
|
|
141
|
+
external_store_url: str | None = None
|
|
142
|
+
location: StoreSearchLocation | None = None
|
|
143
|
+
name: str
|
|
144
|
+
title: str
|
|
145
|
+
ad_count: int
|
|
146
|
+
category: str
|
|
147
|
+
|
|
148
|
+
|
|
149
|
+
class StoreSearchResults(BaseModel):
|
|
150
|
+
data: list[StoreSearchResult]
|
|
151
|
+
total_count: int
|
|
152
|
+
total_page_count: int
|
|
153
|
+
|
|
154
|
+
|
|
155
|
+
### HomeSearch ###
|
|
156
|
+
|
|
157
|
+
|
|
158
|
+
class HomeSearchGeoPoint(BaseModel):
|
|
159
|
+
lat: float
|
|
160
|
+
lon: float
|
|
161
|
+
|
|
162
|
+
|
|
163
|
+
class HomeSearchLocation(BaseModel):
|
|
164
|
+
id: int
|
|
165
|
+
locality: str
|
|
166
|
+
countryCode: str
|
|
167
|
+
streetNumber: str | None = None
|
|
168
|
+
point: HomeSearchGeoPoint
|
|
169
|
+
route: str
|
|
170
|
+
|
|
171
|
+
|
|
172
|
+
class HomeSearchUpload(BaseModel):
|
|
173
|
+
id: int
|
|
174
|
+
order: int | None = None
|
|
175
|
+
type: str
|
|
176
|
+
url: str
|
|
177
|
+
|
|
178
|
+
|
|
179
|
+
class HomeSearchResult(BaseModel):
|
|
180
|
+
bedroomCount: int | None = None
|
|
181
|
+
blockListing: bool
|
|
182
|
+
rentalLengthSeconds: float | None = None
|
|
183
|
+
householdSize: int
|
|
184
|
+
corporateHome: bool
|
|
185
|
+
description: str
|
|
186
|
+
endDate: str | None = None
|
|
187
|
+
firstHand: bool
|
|
188
|
+
furnished: bool
|
|
189
|
+
homeType: str
|
|
190
|
+
id: str
|
|
191
|
+
instantSign: bool
|
|
192
|
+
market: str
|
|
193
|
+
lastBumpedAt: str | None = None
|
|
194
|
+
monthlyCost: int
|
|
195
|
+
petsAllowed: bool
|
|
196
|
+
platform: str
|
|
197
|
+
publishedAt: str
|
|
198
|
+
publishedOrBumpedAt: str
|
|
199
|
+
earlyAccessEndsAt: str | None = None
|
|
200
|
+
rent: int
|
|
201
|
+
currency: str
|
|
202
|
+
roomCount: int
|
|
203
|
+
seniorHome: bool
|
|
204
|
+
shared: bool
|
|
205
|
+
shortcutHome: bool
|
|
206
|
+
smokingAllowed: bool
|
|
207
|
+
sortingScore: float
|
|
208
|
+
squareMeters: int
|
|
209
|
+
startDate: str
|
|
210
|
+
studentHome: bool
|
|
211
|
+
tenantBaseFee: int
|
|
212
|
+
title: str | None = None
|
|
213
|
+
wheelchairAccessible: bool
|
|
214
|
+
location: HomeSearchLocation
|
|
215
|
+
displayStreetNumber: bool
|
|
216
|
+
uploads: list[HomeSearchUpload]
|
|
217
|
+
|
|
218
|
+
|
|
219
|
+
class Documents(BaseModel):
|
|
220
|
+
hasNextPage: bool
|
|
221
|
+
hasPreviousPage: bool
|
|
222
|
+
nodes: list[HomeSearchResult]
|
|
223
|
+
pagesCount: int
|
|
224
|
+
totalCount: int
|
|
225
|
+
|
|
226
|
+
|
|
227
|
+
class HomeIndexSearch(BaseModel):
|
|
228
|
+
documents: Documents
|
|
229
|
+
|
|
230
|
+
|
|
231
|
+
class DataModel(BaseModel):
|
|
232
|
+
homeIndexSearch: HomeIndexSearch
|
|
233
|
+
|
|
234
|
+
|
|
235
|
+
class HomeSearchResults(BaseModel):
|
|
236
|
+
data: DataModel
|
|
237
|
+
|
|
238
|
+
|
|
239
|
+
### StoreListings ###
|
|
240
|
+
|
|
241
|
+
|
|
242
|
+
class StoreListingContactMethods(BaseModel):
|
|
243
|
+
phone: bool
|
|
244
|
+
|
|
245
|
+
|
|
246
|
+
class StoreListingAdvertiser(BaseModel):
|
|
247
|
+
contact_methods: StoreListingContactMethods
|
|
248
|
+
name: str
|
|
249
|
+
store_name: str | None = None
|
|
250
|
+
type: str
|
|
251
|
+
|
|
252
|
+
|
|
253
|
+
class StoreListingAttribute(BaseModel):
|
|
254
|
+
header: str
|
|
255
|
+
id: str
|
|
256
|
+
items: list[str]
|
|
257
|
+
|
|
258
|
+
|
|
259
|
+
class StoreListingCategory(BaseModel):
|
|
260
|
+
id: str
|
|
261
|
+
name: str
|
|
262
|
+
|
|
263
|
+
|
|
264
|
+
class StoreListingImage(BaseModel):
|
|
265
|
+
height: int
|
|
266
|
+
type: str
|
|
267
|
+
url: str
|
|
268
|
+
width: int
|
|
269
|
+
|
|
270
|
+
|
|
271
|
+
class StorListingLocationItem(BaseModel):
|
|
272
|
+
id: str
|
|
273
|
+
name: str
|
|
274
|
+
query_key: str
|
|
275
|
+
|
|
276
|
+
|
|
277
|
+
class StoreListingParameter(BaseModel):
|
|
278
|
+
id: str
|
|
279
|
+
label: str
|
|
280
|
+
value: str
|
|
281
|
+
suffix: str | None = None
|
|
282
|
+
|
|
283
|
+
|
|
284
|
+
class ParameterGroup(BaseModel):
|
|
285
|
+
label: str
|
|
286
|
+
parameters: list[StoreListingParameter]
|
|
287
|
+
type: str
|
|
288
|
+
|
|
289
|
+
|
|
290
|
+
class StoreListingPartnerInfo(BaseModel):
|
|
291
|
+
external_id: str
|
|
292
|
+
name: str
|
|
293
|
+
|
|
294
|
+
|
|
295
|
+
class StoreListingPrice(BaseModel):
|
|
296
|
+
suffix: str
|
|
297
|
+
value: int
|
|
298
|
+
|
|
299
|
+
|
|
300
|
+
class StoreListing(BaseModel):
|
|
301
|
+
ad_id: str
|
|
302
|
+
ad_status: str
|
|
303
|
+
advertiser: StoreListingAdvertiser
|
|
304
|
+
attributes: list[StoreListingAttribute]
|
|
305
|
+
body: str
|
|
306
|
+
category: list[StoreListingCategory]
|
|
307
|
+
images: list[StoreListingImage]
|
|
308
|
+
license_plate: str | None = None
|
|
309
|
+
list_id: str
|
|
310
|
+
list_time: str
|
|
311
|
+
location: list[StorListingLocationItem]
|
|
312
|
+
map_url: str | None = None
|
|
313
|
+
parameter_groups: list[ParameterGroup]
|
|
314
|
+
partner_info: StoreListingPartnerInfo
|
|
315
|
+
price: StoreListingPrice
|
|
316
|
+
share_url: str
|
|
317
|
+
state_id: str
|
|
318
|
+
subject: str
|
|
319
|
+
type: str
|
|
320
|
+
|
|
321
|
+
|
|
322
|
+
class StoreListings(BaseModel):
|
|
323
|
+
data: list[StoreListing]
|
|
324
|
+
|
|
325
|
+
|
|
326
|
+
### GetAdById ###
|
|
327
|
+
|
|
328
|
+
|
|
329
|
+
class AdByIdReviews(BaseModel):
|
|
330
|
+
overall_score: int
|
|
331
|
+
reviews_received_count: int
|
|
332
|
+
|
|
333
|
+
|
|
334
|
+
class AdByIdPublicProfile(BaseModel):
|
|
335
|
+
account_created_at: str
|
|
336
|
+
badges: list[Any]
|
|
337
|
+
blocket_account_id: str
|
|
338
|
+
display_name: str
|
|
339
|
+
number_of_active_ads: int
|
|
340
|
+
reviews: AdByIdReviews
|
|
341
|
+
verified: bool
|
|
342
|
+
verified_label: str
|
|
343
|
+
|
|
344
|
+
|
|
345
|
+
class AdByIdContactMethods(BaseModel):
|
|
346
|
+
mc: bool
|
|
347
|
+
|
|
348
|
+
|
|
349
|
+
class AdByIdAdvertiser(BaseModel):
|
|
350
|
+
account_id: str
|
|
351
|
+
contact_methods: AdByIdContactMethods
|
|
352
|
+
name: str
|
|
353
|
+
public_profile: AdByIdPublicProfile
|
|
354
|
+
type: str
|
|
355
|
+
|
|
356
|
+
|
|
357
|
+
class AdByIdCategory(BaseModel):
|
|
358
|
+
id: str
|
|
359
|
+
name: str
|
|
360
|
+
|
|
361
|
+
|
|
362
|
+
class AdByIdImage(BaseModel):
|
|
363
|
+
height: int
|
|
364
|
+
type: str
|
|
365
|
+
url: str
|
|
366
|
+
width: int
|
|
367
|
+
|
|
368
|
+
|
|
369
|
+
class AdByIdLocation(BaseModel):
|
|
370
|
+
id: str
|
|
371
|
+
name: str
|
|
372
|
+
query_key: str
|
|
373
|
+
|
|
374
|
+
|
|
375
|
+
class AdByIdMap(BaseModel):
|
|
376
|
+
image_url: str
|
|
377
|
+
label: str
|
|
378
|
+
type: str
|
|
379
|
+
|
|
380
|
+
|
|
381
|
+
class AdByIdParameter(BaseModel):
|
|
382
|
+
id: str
|
|
383
|
+
label: str
|
|
384
|
+
value: str
|
|
385
|
+
suffix: str | None = None
|
|
386
|
+
|
|
387
|
+
|
|
388
|
+
class AdByIdParameterGroup(BaseModel):
|
|
389
|
+
label: str
|
|
390
|
+
parameters: list[AdByIdParameter]
|
|
391
|
+
type: str
|
|
392
|
+
|
|
393
|
+
|
|
394
|
+
class AdByIdPrice(BaseModel):
|
|
395
|
+
suffix: str
|
|
396
|
+
value: int
|
|
397
|
+
|
|
398
|
+
|
|
399
|
+
class AdByIdFeatures(BaseModel):
|
|
400
|
+
is_part_of_merge: bool
|
|
401
|
+
|
|
402
|
+
|
|
403
|
+
class AdByIdUrls(BaseModel):
|
|
404
|
+
seller_activate: str
|
|
405
|
+
|
|
406
|
+
|
|
407
|
+
class AdByIdBlocketPackage(BaseModel):
|
|
408
|
+
activated_providers: list[Any]
|
|
409
|
+
ad_id: str
|
|
410
|
+
blocket_payment_backwards_compatability: Any
|
|
411
|
+
buyers_protection_fee: Any
|
|
412
|
+
eligible_providers: list[Any]
|
|
413
|
+
fail_code: Any
|
|
414
|
+
failure: Any
|
|
415
|
+
feature_swish: bool
|
|
416
|
+
features: AdByIdFeatures
|
|
417
|
+
is_in_dispute: bool
|
|
418
|
+
partner: str
|
|
419
|
+
payment_methods: list[Any]
|
|
420
|
+
payment_request_entrance: Any
|
|
421
|
+
payment_url: Any
|
|
422
|
+
service_data: Any
|
|
423
|
+
shipping_buy_now_entrance: Any
|
|
424
|
+
state: str
|
|
425
|
+
transaction_dates: Any
|
|
426
|
+
urls: AdByIdUrls
|
|
427
|
+
|
|
428
|
+
|
|
429
|
+
class AdByIdGamApiKeywords(BaseModel):
|
|
430
|
+
adid: list[str]
|
|
431
|
+
adtitle: list[str]
|
|
432
|
+
adtype: list[str]
|
|
433
|
+
appmode: list[str]
|
|
434
|
+
blocket_section: list[str]
|
|
435
|
+
companyad: list[str]
|
|
436
|
+
country: list[str]
|
|
437
|
+
country_code: list[str]
|
|
438
|
+
county: list[str]
|
|
439
|
+
id: list[str]
|
|
440
|
+
itemimage: list[str]
|
|
441
|
+
itemsecuredthumb: list[str]
|
|
442
|
+
itemthumb: list[str]
|
|
443
|
+
livingarea: list[str] | None = None
|
|
444
|
+
lkf: list[str]
|
|
445
|
+
municipality: list[str]
|
|
446
|
+
nmp_vertical: list[str]
|
|
447
|
+
page: list[str]
|
|
448
|
+
price: list[str]
|
|
449
|
+
price_range_2: list[str] | None = None
|
|
450
|
+
publisher: list[str]
|
|
451
|
+
services: list[Any]
|
|
452
|
+
|
|
453
|
+
|
|
454
|
+
class AdByIdClientKeywords(BaseModel):
|
|
455
|
+
cmp_advertising: str
|
|
456
|
+
logged_in: str
|
|
457
|
+
page_gen: str
|
|
458
|
+
ppid_1: str
|
|
459
|
+
ppid_2: str
|
|
460
|
+
screen_height: str
|
|
461
|
+
screen_width: str
|
|
462
|
+
site_mode: str
|
|
463
|
+
supply_type: str
|
|
464
|
+
viewport_height: str
|
|
465
|
+
viewport_width: str
|
|
466
|
+
|
|
467
|
+
|
|
468
|
+
class AdByIdGamContext(BaseModel):
|
|
469
|
+
api_keywords: AdByIdGamApiKeywords
|
|
470
|
+
client_keywords: AdByIdClientKeywords
|
|
471
|
+
|
|
472
|
+
|
|
473
|
+
class AdByIdContext(BaseModel):
|
|
474
|
+
gam: AdByIdGamContext
|
|
475
|
+
network_id: str | None = None
|
|
476
|
+
|
|
477
|
+
|
|
478
|
+
class AdByIdInventory(BaseModel):
|
|
479
|
+
context: AdByIdContext
|
|
480
|
+
|
|
481
|
+
|
|
482
|
+
class AdByIdGamKeywords(BaseModel):
|
|
483
|
+
adformat: list[str]
|
|
484
|
+
adsize: list[str]
|
|
485
|
+
|
|
486
|
+
|
|
487
|
+
class AdByIdGamMediaType(BaseModel):
|
|
488
|
+
height: int | None = None
|
|
489
|
+
type: str
|
|
490
|
+
width: int | None = None
|
|
491
|
+
|
|
492
|
+
|
|
493
|
+
class AdByIdGamPlacement(BaseModel):
|
|
494
|
+
keywords: AdByIdGamKeywords
|
|
495
|
+
media_types: list[AdByIdGamMediaType]
|
|
496
|
+
path: str
|
|
497
|
+
target_id: str
|
|
498
|
+
|
|
499
|
+
|
|
500
|
+
class AdByIdPlacement(BaseModel):
|
|
501
|
+
gam: AdByIdGamPlacement | None = None
|
|
502
|
+
type: str
|
|
503
|
+
vendor: str
|
|
504
|
+
viewport: str
|
|
505
|
+
safe_purchase: dict[str, Any] | None = None
|
|
506
|
+
|
|
507
|
+
|
|
508
|
+
class AdByIdData(BaseModel):
|
|
509
|
+
ad_id: str
|
|
510
|
+
ad_status: str
|
|
511
|
+
advertiser: AdByIdAdvertiser
|
|
512
|
+
body: str
|
|
513
|
+
category: list[AdByIdCategory]
|
|
514
|
+
images: list[AdByIdImage]
|
|
515
|
+
latitude: float | None = None
|
|
516
|
+
list_id: str
|
|
517
|
+
list_time: str
|
|
518
|
+
location: list[AdByIdLocation]
|
|
519
|
+
longitude: float | None = None
|
|
520
|
+
map: AdByIdMap
|
|
521
|
+
map_url: str
|
|
522
|
+
parameter_groups: list[AdByIdParameterGroup]
|
|
523
|
+
price: AdByIdPrice
|
|
524
|
+
saved: bool
|
|
525
|
+
share_url: str
|
|
526
|
+
state_id: str
|
|
527
|
+
subject: str
|
|
528
|
+
type: str
|
|
529
|
+
zipcode: str
|
|
530
|
+
blocket_package: AdByIdBlocketPackage
|
|
531
|
+
|
|
532
|
+
|
|
533
|
+
class AdByIdResults(BaseModel):
|
|
534
|
+
data: AdByIdData
|
|
535
|
+
inventory: AdByIdInventory
|
|
536
|
+
placements: list[AdByIdPlacement] | None = None
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: blocket_api
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.3.0
|
|
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
|
|
@@ -12,14 +12,14 @@ Requires-Dist: pytest>=8.2.2
|
|
|
12
12
|
Requires-Dist: respx>=0.21.1
|
|
13
13
|
Requires-Dist: mypy>=1.15.0
|
|
14
14
|
Requires-Dist: pydantic>=2.11.7
|
|
15
|
-
Requires-Dist: ruff>=0.13.
|
|
15
|
+
Requires-Dist: ruff>=0.13.1
|
|
16
16
|
Dynamic: license-file
|
|
17
17
|
|
|
18
18
|
# BlocketAPI
|
|
19
19
|
|
|
20
20
|
[](https://pypi.org/project/blocket_api/) [](https://github.com/dunderrrrrr/blocket_api/blob/main/LICENSE)  
|
|
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
|
+
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 or as cleaned pydantic objects.
|
|
23
23
|
|
|
24
24
|
> Blocket is one of Sweden's largest online marketplaces. It was founded in 1996 and allows users to buy and sell a wide range of items, including cars, real estate, jobs, services, and second-hand goods. The platform is known for its extensive reach and user-friendly interface, making it a popular choice for Swedes looking to purchase or sell items quickly and efficiently.
|
|
25
25
|
|
|
@@ -34,12 +34,14 @@ BlocketAPI allows users to query saved searches, known as "Bevakningar", on [blo
|
|
|
34
34
|
|
|
35
35
|
## 🧑💻️ Install
|
|
36
36
|
|
|
37
|
-
BlocketAPI
|
|
37
|
+
Install BlocketAPI via PyPI...
|
|
38
38
|
|
|
39
39
|
```sh
|
|
40
40
|
pip install blocket-api
|
|
41
41
|
```
|
|
42
42
|
|
|
43
|
+
or use [blocket-api.se](https://blocket-api.se) without installing anything!
|
|
44
|
+
|
|
43
45
|
## 💁♀️ Usage
|
|
44
46
|
|
|
45
47
|
```py
|
|
@@ -63,9 +65,11 @@ Some calls require a `bearerToken`. However, some calls are public and don't req
|
|
|
63
65
|
| [`api.custom_search()`](#custom_search) | 👏 No | Yes | Search for everything on Blocket and filter by region |
|
|
64
66
|
| [`api.motor_search()`](#motor_search) | 👏 No | Yes | Advanced search for car-listings. |
|
|
65
67
|
| [`api.price_eval()`](#price_eval) | 👏 No | - | Vehicle purchase valuation and details. |
|
|
66
|
-
| [`api.home_search()`](#home_search) | 👏 No |
|
|
68
|
+
| [`api.home_search()`](#home_search) | 👏 No | Yes | Query home listings.
|
|
67
69
|
| [`api.store_search()`](#store_search) | 👏 No | Yes | Search for a store.
|
|
68
|
-
| [`api.get_store_listings()`](#get_store_listings) | 👏 No |
|
|
70
|
+
| [`api.get_store_listings()`](#get_store_listings) | 👏 No | Yes | Get listings from a specific store.
|
|
71
|
+
| [`api.get_ad_by_id()`](#get_ad_by_id) | 👏 No | Yes | Get ad data from id.
|
|
72
|
+
|
|
69
73
|
|
|
70
74
|
## 🤓 Detailed usage
|
|
71
75
|
|
|
@@ -133,7 +137,7 @@ Parameters:
|
|
|
133
137
|
- `as_objects` (`bool`, optional) - Return results as pydantic models, default is `False`.
|
|
134
138
|
|
|
135
139
|
```py
|
|
136
|
-
>>> from blocket_api import Region
|
|
140
|
+
>>> from blocket_api.blocket import Region, Category
|
|
137
141
|
>>> api.custom_search("saab", Region.blekinge) # search for term "saab" in region of "Blekinge"
|
|
138
142
|
{
|
|
139
143
|
"data":[
|
|
@@ -215,6 +219,7 @@ Query home listings from [bostad.blocket.se](https://bostad.blocket.se/).
|
|
|
215
219
|
- `order_by` (`OrderBy`, optional) - Sorting order, ex. `OrderBy.price`.
|
|
216
220
|
- `ordering` (`HOME_SEARCH_ORDERING`, optional) - Sorting order, ex. `"descending"`.
|
|
217
221
|
- `offset` (`int`, optional) - Offset for results, ex. `60`.
|
|
222
|
+
- `as_objects` (`bool`, optional) - Return results as pydantic models, default is False.
|
|
218
223
|
|
|
219
224
|
```py
|
|
220
225
|
>>> from blocket_api.qasa import HomeType, OrderBy
|
|
@@ -254,6 +259,8 @@ Get listings from a specific store.
|
|
|
254
259
|
|
|
255
260
|
- `store_id` (`int`, required) - The store id. Can be obtained by calling `store_search()`.
|
|
256
261
|
- `page` (`int`, optional) - The page number to return.
|
|
262
|
+
- `as_objects` (`bool`, optional) - Return results as pydantic models, default is `False`.
|
|
263
|
+
|
|
257
264
|
|
|
258
265
|
```py
|
|
259
266
|
>>> api.get_store_listings(1234)
|
|
@@ -271,6 +278,30 @@ Get listings from a specific store.
|
|
|
271
278
|
}
|
|
272
279
|
```
|
|
273
280
|
|
|
281
|
+
### get_ad_by_id
|
|
282
|
+
Get ad data from a specific ad id.
|
|
283
|
+
|
|
284
|
+
- `ad_id` (`int`, required) - The ad id. Can be found by calling any other method or from ad url.
|
|
285
|
+
- `as_objects` (`bool`, optional) - Return results as pydantic models, default is `False`.
|
|
286
|
+
|
|
287
|
+
|
|
288
|
+
```py
|
|
289
|
+
>>> api.get_ad_by_id(1234)
|
|
290
|
+
{
|
|
291
|
+
"data": {
|
|
292
|
+
"ad_id": "1234",
|
|
293
|
+
"ad_status": "active",
|
|
294
|
+
"advertiser": {...},
|
|
295
|
+
"body": "A nice ad.",
|
|
296
|
+
"category": [
|
|
297
|
+
{"id": "4000", "name": "Personligt"},
|
|
298
|
+
{"id": "4080", "name": "Kläder & skor"},
|
|
299
|
+
],
|
|
300
|
+
...
|
|
301
|
+
}
|
|
302
|
+
}
|
|
303
|
+
```
|
|
304
|
+
|
|
274
305
|
## 🔐 Blocket API token
|
|
275
306
|
|
|
276
307
|
There are two ways to acquire your token:
|
|
@@ -295,5 +326,6 @@ My token has never expired or changed during this project. However, if your're m
|
|
|
295
326
|
|
|
296
327
|
## 📝 Notes
|
|
297
328
|
|
|
329
|
+
- REST API: https://blocket-api.se
|
|
298
330
|
- Source repo: https://github.com/dunderrrrrr/blocket_api
|
|
299
331
|
- PyPI: https://pypi.org/project/blocket-api/
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "blocket_api"
|
|
3
|
-
version = "0.
|
|
3
|
+
version = "0.3.0"
|
|
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"
|
|
@@ -12,7 +12,7 @@ dependencies = [
|
|
|
12
12
|
"respx>=0.21.1",
|
|
13
13
|
"mypy>=1.15.0",
|
|
14
14
|
"pydantic>=2.11.7",
|
|
15
|
-
"ruff>=0.13.
|
|
15
|
+
"ruff>=0.13.1",
|
|
16
16
|
]
|
|
17
17
|
|
|
18
18
|
|
|
@@ -1,151 +0,0 @@
|
|
|
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
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|