blocket-api 0.2.5__tar.gz → 0.2.7__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.5
3
+ Version: 0.2.7
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
@@ -8,10 +8,10 @@ Description-Content-Type: text/markdown
8
8
  License-File: LICENSE
9
9
  Requires-Dist: httpx>=0.27.0
10
10
  Requires-Dist: pre-commit>=3.7.1
11
- Requires-Dist: ruff>=0.5.2
12
11
  Requires-Dist: pytest>=8.2.2
13
12
  Requires-Dist: respx>=0.21.1
14
13
  Requires-Dist: mypy>=1.15.0
14
+ Requires-Dist: ruff>=0.12.3
15
15
  Dynamic: license-file
16
16
 
17
17
  # BlocketAPI
@@ -25,9 +25,11 @@ BlocketAPI allows users to query saved searches, known as "Bevakningar", on [blo
25
25
  ## ✨ Features
26
26
 
27
27
  - List saved searches, called "Bevakningar".
28
- - Query all listings/ads filtered on a region.
29
- - Query listings related to a saved search.
30
- - Use motor search to query listings related to a specific car.
28
+ - Get listings from all or a specific saved search.
29
+ - Search for anything on Blocket with filters for region and category.
30
+ - Advanced search for vehicles with multiple filters.
31
+ - Get vehicle information and price evaluation.
32
+ - Search for homes with filters for city, home type and more.
31
33
 
32
34
  ## 🧑‍💻️ Install
33
35
 
@@ -60,6 +62,7 @@ Some calls require a bearerToken. However, some calls are public and don't requi
60
62
  | [`api.custom_search()`](#custom_searchsearch_query-region-limit) | 👏 No | Search for everything on Blocket and filter by region |
61
63
  | [`api.motor_search()`](#motor_searchpage-make-fuel-chassi-price-modelyear-milage-gearbox) | 👏 No | Advanced search for car-listings. |
62
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.
63
66
 
64
67
  ## 🤓 Detailed usage
65
68
 
@@ -121,7 +124,8 @@ Make a custom search through out all of blocked. A region can be passed in as pa
121
124
 
122
125
  Parameters:
123
126
  - `search_query` (`str`, required) - A string to search for.
124
- - `region` (`str`, optional) - Filter results on a region, default is all of Sweden.
127
+ - `region` (`enum`, optional) - Filter results on a region, default is all of Sweden.
128
+ - `category` (`enum`, optional) - Filter for a specific category, ex. `Category.for_hemmet`.
125
129
  - `limit` (`int`, optional) - Limit number of results returned, max is 99.
126
130
 
127
131
  ```py
@@ -183,7 +187,7 @@ Query price evaluation for a specific vehicle by using cars registration number
183
187
 
184
188
  - `registration_number` (`str`, required) - Registration number of the vehicle.
185
189
  ```py
186
- >>> api.price_eval("ABC123)
190
+ >>> api.price_eval("ABC123")
187
191
  {
188
192
  "registration_number": "ABC123",
189
193
  "private_valuation": 108155,
@@ -197,6 +201,26 @@ Query price evaluation for a specific vehicle by using cars registration number
197
201
  }
198
202
  ```
199
203
 
204
+ ### home_search(city, type, order_by, ordering, offset)
205
+ Query home listings from [bostad.blocket.se](https://bostad.blocket.se/).
206
+
207
+ - `city` (`str`, required) - City name, ex. Stockholm.
208
+ - `type` (`HomeType`, optional) - Type of home, ex. `HomeType.apartment`.
209
+ - `order_by` (`OrderBy`, optional) - Sorting order, ex. `OrderBy.price`.
210
+ - `ordering` (`HOME_SEARCH_ORDERING`, optional) - Sorting order, ex. `"descending"`.
211
+ - `offset` (`int`, optional) - Offset for results, ex. `60`.
212
+
213
+ ```py
214
+ >>> from blocket_api.qasa import HomeType, OrderBy
215
+ >>> api.home_search(
216
+ city="Stockholm",
217
+ type=HomeType.apartment,
218
+ order_by=OrderBy.price,
219
+ ordering="descending",
220
+ )
221
+ ...
222
+ ```
223
+
200
224
  ## 🔐 Blocket API token
201
225
 
202
226
  There are two ways to acquire your token:
@@ -9,9 +9,11 @@ BlocketAPI allows users to query saved searches, known as "Bevakningar", on [blo
9
9
  ## ✨ Features
10
10
 
11
11
  - List saved searches, called "Bevakningar".
12
- - Query all listings/ads filtered on a region.
13
- - Query listings related to a saved search.
14
- - Use motor search to query listings related to a specific car.
12
+ - Get listings from all or a specific saved search.
13
+ - Search for anything on Blocket with filters for region and category.
14
+ - Advanced search for vehicles with multiple filters.
15
+ - Get vehicle information and price evaluation.
16
+ - Search for homes with filters for city, home type and more.
15
17
 
16
18
  ## 🧑‍💻️ Install
17
19
 
@@ -44,6 +46,7 @@ Some calls require a bearerToken. However, some calls are public and don't requi
44
46
  | [`api.custom_search()`](#custom_searchsearch_query-region-limit) | 👏 No | Search for everything on Blocket and filter by region |
45
47
  | [`api.motor_search()`](#motor_searchpage-make-fuel-chassi-price-modelyear-milage-gearbox) | 👏 No | Advanced search for car-listings. |
46
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.
47
50
 
48
51
  ## 🤓 Detailed usage
49
52
 
@@ -105,7 +108,8 @@ Make a custom search through out all of blocked. A region can be passed in as pa
105
108
 
106
109
  Parameters:
107
110
  - `search_query` (`str`, required) - A string to search for.
108
- - `region` (`str`, optional) - Filter results on a region, default is all of Sweden.
111
+ - `region` (`enum`, optional) - Filter results on a region, default is all of Sweden.
112
+ - `category` (`enum`, optional) - Filter for a specific category, ex. `Category.for_hemmet`.
109
113
  - `limit` (`int`, optional) - Limit number of results returned, max is 99.
110
114
 
111
115
  ```py
@@ -167,7 +171,7 @@ Query price evaluation for a specific vehicle by using cars registration number
167
171
 
168
172
  - `registration_number` (`str`, required) - Registration number of the vehicle.
169
173
  ```py
170
- >>> api.price_eval("ABC123)
174
+ >>> api.price_eval("ABC123")
171
175
  {
172
176
  "registration_number": "ABC123",
173
177
  "private_valuation": 108155,
@@ -181,6 +185,26 @@ Query price evaluation for a specific vehicle by using cars registration number
181
185
  }
182
186
  ```
183
187
 
188
+ ### home_search(city, type, order_by, ordering, offset)
189
+ Query home listings from [bostad.blocket.se](https://bostad.blocket.se/).
190
+
191
+ - `city` (`str`, required) - City name, ex. Stockholm.
192
+ - `type` (`HomeType`, optional) - Type of home, ex. `HomeType.apartment`.
193
+ - `order_by` (`OrderBy`, optional) - Sorting order, ex. `OrderBy.price`.
194
+ - `ordering` (`HOME_SEARCH_ORDERING`, optional) - Sorting order, ex. `"descending"`.
195
+ - `offset` (`int`, optional) - Offset for results, ex. `60`.
196
+
197
+ ```py
198
+ >>> from blocket_api.qasa import HomeType, OrderBy
199
+ >>> api.home_search(
200
+ city="Stockholm",
201
+ type=HomeType.apartment,
202
+ order_by=OrderBy.price,
203
+ ordering="descending",
204
+ )
205
+ ...
206
+ ```
207
+
184
208
  ## 🔐 Blocket API token
185
209
 
186
210
  There are two ways to acquire your token:
@@ -9,6 +9,8 @@ from typing import TYPE_CHECKING, Any, List, Literal, Optional, Tuple
9
9
 
10
10
  import httpx
11
11
 
12
+ from blocket_api.qasa import HOME_SEARCH_ORDERING, HomeType, OrderBy, Qasa
13
+
12
14
  if TYPE_CHECKING:
13
15
  from httpx import Response
14
16
 
@@ -44,6 +46,52 @@ class Region(Enum):
44
46
  örebro = 8
45
47
 
46
48
 
49
+ class Category(Enum):
50
+ fordon = 1000
51
+ bilar = 1020
52
+ bildelar_biltillbehor = 1040
53
+ batar = 1060
54
+ batdelar_tillbehor = 1080
55
+ husvagnar_husbilar = 1100
56
+ mopeder_a_traktor = 1120
57
+ motorcyklar = 1140
58
+ mc_delar_tillbehor = 1160
59
+ lastbil_truck_entreprenad = 1220
60
+ skogs_lantbruksmaskiner = 1240
61
+ snoskotrar = 1180
62
+ snoskoterdelar_tillbehor = 1200
63
+ for_hemmet = 2000
64
+ bygg_tradgard = 2020
65
+ mobler_heminredning = 2040
66
+ husgerad_vitvaror = 2060
67
+ verktyg = 2026
68
+ bostad = 3000
69
+ lagenheter = 3020
70
+ villor = 3100
71
+ radhus = 3120
72
+ tomter = 3060
73
+ gardar = 3070
74
+ fritidsboende = 3040
75
+ utland = 3080
76
+ personligt = 4000
77
+ klader_skor = 4080
78
+ accessoarer_klockor = 4060
79
+ barnklader_skor = 4020
80
+ barnartiklar_leksaker = 4040
81
+ elektronik = 5000
82
+ datorer_tv_spel = 5020
83
+ ljud_bild = 5040
84
+ telefoner_tillbehor = 5060
85
+ fritid_hobby = 6000
86
+ biljetter_resor = 6020
87
+ bocker_studentlitteratur = 6040
88
+ cyklar = 6060
89
+ djur = 6080
90
+ hobby_samlarprylar = 6100
91
+ hastar_ridsport = 6120
92
+ jakt_fiske = 6140
93
+
94
+
47
95
  MAKE_OPTIONS = Literal[
48
96
  "Audi",
49
97
  "BMW",
@@ -186,7 +234,11 @@ class BlocketAPI:
186
234
 
187
235
  @public_token
188
236
  def custom_search(
189
- self, search_query: str, region: Region = Region.hela_sverige, limit: int = 99
237
+ self,
238
+ search_query: str,
239
+ region: Region = Region.hela_sverige,
240
+ category: Category | None = None,
241
+ limit: int = 99,
190
242
  ) -> dict:
191
243
  """
192
244
  Do a custom search through out all of Blocket.
@@ -197,10 +249,12 @@ class BlocketAPI:
197
249
  if limit > 99:
198
250
  raise LimitError("Limit cannot be greater than 99.")
199
251
 
200
- return _make_request(
201
- url=f"{BASE_URL}/search_bff/v2/content?lim={limit}&q={search_query}&r={region.value}&status=active",
202
- token=self.token,
203
- ).json()
252
+ url = f"{BASE_URL}/search_bff/v2/content?lim={limit}&q={search_query}&r={region.value}&status=active"
253
+
254
+ if category:
255
+ url += f"&cg={category.value}"
256
+
257
+ return _make_request(url=url, token=self.token).json()
204
258
 
205
259
  @public_token
206
260
  def motor_search(
@@ -259,3 +313,24 @@ class BlocketAPI:
259
313
  """
260
314
  url = f"{BYTBIL_URL}/blocket-basedata-api/v3/vehicle-data/{registration_number}"
261
315
  return _make_request(url=f"{url}", token=None).json()
316
+
317
+ def home_search(
318
+ self,
319
+ city: str,
320
+ type: HomeType,
321
+ order_by: OrderBy = OrderBy.published_at,
322
+ ordering: HOME_SEARCH_ORDERING = "descending",
323
+ offset: int = 0,
324
+ ) -> dict:
325
+ """
326
+ This returns all available home listings available at
327
+ https://bostad.blocket.se/. Specify offset to get next page. Each page contains
328
+ 60 items, which is max items returned per api query.
329
+ """
330
+ return Qasa(
331
+ city=city,
332
+ home_type=type,
333
+ order_by=order_by,
334
+ ordering=ordering,
335
+ offset=offset,
336
+ ).search()
@@ -0,0 +1,135 @@
1
+ from dataclasses import dataclass
2
+ from enum import Enum
3
+ from typing import Literal
4
+ import httpx
5
+
6
+ QASA_URL = "https://api.qasa.se/graphql"
7
+ HOME_SEARCH_ORDERING = Literal["descending", "ascending"]
8
+
9
+
10
+ class OrderBy(Enum):
11
+ published_at = "published_or_bumped_at"
12
+ price = "monthly_cost_cents"
13
+ size = "square_meters"
14
+ move_in_date = "start_date"
15
+ move_out_date = "end_date"
16
+
17
+
18
+ class HomeType(Enum):
19
+ apartment = ["apartment", "loft"]
20
+ house = ["house", "terrace_house", "duplex"]
21
+ cottage = ["cottage"]
22
+ corridor = ["corridor", "room"]
23
+ other = ["other"]
24
+
25
+
26
+ @dataclass
27
+ class Qasa:
28
+ city: str
29
+ home_type: HomeType
30
+ order_by: OrderBy
31
+ ordering: HOME_SEARCH_ORDERING
32
+ offset: int
33
+
34
+ def _construct_payload(self) -> dict:
35
+ return {
36
+ "operationName": "HomeSearch",
37
+ "variables": {
38
+ "limit": 60, # no more than 60 items per page is allowed
39
+ "offset": 0,
40
+ "order": {
41
+ "direction": f"{self.ordering}",
42
+ "orderBy": f"{self.order_by.value}",
43
+ },
44
+ "params": {
45
+ "currency": "SEK",
46
+ "homeType": self.home_type.value,
47
+ "areaIdentifier": [f"se/{self.city}"],
48
+ "rentalType": ["long_term"],
49
+ "markets": ["sweden"],
50
+ },
51
+ },
52
+ "query": """
53
+ query HomeSearch(
54
+ $order: HomeIndexSearchOrderInput,
55
+ $offset: Int,
56
+ $limit: Int,
57
+ $params: HomeSearchParamsInput
58
+ ) {
59
+ homeIndexSearch(order: $order, params: $params) {
60
+ documents(offset: $offset, limit: $limit) {
61
+ hasNextPage
62
+ hasPreviousPage
63
+ nodes {
64
+ bedroomCount
65
+ blockListing
66
+ rentalLengthSeconds
67
+ householdSize
68
+ corporateHome
69
+ description
70
+ endDate
71
+ firstHand
72
+ furnished
73
+ homeType
74
+ id
75
+ instantSign
76
+ market
77
+ lastBumpedAt
78
+ monthlyCost
79
+ petsAllowed
80
+ platform
81
+ publishedAt
82
+ publishedOrBumpedAt
83
+ earlyAccessEndsAt
84
+ rent
85
+ currency
86
+ roomCount
87
+ seniorHome
88
+ shared
89
+ shortcutHome
90
+ smokingAllowed
91
+ sortingScore
92
+ squareMeters
93
+ startDate
94
+ studentHome
95
+ tenantBaseFee
96
+ title
97
+ wheelchairAccessible
98
+ location {
99
+ id
100
+ locality
101
+ countryCode
102
+ streetNumber
103
+ point {
104
+ lat
105
+ lon
106
+ __typename
107
+ }
108
+ route
109
+ __typename
110
+ }
111
+ displayStreetNumber
112
+ uploads {
113
+ id
114
+ order
115
+ type
116
+ url
117
+ __typename
118
+ }
119
+ __typename
120
+ }
121
+ pagesCount
122
+ totalCount
123
+ __typename
124
+ }
125
+ __typename
126
+ }
127
+ }""",
128
+ }
129
+
130
+ def search(self) -> dict:
131
+ query = self._construct_payload()
132
+
133
+ response = httpx.post(QASA_URL, json=query)
134
+ response.raise_for_status()
135
+ return response.json()
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: blocket_api
3
- Version: 0.2.5
3
+ Version: 0.2.7
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
@@ -8,10 +8,10 @@ Description-Content-Type: text/markdown
8
8
  License-File: LICENSE
9
9
  Requires-Dist: httpx>=0.27.0
10
10
  Requires-Dist: pre-commit>=3.7.1
11
- Requires-Dist: ruff>=0.5.2
12
11
  Requires-Dist: pytest>=8.2.2
13
12
  Requires-Dist: respx>=0.21.1
14
13
  Requires-Dist: mypy>=1.15.0
14
+ Requires-Dist: ruff>=0.12.3
15
15
  Dynamic: license-file
16
16
 
17
17
  # BlocketAPI
@@ -25,9 +25,11 @@ BlocketAPI allows users to query saved searches, known as "Bevakningar", on [blo
25
25
  ## ✨ Features
26
26
 
27
27
  - List saved searches, called "Bevakningar".
28
- - Query all listings/ads filtered on a region.
29
- - Query listings related to a saved search.
30
- - Use motor search to query listings related to a specific car.
28
+ - Get listings from all or a specific saved search.
29
+ - Search for anything on Blocket with filters for region and category.
30
+ - Advanced search for vehicles with multiple filters.
31
+ - Get vehicle information and price evaluation.
32
+ - Search for homes with filters for city, home type and more.
31
33
 
32
34
  ## 🧑‍💻️ Install
33
35
 
@@ -60,6 +62,7 @@ Some calls require a bearerToken. However, some calls are public and don't requi
60
62
  | [`api.custom_search()`](#custom_searchsearch_query-region-limit) | 👏 No | Search for everything on Blocket and filter by region |
61
63
  | [`api.motor_search()`](#motor_searchpage-make-fuel-chassi-price-modelyear-milage-gearbox) | 👏 No | Advanced search for car-listings. |
62
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.
63
66
 
64
67
  ## 🤓 Detailed usage
65
68
 
@@ -121,7 +124,8 @@ Make a custom search through out all of blocked. A region can be passed in as pa
121
124
 
122
125
  Parameters:
123
126
  - `search_query` (`str`, required) - A string to search for.
124
- - `region` (`str`, optional) - Filter results on a region, default is all of Sweden.
127
+ - `region` (`enum`, optional) - Filter results on a region, default is all of Sweden.
128
+ - `category` (`enum`, optional) - Filter for a specific category, ex. `Category.for_hemmet`.
125
129
  - `limit` (`int`, optional) - Limit number of results returned, max is 99.
126
130
 
127
131
  ```py
@@ -183,7 +187,7 @@ Query price evaluation for a specific vehicle by using cars registration number
183
187
 
184
188
  - `registration_number` (`str`, required) - Registration number of the vehicle.
185
189
  ```py
186
- >>> api.price_eval("ABC123)
190
+ >>> api.price_eval("ABC123")
187
191
  {
188
192
  "registration_number": "ABC123",
189
193
  "private_valuation": 108155,
@@ -197,6 +201,26 @@ Query price evaluation for a specific vehicle by using cars registration number
197
201
  }
198
202
  ```
199
203
 
204
+ ### home_search(city, type, order_by, ordering, offset)
205
+ Query home listings from [bostad.blocket.se](https://bostad.blocket.se/).
206
+
207
+ - `city` (`str`, required) - City name, ex. Stockholm.
208
+ - `type` (`HomeType`, optional) - Type of home, ex. `HomeType.apartment`.
209
+ - `order_by` (`OrderBy`, optional) - Sorting order, ex. `OrderBy.price`.
210
+ - `ordering` (`HOME_SEARCH_ORDERING`, optional) - Sorting order, ex. `"descending"`.
211
+ - `offset` (`int`, optional) - Offset for results, ex. `60`.
212
+
213
+ ```py
214
+ >>> from blocket_api.qasa import HomeType, OrderBy
215
+ >>> api.home_search(
216
+ city="Stockholm",
217
+ type=HomeType.apartment,
218
+ order_by=OrderBy.price,
219
+ ordering="descending",
220
+ )
221
+ ...
222
+ ```
223
+
200
224
  ## 🔐 Blocket API token
201
225
 
202
226
  There are two ways to acquire your token:
@@ -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/qasa.py
6
7
  blocket_api.egg-info/PKG-INFO
7
8
  blocket_api.egg-info/SOURCES.txt
8
9
  blocket_api.egg-info/dependency_links.txt
@@ -1,6 +1,6 @@
1
1
  httpx>=0.27.0
2
2
  pre-commit>=3.7.1
3
- ruff>=0.5.2
4
3
  pytest>=8.2.2
5
4
  respx>=0.21.1
6
5
  mypy>=1.15.0
6
+ ruff>=0.12.3
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "blocket_api"
3
- version = "0.2.5"
3
+ version = "0.2.7"
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"
@@ -8,10 +8,10 @@ requires-python = ">=3.10"
8
8
  dependencies = [
9
9
  "httpx>=0.27.0",
10
10
  "pre-commit>=3.7.1",
11
- "ruff>=0.5.2",
12
11
  "pytest>=8.2.2",
13
12
  "respx>=0.21.1",
14
13
  "mypy>=1.15.0",
14
+ "ruff>=0.12.3",
15
15
  ]
16
16
 
17
17
 
File without changes
File without changes