blocket-api 0.3.1__tar.gz → 0.3.4__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.3.1
3
+ Version: 0.3.4
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,12 +12,19 @@ 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.1
15
+ Requires-Dist: mkdocs>=1.6.1
16
+ Requires-Dist: mkdocs-material>=9.6.21
17
+ Requires-Dist: mkdocs-swagger-ui-tag>=0.7.2
18
+ Requires-Dist: ruff>=0.14.1
16
19
  Dynamic: license-file
17
20
 
21
+ <p align="center">
22
+ <img src="https://blocket-api.se/blocket-api.png" />
23
+ </p>
24
+
18
25
  # BlocketAPI
19
26
 
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)
27
+ [![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/dw/blocket_api?style=for-the-badge&color=%23dbce58)
21
28
 
22
29
  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
30
 
@@ -61,7 +68,7 @@ Some calls require a `bearerToken`. However, some calls are public and don't req
61
68
 
62
69
  | Function | Token required | `as_objects` | Description |
63
70
  |---|---|---|---|
64
- | [`api.saved_searches()`](#saved_searches) | 🔐 Yes | - | List your saved searches (bevakningar) |
71
+ | [`api.saved_searches()`](#saved_searches) | 🔐 Yes | Yes | List your saved searches (bevakningar) |
65
72
  | [`api.get_listings()`](#get_listings) | 🔐 Yes | - | List items related to a saved search |
66
73
  | [`api.custom_search()`](#custom_search) | 👏 No | Yes | Search for everything on Blocket and filter by region |
67
74
  | [`api.motor_search()`](#motor_search) | 👏 No | Yes | Advanced search for car-listings. |
@@ -71,6 +78,8 @@ Some calls require a `bearerToken`. However, some calls are public and don't req
71
78
  | [`api.get_store_listings()`](#get_store_listings) | 👏 No | Yes | Get listings from a specific store.
72
79
  | [`api.get_ad_by_id()`](#get_ad_by_id) | 👏 No | Yes | Get ad data from id.
73
80
  | [`api.get_user_by_id()`](#get_user_by_id) | 👏 No | Yes | Get user data from id.
81
+ | [`api.save_ad()`](#save_ad) | 🔐 Yes | - | Save ad to "Saved ads".
82
+ | [`api.get_saved_ads()`](#get_saved_ads) | 🔐 Yes | - | List all saved ads.
74
83
 
75
84
 
76
85
  ## 🤓 Detailed usage
@@ -79,6 +88,9 @@ Some calls require a `bearerToken`. However, some calls are public and don't req
79
88
 
80
89
  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.
81
90
 
91
+ Parameters:
92
+ - `as_objects` (`bool`, optional) - Return results as pydantic models, default is `False`.
93
+
82
94
  ```py
83
95
  >>> api.saved_searches()
84
96
  [
@@ -327,6 +339,33 @@ Get user data from a user id. User id can be found in ads, searches and in block
327
339
  }
328
340
  ```
329
341
 
342
+ ### save_ad
343
+ This saves the ad to "Saved ads" which can be found here at `https://www.blocket.se/sparade/annonser`. When saving an ad, blocket always responds with 204, even if the ad is already saved or does not exist.
344
+
345
+ - `ad_id` (`int`, required) - The ad id. Can be found by calling any other method or from ad url.
346
+
347
+ ```py
348
+ >>> api.save_ad(1234)
349
+ ```
350
+
351
+ ### get_saved_ads
352
+ Returns all of your saved ads from `https://www.blocket.se/sparade/annonser`.
353
+
354
+ ```py
355
+ >>> api.get_saved_ads()
356
+ {
357
+ 'data': [{
358
+ 'ad_id': '1213682185'
359
+ 'list_id': '1213682185'
360
+ 'subject': 'Jeans från Gina tricot 158'
361
+ 'body': 'Moderna jeans från Gina Tricot!'
362
+ ...
363
+ }]
364
+ ...
365
+ }
366
+
367
+ ```
368
+
330
369
  ## 🔐 Blocket API token
331
370
 
332
371
  There are two ways to acquire your token:
@@ -1,23 +1,10 @@
1
- Metadata-Version: 2.4
2
- Name: blocket_api
3
- Version: 0.3.1
4
- Summary: A python API wrapper for blocket.se
5
- Author-email: dunderrrrrr <emil.bjorkroth@gmail.com>
6
- Requires-Python: >=3.10
7
- Description-Content-Type: text/markdown
8
- License-File: LICENSE
9
- Requires-Dist: httpx>=0.27.0
10
- Requires-Dist: pre-commit>=3.7.1
11
- Requires-Dist: pytest>=8.2.2
12
- Requires-Dist: respx>=0.21.1
13
- Requires-Dist: mypy>=1.15.0
14
- Requires-Dist: pydantic>=2.11.7
15
- Requires-Dist: ruff>=0.13.1
16
- Dynamic: license-file
1
+ <p align="center">
2
+ <img src="https://blocket-api.se/blocket-api.png" />
3
+ </p>
17
4
 
18
5
  # BlocketAPI
19
6
 
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)
7
+ [![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/dw/blocket_api?style=for-the-badge&color=%23dbce58)
21
8
 
22
9
  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
10
 
@@ -61,7 +48,7 @@ Some calls require a `bearerToken`. However, some calls are public and don't req
61
48
 
62
49
  | Function | Token required | `as_objects` | Description |
63
50
  |---|---|---|---|
64
- | [`api.saved_searches()`](#saved_searches) | 🔐 Yes | - | List your saved searches (bevakningar) |
51
+ | [`api.saved_searches()`](#saved_searches) | 🔐 Yes | Yes | List your saved searches (bevakningar) |
65
52
  | [`api.get_listings()`](#get_listings) | 🔐 Yes | - | List items related to a saved search |
66
53
  | [`api.custom_search()`](#custom_search) | 👏 No | Yes | Search for everything on Blocket and filter by region |
67
54
  | [`api.motor_search()`](#motor_search) | 👏 No | Yes | Advanced search for car-listings. |
@@ -71,6 +58,8 @@ Some calls require a `bearerToken`. However, some calls are public and don't req
71
58
  | [`api.get_store_listings()`](#get_store_listings) | 👏 No | Yes | Get listings from a specific store.
72
59
  | [`api.get_ad_by_id()`](#get_ad_by_id) | 👏 No | Yes | Get ad data from id.
73
60
  | [`api.get_user_by_id()`](#get_user_by_id) | 👏 No | Yes | Get user data from id.
61
+ | [`api.save_ad()`](#save_ad) | 🔐 Yes | - | Save ad to "Saved ads".
62
+ | [`api.get_saved_ads()`](#get_saved_ads) | 🔐 Yes | - | List all saved ads.
74
63
 
75
64
 
76
65
  ## 🤓 Detailed usage
@@ -79,6 +68,9 @@ Some calls require a `bearerToken`. However, some calls are public and don't req
79
68
 
80
69
  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.
81
70
 
71
+ Parameters:
72
+ - `as_objects` (`bool`, optional) - Return results as pydantic models, default is `False`.
73
+
82
74
  ```py
83
75
  >>> api.saved_searches()
84
76
  [
@@ -327,6 +319,33 @@ Get user data from a user id. User id can be found in ads, searches and in block
327
319
  }
328
320
  ```
329
321
 
322
+ ### save_ad
323
+ This saves the ad to "Saved ads" which can be found here at `https://www.blocket.se/sparade/annonser`. When saving an ad, blocket always responds with 204, even if the ad is already saved or does not exist.
324
+
325
+ - `ad_id` (`int`, required) - The ad id. Can be found by calling any other method or from ad url.
326
+
327
+ ```py
328
+ >>> api.save_ad(1234)
329
+ ```
330
+
331
+ ### get_saved_ads
332
+ Returns all of your saved ads from `https://www.blocket.se/sparade/annonser`.
333
+
334
+ ```py
335
+ >>> api.get_saved_ads()
336
+ {
337
+ 'data': [{
338
+ 'ad_id': '1213682185'
339
+ 'list_id': '1213682185'
340
+ 'subject': 'Jeans från Gina tricot 158'
341
+ 'body': 'Moderna jeans från Gina Tricot!'
342
+ ...
343
+ }]
344
+ ...
345
+ }
346
+
347
+ ```
348
+
330
349
  ## 🔐 Blocket API token
331
350
 
332
351
  There are two ways to acquire your token:
@@ -15,6 +15,7 @@ from blocket_api.models import (
15
15
  CustomSearchResults,
16
16
  HomeSearchResults,
17
17
  MotorSearchResults,
18
+ SavedSearchResponse,
18
19
  StoreListings,
19
20
  StoreSearchResults,
20
21
  )
@@ -165,7 +166,11 @@ def public_token(method: Callable) -> Callable:
165
166
 
166
167
 
167
168
  def _make_request(
168
- *, url: str, token: str | None, raise_for_status: bool = True
169
+ *,
170
+ method: Callable[..., Response] = httpx.get,
171
+ url: str,
172
+ token: str | None,
173
+ raise_for_status: bool = True,
169
174
  ) -> Response:
170
175
  headers = {
171
176
  "User-Agent": "Mozilla/5.0 (X11; Linux x86_64; rv:128.0) Gecko/20100101 Firefox/128.0"
@@ -173,11 +178,11 @@ def _make_request(
173
178
  if token:
174
179
  headers["Authorization"] = f"Bearer {token}"
175
180
  try:
176
- response = httpx.get(url, headers=headers)
181
+ response = method(url, headers=headers)
177
182
  if raise_for_status:
178
183
  response.raise_for_status()
179
- except Exception as E:
180
- raise APIError(E)
184
+ except Exception as e:
185
+ raise APIError(e)
181
186
  return response
182
187
 
183
188
 
@@ -185,8 +190,28 @@ def _make_request(
185
190
  class BlocketAPI:
186
191
  token: str | None = None
187
192
 
193
+ @overload
194
+ def saved_searches(
195
+ self,
196
+ limit: int = 99,
197
+ *,
198
+ as_objects: Literal[True],
199
+ ) -> SavedSearchResponse: ...
200
+
201
+ @overload
202
+ def saved_searches(
203
+ self,
204
+ limit: int = 99,
205
+ *,
206
+ as_objects: Literal[False] = False,
207
+ ) -> list[dict]: ...
208
+
188
209
  @auth_token
189
- def saved_searches(self) -> list[dict]:
210
+ def saved_searches(
211
+ self,
212
+ *,
213
+ as_objects: bool = False,
214
+ ) -> list[dict] | SavedSearchResponse:
190
215
  """
191
216
  Retrieves saved searches data, also known as "Bevakningar".
192
217
  """
@@ -205,7 +230,8 @@ class BlocketAPI:
205
230
  .get("data", [])
206
231
  )
207
232
 
208
- return searches + mobility_searches
233
+ result = searches + mobility_searches
234
+ return SavedSearchResponse(searches=result) if as_objects else result
209
235
 
210
236
  def _for_search_id(self, search_id: int, limit: int) -> dict:
211
237
  assert self.token
@@ -568,3 +594,22 @@ class BlocketAPI:
568
594
  url = f"{BASE_URL}/profile-be/v1/public-profiles/{user_id}"
569
595
  response = _make_request(url=f"{url}", token=self.token).json()
570
596
  return BlocketUser.model_validate(response) if as_objects else response
597
+
598
+ @auth_token
599
+ def save_ad(self, ad_id: int) -> dict:
600
+ """
601
+ Save an ad to "Saved ads" which can be found here:
602
+ https://www.blocket.se/sparade/annonser
603
+ """
604
+ url = f"{BASE_URL}/search_bff/v1/saved_content/{ad_id}"
605
+ response = _make_request(method=httpx.put, url=f"{url}", token=self.token)
606
+ return {"status_code": response.status_code}
607
+
608
+ @auth_token
609
+ def get_saved_ads(self, limit: int = 100) -> dict:
610
+ """
611
+ Returns all of your saved ads from https://www.blocket.se/sparade/annonser.
612
+ """
613
+ url = f"{BASE_URL}/search_bff/v1/saved_content?lim={limit}"
614
+ response = _make_request(url=f"{url}", token=self.token).json()
615
+ return response
@@ -590,3 +590,21 @@ class BlocketUser(BaseModel):
590
590
  co2_savings: BlocketUserCO2Savings
591
591
  profile_info: BlocketUserProfileInfo
592
592
  review_scores: dict | None = None
593
+
594
+
595
+ ### SavedSearchesResult ###
596
+
597
+
598
+ class SavedSearch(BaseModel):
599
+ id: str
600
+ name: str
601
+ query: str
602
+ total_count: int
603
+ new_count: int
604
+ push_enabled: bool
605
+ push_available: bool
606
+ email_enabled: bool | None = None
607
+
608
+
609
+ class SavedSearchResponse(BaseModel):
610
+ searches: list[SavedSearch]
@@ -1,6 +1,30 @@
1
+ Metadata-Version: 2.4
2
+ Name: blocket_api
3
+ Version: 0.3.4
4
+ Summary: A python API wrapper for blocket.se
5
+ Author-email: dunderrrrrr <emil.bjorkroth@gmail.com>
6
+ Requires-Python: >=3.10
7
+ Description-Content-Type: text/markdown
8
+ License-File: LICENSE
9
+ Requires-Dist: httpx>=0.27.0
10
+ Requires-Dist: pre-commit>=3.7.1
11
+ Requires-Dist: pytest>=8.2.2
12
+ Requires-Dist: respx>=0.21.1
13
+ Requires-Dist: mypy>=1.15.0
14
+ Requires-Dist: pydantic>=2.11.7
15
+ Requires-Dist: mkdocs>=1.6.1
16
+ Requires-Dist: mkdocs-material>=9.6.21
17
+ Requires-Dist: mkdocs-swagger-ui-tag>=0.7.2
18
+ Requires-Dist: ruff>=0.14.1
19
+ Dynamic: license-file
20
+
21
+ <p align="center">
22
+ <img src="https://blocket-api.se/blocket-api.png" />
23
+ </p>
24
+
1
25
  # BlocketAPI
2
26
 
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)
27
+ [![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/dw/blocket_api?style=for-the-badge&color=%23dbce58)
4
28
 
5
29
  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
30
 
@@ -44,7 +68,7 @@ Some calls require a `bearerToken`. However, some calls are public and don't req
44
68
 
45
69
  | Function | Token required | `as_objects` | Description |
46
70
  |---|---|---|---|
47
- | [`api.saved_searches()`](#saved_searches) | 🔐 Yes | - | List your saved searches (bevakningar) |
71
+ | [`api.saved_searches()`](#saved_searches) | 🔐 Yes | Yes | List your saved searches (bevakningar) |
48
72
  | [`api.get_listings()`](#get_listings) | 🔐 Yes | - | List items related to a saved search |
49
73
  | [`api.custom_search()`](#custom_search) | 👏 No | Yes | Search for everything on Blocket and filter by region |
50
74
  | [`api.motor_search()`](#motor_search) | 👏 No | Yes | Advanced search for car-listings. |
@@ -54,6 +78,8 @@ Some calls require a `bearerToken`. However, some calls are public and don't req
54
78
  | [`api.get_store_listings()`](#get_store_listings) | 👏 No | Yes | Get listings from a specific store.
55
79
  | [`api.get_ad_by_id()`](#get_ad_by_id) | 👏 No | Yes | Get ad data from id.
56
80
  | [`api.get_user_by_id()`](#get_user_by_id) | 👏 No | Yes | Get user data from id.
81
+ | [`api.save_ad()`](#save_ad) | 🔐 Yes | - | Save ad to "Saved ads".
82
+ | [`api.get_saved_ads()`](#get_saved_ads) | 🔐 Yes | - | List all saved ads.
57
83
 
58
84
 
59
85
  ## 🤓 Detailed usage
@@ -62,6 +88,9 @@ Some calls require a `bearerToken`. However, some calls are public and don't req
62
88
 
63
89
  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.
64
90
 
91
+ Parameters:
92
+ - `as_objects` (`bool`, optional) - Return results as pydantic models, default is `False`.
93
+
65
94
  ```py
66
95
  >>> api.saved_searches()
67
96
  [
@@ -310,6 +339,33 @@ Get user data from a user id. User id can be found in ads, searches and in block
310
339
  }
311
340
  ```
312
341
 
342
+ ### save_ad
343
+ This saves the ad to "Saved ads" which can be found here at `https://www.blocket.se/sparade/annonser`. When saving an ad, blocket always responds with 204, even if the ad is already saved or does not exist.
344
+
345
+ - `ad_id` (`int`, required) - The ad id. Can be found by calling any other method or from ad url.
346
+
347
+ ```py
348
+ >>> api.save_ad(1234)
349
+ ```
350
+
351
+ ### get_saved_ads
352
+ Returns all of your saved ads from `https://www.blocket.se/sparade/annonser`.
353
+
354
+ ```py
355
+ >>> api.get_saved_ads()
356
+ {
357
+ 'data': [{
358
+ 'ad_id': '1213682185'
359
+ 'list_id': '1213682185'
360
+ 'subject': 'Jeans från Gina tricot 158'
361
+ 'body': 'Moderna jeans från Gina Tricot!'
362
+ ...
363
+ }]
364
+ ...
365
+ }
366
+
367
+ ```
368
+
313
369
  ## 🔐 Blocket API token
314
370
 
315
371
  There are two ways to acquire your token:
@@ -4,4 +4,7 @@ pytest>=8.2.2
4
4
  respx>=0.21.1
5
5
  mypy>=1.15.0
6
6
  pydantic>=2.11.7
7
- ruff>=0.13.1
7
+ mkdocs>=1.6.1
8
+ mkdocs-material>=9.6.21
9
+ mkdocs-swagger-ui-tag>=0.7.2
10
+ ruff>=0.14.1
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "blocket_api"
3
- version = "0.3.1"
3
+ version = "0.3.4"
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,10 @@ dependencies = [
12
12
  "respx>=0.21.1",
13
13
  "mypy>=1.15.0",
14
14
  "pydantic>=2.11.7",
15
- "ruff>=0.13.1",
15
+ "mkdocs>=1.6.1",
16
+ "mkdocs-material>=9.6.21",
17
+ "mkdocs-swagger-ui-tag>=0.7.2",
18
+ "ruff>=0.14.1",
16
19
  ]
17
20
 
18
21
 
File without changes
File without changes