blocket-api 0.2.5__py3-none-any.whl
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/__init__.py
ADDED
blocket_api/blocket.py
ADDED
|
@@ -0,0 +1,261 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from collections.abc import Callable
|
|
4
|
+
from functools import wraps
|
|
5
|
+
import urllib
|
|
6
|
+
from dataclasses import dataclass
|
|
7
|
+
from enum import Enum
|
|
8
|
+
from typing import TYPE_CHECKING, Any, List, Literal, Optional, Tuple
|
|
9
|
+
|
|
10
|
+
import httpx
|
|
11
|
+
|
|
12
|
+
if TYPE_CHECKING:
|
|
13
|
+
from httpx import Response
|
|
14
|
+
|
|
15
|
+
BASE_URL = "https://api.blocket.se"
|
|
16
|
+
SITE_URL = "https://www.blocket.se"
|
|
17
|
+
BYTBIL_URL = "https://api.bytbil.com"
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
class Region(Enum):
|
|
21
|
+
hela_sverige = 0
|
|
22
|
+
östergötland = 14
|
|
23
|
+
blekinge = 22
|
|
24
|
+
dalarna = 6
|
|
25
|
+
gotland = 19
|
|
26
|
+
gävleborg = 5
|
|
27
|
+
göteborg = 15
|
|
28
|
+
halland = 20
|
|
29
|
+
jämtland = 3
|
|
30
|
+
jönköping = 17
|
|
31
|
+
kalmar = 18
|
|
32
|
+
kronoberg = 21
|
|
33
|
+
norrbotten = 1
|
|
34
|
+
skaraborg = 13
|
|
35
|
+
skåne = 23
|
|
36
|
+
stockholm = 11
|
|
37
|
+
södermanland = 12
|
|
38
|
+
uppsala = 10
|
|
39
|
+
värmland = 7
|
|
40
|
+
västerbotten = 2
|
|
41
|
+
västernorrland = 4
|
|
42
|
+
västmanland = 9
|
|
43
|
+
älvsborg = 16
|
|
44
|
+
örebro = 8
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
MAKE_OPTIONS = Literal[
|
|
48
|
+
"Audi",
|
|
49
|
+
"BMW",
|
|
50
|
+
"Chevrolet",
|
|
51
|
+
"Citroën",
|
|
52
|
+
"Ford",
|
|
53
|
+
"Honda",
|
|
54
|
+
"Hyundai",
|
|
55
|
+
"Kia",
|
|
56
|
+
"Mazda",
|
|
57
|
+
"Mercedes-Benz",
|
|
58
|
+
"Nissan",
|
|
59
|
+
"Opel",
|
|
60
|
+
"Peugeot",
|
|
61
|
+
"Renault",
|
|
62
|
+
"Saab",
|
|
63
|
+
"Skoda",
|
|
64
|
+
"Subaru",
|
|
65
|
+
"Toyota",
|
|
66
|
+
"Volkswagen",
|
|
67
|
+
"Volvo",
|
|
68
|
+
]
|
|
69
|
+
|
|
70
|
+
FUEL_OPTIONS = Literal["Diesel", "Bensin", "El", "Miljöbränsle/Hybrid"]
|
|
71
|
+
CHASSI_OPTIONS = Literal[
|
|
72
|
+
"Kombi", "SUV", "Sedan", "Halvkombi", "Coupé", "Cab", "Familjebuss", "Yrkesfordon"
|
|
73
|
+
]
|
|
74
|
+
GEARBOX_OPTIONS = Literal["Automat", "Manuell"]
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
class APIError(Exception): ...
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
class LimitError(Exception): ...
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
class TokenError(Exception): ...
|
|
84
|
+
|
|
85
|
+
|
|
86
|
+
def auth_token(method: Callable) -> Callable:
|
|
87
|
+
@wraps(method)
|
|
88
|
+
def wrapper(self: Any, *args: Any, **kwargs: Any) -> Callable:
|
|
89
|
+
if not self.token:
|
|
90
|
+
raise TokenError("Token is required, see documentation.")
|
|
91
|
+
return method(self, *args, **kwargs)
|
|
92
|
+
|
|
93
|
+
return wrapper
|
|
94
|
+
|
|
95
|
+
|
|
96
|
+
def public_token(method: Callable) -> Callable:
|
|
97
|
+
@wraps(method)
|
|
98
|
+
def wrapper(self: Any, *args: Any, **kwargs: Any) -> Callable:
|
|
99
|
+
if not self.token:
|
|
100
|
+
response = httpx.get(
|
|
101
|
+
f"{SITE_URL}/api/adout-api-route/refresh-token-and-validate-session"
|
|
102
|
+
)
|
|
103
|
+
response.raise_for_status()
|
|
104
|
+
self.token = response.json()["bearerToken"]
|
|
105
|
+
return method(self, *args, **kwargs)
|
|
106
|
+
|
|
107
|
+
return wrapper
|
|
108
|
+
|
|
109
|
+
|
|
110
|
+
def _make_request(
|
|
111
|
+
*, url: str, token: str | None, raise_for_status: bool = True
|
|
112
|
+
) -> Response:
|
|
113
|
+
headers = {
|
|
114
|
+
"User-Agent": "Mozilla/5.0 (X11; Linux x86_64; rv:128.0) Gecko/20100101 Firefox/128.0"
|
|
115
|
+
}
|
|
116
|
+
if token:
|
|
117
|
+
headers["Authorization"] = f"Bearer {token}"
|
|
118
|
+
try:
|
|
119
|
+
response = httpx.get(url, headers=headers)
|
|
120
|
+
if raise_for_status:
|
|
121
|
+
response.raise_for_status()
|
|
122
|
+
except Exception as E:
|
|
123
|
+
raise APIError(E)
|
|
124
|
+
return response
|
|
125
|
+
|
|
126
|
+
|
|
127
|
+
@dataclass
|
|
128
|
+
class BlocketAPI:
|
|
129
|
+
token: str | None = None
|
|
130
|
+
|
|
131
|
+
@auth_token
|
|
132
|
+
def saved_searches(self) -> list[dict]:
|
|
133
|
+
"""
|
|
134
|
+
Retrieves saved searches data, also known as "Bevakningar".
|
|
135
|
+
"""
|
|
136
|
+
assert self.token
|
|
137
|
+
|
|
138
|
+
searches = (
|
|
139
|
+
_make_request(url=f"{BASE_URL}/saved/v2/searches", token=self.token)
|
|
140
|
+
.json()
|
|
141
|
+
.get("data", [])
|
|
142
|
+
)
|
|
143
|
+
mobility_searches = (
|
|
144
|
+
_make_request(
|
|
145
|
+
url=f"{BASE_URL}/mobility-saved-searches/v1/searches", token=self.token
|
|
146
|
+
)
|
|
147
|
+
.json()
|
|
148
|
+
.get("data", [])
|
|
149
|
+
)
|
|
150
|
+
|
|
151
|
+
return searches + mobility_searches
|
|
152
|
+
|
|
153
|
+
def _for_search_id(self, search_id: int, limit: int) -> dict:
|
|
154
|
+
assert self.token
|
|
155
|
+
searches = _make_request(
|
|
156
|
+
url=f"{BASE_URL}/saved/v2/searches_content/{search_id}?lim={limit}",
|
|
157
|
+
token=self.token,
|
|
158
|
+
raise_for_status=False,
|
|
159
|
+
)
|
|
160
|
+
if searches.status_code == 404:
|
|
161
|
+
mobility_searches = _make_request(
|
|
162
|
+
url=f"{BASE_URL}/mobility-saved-searches/v1/searches/{search_id}/ads?lim={limit}",
|
|
163
|
+
token=self.token,
|
|
164
|
+
raise_for_status=True,
|
|
165
|
+
)
|
|
166
|
+
return mobility_searches.json()
|
|
167
|
+
return searches.json()
|
|
168
|
+
|
|
169
|
+
@auth_token
|
|
170
|
+
def get_listings(self, search_id: int | None = None, limit: int = 99) -> dict:
|
|
171
|
+
"""
|
|
172
|
+
Retrieve listings/ads based on the provided search criteria.
|
|
173
|
+
"""
|
|
174
|
+
assert self.token
|
|
175
|
+
|
|
176
|
+
if limit > 99:
|
|
177
|
+
raise LimitError("Limit cannot be greater than 99.")
|
|
178
|
+
|
|
179
|
+
if search_id:
|
|
180
|
+
return self._for_search_id(search_id, limit)
|
|
181
|
+
|
|
182
|
+
return _make_request(
|
|
183
|
+
url=BASE_URL + f"/saved/v2/searches_content?lim={limit}",
|
|
184
|
+
token=self.token,
|
|
185
|
+
).json()
|
|
186
|
+
|
|
187
|
+
@public_token
|
|
188
|
+
def custom_search(
|
|
189
|
+
self, search_query: str, region: Region = Region.hela_sverige, limit: int = 99
|
|
190
|
+
) -> dict:
|
|
191
|
+
"""
|
|
192
|
+
Do a custom search through out all of Blocket.
|
|
193
|
+
Supply a region for filtering. Default is all of Sweden.
|
|
194
|
+
"""
|
|
195
|
+
assert self.token
|
|
196
|
+
|
|
197
|
+
if limit > 99:
|
|
198
|
+
raise LimitError("Limit cannot be greater than 99.")
|
|
199
|
+
|
|
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()
|
|
204
|
+
|
|
205
|
+
@public_token
|
|
206
|
+
def motor_search(
|
|
207
|
+
self,
|
|
208
|
+
page: int,
|
|
209
|
+
make: List[MAKE_OPTIONS],
|
|
210
|
+
fuel: Optional[List[FUEL_OPTIONS]] = None,
|
|
211
|
+
chassi: Optional[List[CHASSI_OPTIONS]] = None,
|
|
212
|
+
price: Optional[Tuple[int, int]] = None,
|
|
213
|
+
modelYear: Optional[Tuple[int, int]] = None,
|
|
214
|
+
milage: Optional[Tuple[int, int]] = None,
|
|
215
|
+
gearbox: Optional[GEARBOX_OPTIONS] = None,
|
|
216
|
+
) -> dict:
|
|
217
|
+
"""
|
|
218
|
+
Search specifically in the car section of Blocket
|
|
219
|
+
with set optional parameters for filtering.
|
|
220
|
+
"""
|
|
221
|
+
assert self.token
|
|
222
|
+
|
|
223
|
+
range_params = ["price", "modelYear", "milage"]
|
|
224
|
+
set_params = {
|
|
225
|
+
key: value
|
|
226
|
+
for key, value in locals().items()
|
|
227
|
+
if key not in ["self", "page", "range_params"] and value is not None
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
filters = []
|
|
231
|
+
for param, value in set_params.items():
|
|
232
|
+
filter = {"key": param, "values": value}
|
|
233
|
+
if param in range_params:
|
|
234
|
+
range_start, range_end = filter.pop("values")
|
|
235
|
+
filter["range"] = {
|
|
236
|
+
"start": str(range_start),
|
|
237
|
+
"end": str(range_end),
|
|
238
|
+
}
|
|
239
|
+
filter_str = urllib.parse.quote(str(filter).replace("'", '"'))
|
|
240
|
+
filters.append(filter_str)
|
|
241
|
+
|
|
242
|
+
motor_base_url = f"{BASE_URL}/motor-search-service/v4/search/car"
|
|
243
|
+
|
|
244
|
+
filters_str = "&".join([f"filter={f}" for f in filters])
|
|
245
|
+
url = f"{motor_base_url}?{filters_str}&page={page}"
|
|
246
|
+
|
|
247
|
+
return _make_request(url=f"{url}", token=self.token).json()
|
|
248
|
+
|
|
249
|
+
@public_token
|
|
250
|
+
def price_eval(
|
|
251
|
+
self,
|
|
252
|
+
registration_number: str,
|
|
253
|
+
) -> dict:
|
|
254
|
+
"""
|
|
255
|
+
Price evaluation for a specific vehicle by using cars
|
|
256
|
+
registration number (ABC123).
|
|
257
|
+
|
|
258
|
+
This is using same api endpoint as https://www.blocket.se/tjanster/vardera-bil.
|
|
259
|
+
"""
|
|
260
|
+
url = f"{BYTBIL_URL}/blocket-basedata-api/v3/vehicle-data/{registration_number}"
|
|
261
|
+
return _make_request(url=f"{url}", token=None).json()
|
|
@@ -0,0 +1,225 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: blocket_api
|
|
3
|
+
Version: 0.2.5
|
|
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: ruff>=0.5.2
|
|
12
|
+
Requires-Dist: pytest>=8.2.2
|
|
13
|
+
Requires-Dist: respx>=0.21.1
|
|
14
|
+
Requires-Dist: mypy>=1.15.0
|
|
15
|
+
Dynamic: license-file
|
|
16
|
+
|
|
17
|
+
# BlocketAPI
|
|
18
|
+
|
|
19
|
+
[](https://pypi.org/project/blocket_api/) [](https://github.com/dunderrrrrr/blocket_api/blob/main/LICENSE) [](https://pypi.org/project/blocket_api/) 
|
|
20
|
+
|
|
21
|
+
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
|
+
> 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.
|
|
24
|
+
|
|
25
|
+
## ✨ Features
|
|
26
|
+
|
|
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.
|
|
31
|
+
|
|
32
|
+
## 🧑💻️ Install
|
|
33
|
+
|
|
34
|
+
BlocketAPI is available on PyPI.
|
|
35
|
+
|
|
36
|
+
```sh
|
|
37
|
+
pip install blocket-api
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
## 💁♀️ Usage
|
|
41
|
+
|
|
42
|
+
```py
|
|
43
|
+
>>> from blocket_api import BlocketAPI
|
|
44
|
+
>>> api = BlocketAPI("YourBlocketTokenHere")
|
|
45
|
+
>>> print(api.saved_searches())
|
|
46
|
+
...
|
|
47
|
+
>>> print(BlocketAPI().custom_search("saab")) # no token required
|
|
48
|
+
...
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
Some calls require a bearerToken. However, some calls are public and don't require a token.
|
|
52
|
+
|
|
53
|
+
[Where token?](#-blocket-api-token)
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
| Function | Token required | Description |
|
|
57
|
+
|---|---|---|
|
|
58
|
+
| [`api.saved_searches()`](#saved_searches) | 🔐 Yes | List your saved searches (bevakningar) |
|
|
59
|
+
| [`api.get_listings()`](#get_listingssearch_id-limit) | 🔐 Yes | List items related to a saved search |
|
|
60
|
+
| [`api.custom_search()`](#custom_searchsearch_query-region-limit) | 👏 No | Search for everything on Blocket and filter by region |
|
|
61
|
+
| [`api.motor_search()`](#motor_searchpage-make-fuel-chassi-price-modelyear-milage-gearbox) | 👏 No | Advanced search for car-listings. |
|
|
62
|
+
| [`api.price_eval()`](#price_evalregistration_number) | 👏 No | Vehicle purchase valuation and details. |
|
|
63
|
+
|
|
64
|
+
## 🤓 Detailed usage
|
|
65
|
+
|
|
66
|
+
### saved_searches()
|
|
67
|
+
|
|
68
|
+
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.
|
|
69
|
+
|
|
70
|
+
```py
|
|
71
|
+
>>> api.saved_searches()
|
|
72
|
+
[
|
|
73
|
+
{
|
|
74
|
+
"id":"4150081",
|
|
75
|
+
"new_count":0,
|
|
76
|
+
"total_count":41,
|
|
77
|
+
"push_enabled":false,
|
|
78
|
+
"push_available":true,
|
|
79
|
+
"query":"cg=1020&q=buggy&st=s",
|
|
80
|
+
"name":"\"buggy\", Bilar säljes i hela Sverige"
|
|
81
|
+
},
|
|
82
|
+
]
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
### get_listings(search_id, limit)
|
|
86
|
+
Returns all listings related to a saved search.
|
|
87
|
+
|
|
88
|
+
Parameters:
|
|
89
|
+
- `search_id` (`int`, optional) - Get listings for a specific saved search. If not provided, all saved searches will be combined.
|
|
90
|
+
- `limit` (`int`, optional) - Limit number of results returned, max is 99.
|
|
91
|
+
|
|
92
|
+
```py
|
|
93
|
+
>>> api.get_listings(4150081)
|
|
94
|
+
{
|
|
95
|
+
"data":[
|
|
96
|
+
{
|
|
97
|
+
"ad":{
|
|
98
|
+
"ad_id":"1401053984",
|
|
99
|
+
"list_id":"1401053984",
|
|
100
|
+
"zipcode":"81290",
|
|
101
|
+
"ad_status":"active",
|
|
102
|
+
"list_time":"2024-07-15T19:07:16+02:00",
|
|
103
|
+
"subject":"Volkswagen 1500 lim 113 chassi",
|
|
104
|
+
"body":"Säljer ett chassi/bottenplatta till en volkswagen 1500 lim 113 1967, blästrat och målat.\nFinns en beach buggy kaross att få med om man vill det. \nReg nmr ABC123",
|
|
105
|
+
"price":{
|
|
106
|
+
"value":10000,
|
|
107
|
+
"suffix":"kr"
|
|
108
|
+
},
|
|
109
|
+
...
|
|
110
|
+
},
|
|
111
|
+
},
|
|
112
|
+
],
|
|
113
|
+
"total_count":41,
|
|
114
|
+
"timestamp":"2024-07-16T08:08:43.810828006Z",
|
|
115
|
+
"total_page_count":1
|
|
116
|
+
}
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
### custom_search(search_query, region, limit)
|
|
120
|
+
Make a custom search through out all of blocked. A region can be passed in as parameter for filtering.
|
|
121
|
+
|
|
122
|
+
Parameters:
|
|
123
|
+
- `search_query` (`str`, required) - A string to search for.
|
|
124
|
+
- `region` (`str`, optional) - Filter results on a region, default is all of Sweden.
|
|
125
|
+
- `limit` (`int`, optional) - Limit number of results returned, max is 99.
|
|
126
|
+
|
|
127
|
+
```py
|
|
128
|
+
>>> from blocket_api import Region
|
|
129
|
+
>>> api.custom_search("saab", Region.blekinge) # search for term "saab" in region of "Blekinge"
|
|
130
|
+
{
|
|
131
|
+
"data":[
|
|
132
|
+
{
|
|
133
|
+
"ad_id":"1401038836",
|
|
134
|
+
"ad_status":"active",
|
|
135
|
+
"advertiser":{
|
|
136
|
+
"account_id":"684279",
|
|
137
|
+
"name":"Stefan Ingves",
|
|
138
|
+
"type":"private"
|
|
139
|
+
},
|
|
140
|
+
...
|
|
141
|
+
"location":[
|
|
142
|
+
{
|
|
143
|
+
"id":"22",
|
|
144
|
+
"name":"Blekinge",
|
|
145
|
+
"query_key":"r"
|
|
146
|
+
},
|
|
147
|
+
{
|
|
148
|
+
"id":"256",
|
|
149
|
+
"name":"Ronneby",
|
|
150
|
+
"query_key":"m"
|
|
151
|
+
}
|
|
152
|
+
],
|
|
153
|
+
...
|
|
154
|
+
}
|
|
155
|
+
]
|
|
156
|
+
}
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
### motor_search(page, make, fuel, chassi, price, modelYear, milage, gearbox)
|
|
160
|
+
To query listings related to a specific car, supply the following parameters:
|
|
161
|
+
|
|
162
|
+
- `page` (`int`, required) - Results are split in pages, set page number here.
|
|
163
|
+
- `make` (`List[MAKE_OPTIONS]`) - Filter a specific make, ex. `Audi`.
|
|
164
|
+
- `fuel` (`Optional[List[FUEL_OPTIONS]]`) - Filter a specific fuel, ex. `Diesel`.
|
|
165
|
+
- `chassi` (`Optional[List[CHASSI_OPTIONS]]`) - Filter a specific chassi, ex. `Cab`.
|
|
166
|
+
- `price` (`Optional[Tuple[int, int]]`) - Set price range, ex. `(50000, 100000)`.
|
|
167
|
+
- `modelYear` (`Optional[Tuple[int, int]]`) - Set model year range, ex. `(2000, 2020)`.
|
|
168
|
+
- `milage` (`Optional[Tuple[int, int]]`) - Set milage range, ex. `(1000, 2000)`.
|
|
169
|
+
- `gearbox` (`Optional[GEARBOX_OPTIONS]`) - Filter a specific gearbox, ex. `Automat`.
|
|
170
|
+
```py
|
|
171
|
+
>>> api.motor_search(
|
|
172
|
+
make=["Audi", "Ford"],
|
|
173
|
+
fuel=["Diesel"],
|
|
174
|
+
chassi=["Cab"],
|
|
175
|
+
price=(50000, 100000),
|
|
176
|
+
page=1,
|
|
177
|
+
)
|
|
178
|
+
...
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
### price_eval(registration_number)
|
|
182
|
+
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.
|
|
183
|
+
|
|
184
|
+
- `registration_number` (`str`, required) - Registration number of the vehicle.
|
|
185
|
+
```py
|
|
186
|
+
>>> api.price_eval("ABC123)
|
|
187
|
+
{
|
|
188
|
+
"registration_number": "ABC123",
|
|
189
|
+
"private_valuation": 108155,
|
|
190
|
+
"company_valuation": 108155,
|
|
191
|
+
"car_info": {
|
|
192
|
+
"make": "Volkswagen",
|
|
193
|
+
"model": "Polo"
|
|
194
|
+
...
|
|
195
|
+
}
|
|
196
|
+
...
|
|
197
|
+
}
|
|
198
|
+
```
|
|
199
|
+
|
|
200
|
+
## 🔐 Blocket API token
|
|
201
|
+
|
|
202
|
+
There are two ways to acquire your token:
|
|
203
|
+
|
|
204
|
+
- Log in to Blocket.se with your credentials using any web browser.
|
|
205
|
+
- Go to [this](https://www.blocket.se/api/adout-api-route/refresh-token-and-validate-session) URL and copy the value of `bearerToken`.
|
|
206
|
+
|
|
207
|
+
If there's a better way of doing this, feel free to help out in [#2](https://github.com/dunderrrrrr/blocket_api/issues/2).
|
|
208
|
+
|
|
209
|
+
Your token can also be found in the request headers in the "Bevakningar"-section on Blocket.
|
|
210
|
+
|
|
211
|
+
- **Login to [blocket.se](https**://blocket.se/)**: Sign in with your credentials.
|
|
212
|
+
- **Click "Bevakningar"**: Go to the "Bevakningar" section.
|
|
213
|
+
- **Inspect the page**: Right-click the page and select "Inspect".
|
|
214
|
+
- **Open the Network tab**: Switch to the Network tab in the Developer Tools.
|
|
215
|
+
- **Find request headers**: Locate a request where the domain is "api.blocket.se" and the file is "searches". *Pretty much every request to api.blocket.se contains this auth-header, so any request will do.*
|
|
216
|
+
- **Inspect request headers**: Look at the request headers to find your token under "Authorization".
|
|
217
|
+
|
|
218
|
+

|
|
219
|
+
|
|
220
|
+
My token has never expired or changed during this project. However, if your're met with a `401 Unauthorized` at some point, you may want to refresh your token by repeating the steps above.
|
|
221
|
+
|
|
222
|
+
## 📝 Notes
|
|
223
|
+
|
|
224
|
+
- Source repo: https://github.com/dunderrrrrr/blocket_api
|
|
225
|
+
- PyPI: https://pypi.org/project/blocket-api/
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
blocket_api/__init__.py,sha256=I06XkzHU4zGWZ2Zk9kDZlX0OZ39IT_SXv9iBA25qofA,84
|
|
2
|
+
blocket_api/blocket.py,sha256=5zTv-IhsCKHAtVI0xdu-pDrEHE5E-RQLvoG9UN8rMw4,7264
|
|
3
|
+
blocket_api-0.2.5.dist-info/licenses/LICENSE,sha256=SlUIRj6AhkUmDrxKCoiYP_DPHfk_vSvtW7qxPH9aGz8,460
|
|
4
|
+
blocket_api-0.2.5.dist-info/METADATA,sha256=64AHvPgUx5fTF2K9E80MBDFaZ1DJPMYZ-GiehhLoY2U,8626
|
|
5
|
+
blocket_api-0.2.5.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
6
|
+
blocket_api-0.2.5.dist-info/top_level.txt,sha256=jbWcqpXYz4vCiWeDO9fUUzpPAtwDztvupocPkoQ9OYw,12
|
|
7
|
+
blocket_api-0.2.5.dist-info/RECORD,,
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
|
|
2
|
+
Version 2, December 2004
|
|
3
|
+
|
|
4
|
+
Copyright (C) 2018 Satwik Kansal
|
|
5
|
+
|
|
6
|
+
Everyone is permitted to copy and distribute verbatim or modified
|
|
7
|
+
copies of this license document, and changing it is allowed as long
|
|
8
|
+
as the name is changed.
|
|
9
|
+
|
|
10
|
+
DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
|
|
11
|
+
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
|
12
|
+
|
|
13
|
+
0. You just DO WHAT THE FUCK YOU WANT TO.
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
blocket_api
|