Skip to content

Commit

Permalink
Merge pull request #6 from Drakorgaur/pomo/bezrealitky
Browse files Browse the repository at this point in the history
added scrapper for bezrealitky web.
  • Loading branch information
janchaloupka authored Jul 15, 2023
2 parents 1e6e328 + 82df3e3 commit 1e8b0c5
Show file tree
Hide file tree
Showing 5 changed files with 106 additions and 3 deletions.
3 changes: 2 additions & 1 deletion Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ RUN pip3 install -r requirements.txt

COPY .env* .
COPY src .
COPY graphql /graphql

ENV APP_ENV=docker
CMD [ "python3", "main.py"]
CMD ["python3", "main.py"]
14 changes: 14 additions & 0 deletions graphql/bezrealitky.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
{
"operationName": "AdvertList",
"variables": {
"limit": 15,
"offset": 75,
"order": "TIMEORDER_DESC",
"locale": "CS",
"offerType": [],
"estateType": [],
"disposition": [],
"regionOsmIds": []
},
"query": "query AdvertList($locale: Locale!, $estateType: [EstateType], $offerType: [OfferType], $disposition: [Disposition], $region: ID, $regionOsmIds: [ID], $limit: Int = 15, $offset: Int = 0, $order: ResultOrder = TIMEORDER_DESC, $petFriendly: Boolean, $balconyFrom: Float, $balconyTo: Float, $loggiaFrom: Float, $loggiaTo: Float, $terraceFrom: Float, $terraceTo: Float, $cellarFrom: Float, $cellarTo: Float, $parking: Boolean, $garage: Boolean, $newBuilding: Boolean, $lift: Boolean, $ownership: [Ownership], $construction: [Construction], $equipped: [Equipped], $priceFrom: Int, $priceTo: Int, $surfaceFrom: Int, $surfaceTo: Int, $advertId: [ID], $roommate: Boolean, $includeImports: Boolean, $boundaryPoints: [GPSPointInput], $discountedOnly: Boolean, $barrierFree: Boolean, $polygonBuffer: Int, $availableFrom: DateTime) {\n listAdverts(\n offerType: $offerType\n estateType: $estateType\n disposition: $disposition\n limit: $limit\n regionId: $region\n regionOsmIds: $regionOsmIds\n offset: $offset\n order: $order\n petFriendly: $petFriendly\n balconySurfaceFrom: $balconyFrom\n balconySurfaceTo: $balconyTo\n loggiaSurfaceFrom: $loggiaFrom\n loggiaSurfaceTo: $loggiaTo\n terraceSurfaceFrom: $terraceFrom\n terraceSurfaceTo: $terraceTo\n cellarSurfaceFrom: $cellarFrom\n cellarSurfaceTo: $cellarTo\n parking: $parking\n garage: $garage\n newBuilding: $newBuilding\n lift: $lift\n ownership: $ownership\n construction: $construction\n equipped: $equipped\n priceFrom: $priceFrom\n priceTo: $priceTo\n surfaceFrom: $surfaceFrom\n surfaceTo: $surfaceTo\n ids: $advertId\n roommate: $roommate\n includeImports: $includeImports\n boundaryPoints: $boundaryPoints\n discountedOnly: $discountedOnly\n polygonBuffer: $polygonBuffer\n barrierFree: $barrierFree\n availableFrom: $availableFrom\n ) {\n list {\n id\n uri\n estateType\n offerType\n disposition\n imageAltText(locale: $locale)\n mainImage {\n id\n url(filter: RECORD_THUMB)\n __typename\n }\n address(locale: $locale)\n surface\n surfaceLand\n tags(locale: $locale)\n price\n charges\n currency\n petFriendly\n reserved\n highlighted\n roommate\n project {\n id\n __typename\n }\n gps {\n lat\n lng\n __typename\n }\n mortgageData(locale: $locale) {\n rateLow\n rateHigh\n loan\n years\n __typename\n }\n originalPrice\n isDiscounted\n nemoreport {\n id\n status\n timeCreated\n __typename\n }\n isNew\n videos {\n id\n previewUrl\n status\n __typename\n }\n links {\n id\n url\n type\n status\n __typename\n }\n __typename\n }\n totalCount\n __typename\n }\n actionList: listAdverts(\n offerType: $offerType\n estateType: $estateType\n disposition: $disposition\n regionId: $region\n regionOsmIds: $regionOsmIds\n offset: $offset\n order: $order\n petFriendly: $petFriendly\n balconySurfaceFrom: $balconyFrom\n balconySurfaceTo: $balconyTo\n loggiaSurfaceFrom: $loggiaFrom\n loggiaSurfaceTo: $loggiaTo\n terraceSurfaceFrom: $terraceFrom\n terraceSurfaceTo: $terraceTo\n cellarSurfaceFrom: $cellarFrom\n cellarSurfaceTo: $cellarTo\n parking: $parking\n garage: $garage\n newBuilding: $newBuilding\n lift: $lift\n ownership: $ownership\n construction: $construction\n equipped: $equipped\n priceFrom: $priceFrom\n priceTo: $priceTo\n surfaceFrom: $surfaceFrom\n surfaceTo: $surfaceTo\n ids: $advertId\n roommate: $roommate\n includeImports: $includeImports\n boundaryPoints: $boundaryPoints\n discountedOnly: true\n limit: 3\n availableFrom: $availableFrom\n ) {\n list {\n id\n uri\n estateType\n offerType\n disposition\n imageAltText(locale: $locale)\n mainImage {\n id\n url(filter: RECORD_THUMB)\n __typename\n }\n address(locale: $locale)\n surface\n surfaceLand\n tags(locale: $locale)\n price\n charges\n currency\n petFriendly\n reserved\n highlighted\n roommate\n project {\n id\n __typename\n }\n gps {\n lat\n lng\n __typename\n }\n mortgageData(locale: $locale) {\n rateLow\n rateHigh\n loan\n years\n __typename\n }\n originalPrice\n isDiscounted\n nemoreport {\n id\n status\n timeCreated\n __typename\n }\n isNew\n videos {\n id\n previewUrl\n status\n __typename\n }\n links {\n id\n url\n type\n status\n __typename\n }\n __typename\n }\n totalCount\n __typename\n }\n}\n"
}
2 changes: 1 addition & 1 deletion src/scrapers/rental_offer.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ class RentalOffer:
location: str
"""Lokace bytu (městská část, ulice)"""

price: int
price: int | str
"""Cena pronájmu za měsíc bez poplatků a energií"""

image_url: str
Expand Down
86 changes: 86 additions & 0 deletions src/scrapers/scraper_bezrealitky.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
""" Scraper for BezRealitky.cz
author: Mark Barzali
"""

import json
from abc import ABC as abstract
from typing import ClassVar

from disposition import Disposition
from scrapers.scraper_base import ScraperBase
from scrapers.rental_offer import RentalOffer
import requests


class ScraperBezrealitky(ScraperBase):

name = "BezRealitky"
logo_url = "https://www.bezrealitky.cz/manifest-icon-192.maskable.png"
color = 0x00CC00
base_url = "https://www.bezrealitky.cz"
file: ClassVar[str] = "/graphql/bezrealitky.json"

API: ClassVar[str] = "https://api.bezrealitky.cz/"
OFFER_TYPE: ClassVar[str] = "PRONAJEM"
ESTATE_TYPE: ClassVar[str] = "BYT"
BRNO: ClassVar[str] = "R438171"

class Routes(abstract):
GRAPHQL: ClassVar[str] = "graphql/"
OFFERS: ClassVar[str] = "nemovitosti-byty-domy/"

disposition_mapping = {
Disposition.FLAT_1KK: "DISP_1_KK",
Disposition.FLAT_1: "DISP_1_1",
Disposition.FLAT_2KK: "DISP_2_KK",
Disposition.FLAT_2: "DISP_2_1",
Disposition.FLAT_3KK: "DISP_3_KK",
Disposition.FLAT_3: "DISP_3_1",
Disposition.FLAT_4KK: "DISP_4_KK",
Disposition.FLAT_4: "DISP_4_1",
Disposition.FLAT_5_UP: None,
Disposition.FLAT_OTHERS: None,
}

def __init__(self, dispositions: Disposition):
super().__init__(dispositions)
self._read_config()
self._patch_config()

def _read_config(self) -> None:
with open(ScraperBezrealitky.file, "r") as file:
self._config = json.load(file)

def _patch_config(self):
match = {
"estateType": self.ESTATE_TYPE,
"offerType": self.OFFER_TYPE,
"disposition": self.get_dispositions_data(),
"regionOsmIds": [self.BRNO],
}
self._config["variables"].update(match)

@staticmethod
def _create_link_to_offer(item: dict) -> str:
return f"{ScraperBezrealitky.base_url}/{ScraperBezrealitky.Routes.OFFERS}{item}"

def build_response(self) -> requests.Response:
return requests.post(
url=f"{ScraperBezrealitky.API}{ScraperBezrealitky.Routes.GRAPHQL}",
json=self._config
)

def get_latest_offers(self) -> list[RentalOffer]:
response = self.build_response().json()

return [ # type: list[RentalOffer]
RentalOffer(
scraper=self,
link=self._create_link_to_offer(item["uri"]),
title=item["imageAltText"],
location=item["address"],
price=f"{item['price']} / {item['charges']}",
image_url=item["mainImage"]["url"],
)
for item in response["data"]["listAdverts"]["list"]
]
4 changes: 3 additions & 1 deletion src/scrapers_manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
from scrapers.scraper_remax import ScraperRemax
from scrapers.scraper_sreality import ScraperSreality
from scrapers.scraper_ulov_domov import ScraperUlovDomov
from scrapers.scraper_bezrealitky import ScraperBezrealitky


def create_scrapers(dispositions: Disposition) -> list[ScraperBase]:
Expand All @@ -24,7 +25,8 @@ def create_scrapers(dispositions: Disposition) -> list[ScraperBase]:
ScraperRealingo(dispositions),
ScraperRemax(dispositions),
ScraperSreality(dispositions),
ScraperUlovDomov(dispositions)
ScraperUlovDomov(dispositions),
ScraperBezrealitky(dispositions),
]


Expand Down

0 comments on commit 1e8b0c5

Please sign in to comment.