Tässä verkkokaappausopetusohjelmassa tarkastellaan Redfinin kaapimista – suosittua kiinteistöjen listaussivua.
Kaavimme kiinteistötiedot, kuten hintatiedot, osoitteet, valokuvat ja puhelinnumerot, jotka näkyvät Redfinin kiinteistösivuilla.
Käytämme Redfin-ominaisuuksien raapimiseenpiilotettu verkkotietojen kaapiminenmenetelmä. Tutustumme myös siihen, kuinka voit löytää kiinteistöjä Redfinin haku- ja sivukarttajärjestelmän avulla kerätäksemme koko sivustolla olevan kiinteistötietojoukon.
Lopuksi katamme myös kiinteistöjen seurannan etsimällä jatkuvasti uusia listattuja tai päivitettyjä tietoja, mikä antaa meille ylivoiman kiinteistöhinnoittelussa. Käytämme Pythonia muutaman yhteisön kirjaston kanssa - Sukellaanpa sisään!
Miksi Scrape Redfin.com?
Redfin.com on yksi suurimmista kiinteistösivustoista Yhdysvalloissa, mikä tekee siitä suurimman julkisen kiinteistötietojoukon. Sisältää kenttiä, kuten kiinteistöjen hinnat, listauspaikat ja myyntipäivämäärät sekä yleiset kiinteistötiedot.
Tämä on arvokasta tietoa markkina-analytiikkaan, asuntoalan tutkimukseen ja yleiseen kilpailijakatsaukseen. Verkkokaappauksella Redfin saamme helposti käsiksi suuren kiinteistötietojoukon.
Katso meidänKaavinta käyttötapauksetopas lisää.
Käytettävissä olevat Redfind-tietokentät
Voimme kaapata Redfin useille suosituille kiinteistötietokentille ja kohteille:
- Kiinteistöt myytävänä
- Maata myytävänä
- Avointen ovien tapahtumia
- Kiinteistöt vuokralle
- Kiinteistönvälittäjän tiedot
Tässä oppaassa käsittelemme keskittymistä kiinteistöjen kaavintamiseen (vuokra ja myynti), vaikka kaikkea oppimaansa on helppo soveltaa muille sivuille.
Projektin asennus
Tässä opetusohjelmassa käytämme Pythonia kolmen yhteisöpaketin kanssa:
- httpx- HTTP-asiakaskirjasto, jonka avulla voimme kommunikoida Redfin.comin palvelimien kanssa
- paketti- HTML-jäsennyskirjasto, joka auttaa meitä jäsentämään web-kaapattuja HTML-tiedostoja.
- jmespath- JSON-jäsennyskirjasto. Mahdollistaa XPath-tyyppisten sääntöjen kirjoittamisen JSONille.
Nämä paketit voidaan asentaa helpostipip asennus
komento:
$ pip asennus httpx parsel jmespath
Vaihtoehtoisesti voit vapaasti vaihtaahttpx
ulos minkä tahansa muun HTTP-asiakaspaketin kanssa, kutenpyynnötkoska tarvitsemme vain HTTP-perustoimintoja, jotka ovat lähes vaihdettavissa jokaisessa kirjastossa. Mitä tulee,paketti
, toinen loistava vaihtoehto onkaunis keittopaketti.
Redfin-kiinteistötietojen kaapiminen
Katsotaanpa aluksi, kuinka yksittäisen listaussivun ominaisuustiedot voidaan kaapata.
Redfin käyttää Next.js:ää sivujen hahmontamiseen. Voimme hyödyntää tätä tosiasiaa ja raaputtaa piilotetut verkkotiedot sen sijaan, että jäsentäisimme HTML:n suoraan. Tämä saattaa vaikuttaa hieman monimutkaiselta, joten jos et ole perehtynyt piilotettujen verkkotietojen kaapimiseen, katso esittelyartikkeliamme:
Redfinin piilotettu tietojoukko sisältää kaikki kiinteistötiedot ja paljon muuta. Tässä skenaariossa ominaisuustiedot sijaitsevat JavaScript-muuttujassa__reactServerState.InitialContext
:
Poimimme koko tietojoukon seuraavasti:
- Etsi
käsikirjoitus
elementti, joka sisältää tämän JavaScript-muuttujan - Käytä säännöllisiä lausekkeita löytääksesi muuttujan arvon
- Lataa se Python-sanakirjana ja puhdista tietojoukko
Katsotaanpa sitä toiminnassa:
import jsonimport asyncio from httpx import AsyncClient, Responsefrom parsel import Selectorsession = AsyncClient(headers={ # käytä samoja otsikoita kuin suosittu selain (tässä tapauksessa Chrome Windowsissa) "User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, kuten Gecko) Chrome/91.0.4472.114 Safari/537.36", "Hyväksy": "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image /webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9", "Accept-Language": "en-US,en;q=0.9"}) def extract_cache(react_initial_context): """poimi mikropalvelun välimuistitiedot react-palvelinagentista""" tulos = {} nimelle, välimuisti react_initial_context["ReactServerAgent.cache"]["dataCache"].items(): # ensin haemme välimuistiin tallennetun vastauksen ja katsomme onnistuiko se kokeile: cache_response = cache["res"] paitsi KeyError: # tyhjä välimuisti jatka jos cache_response.get("status") != 200: print("ohita ei 200 välimuistia") jatka # pura sitten välimuistissa olevan vastauksen runko ja tulkitse se JSON-muodossa cache_data = cache_response.get("body", {}).get("payload"), jos ei cache_data: cache_data = json.loads(cache_response["text"].split ("&&", 1)[-1]).get("hyötykuorma") jos ei cache_data: # ohita tyhjät välimuistit jatka # varten Redfin voimme puhdistaa välimuistin nimet kodin datapäätepisteille: jos "/home/details" nimessä : nimi = nimi.split("/home/details/")[-1] tulos[nimi.korvaa("/", "")] = cache_data # ^huomautus: puhdistamme nimen vinoviivojen välttämiseksi, koska ne eivät ole sallittuja JMESPathissa return resultdef parse_property(response: Response): selector = Selector(response.text) script = selector.xpath('//script[contains(.,"ServerState.InitialContext")]/text()').get( ) origin_context = re.findall(r"ServerState.InitialContext = (\{.+\});", komentosarja), jos ei alkuperäinen_context: print(f"sivu {response.url} ei ole omaisuusluettelosivu") return extract_cache(json.loads(initial_context[0]))async def scrape_properties(urls: List[str]) -> List[PropertyResult]: to_scrape = [session.get(url) URL-osoitteelle URL-osoitteissa] property = [] vastaukselle kohdassa asyncio.as_completed(to_scrape): properties.append(parse_property(wait response)) palauttaa ominaisuudet
Suorita koodi
Käyttääksemme kaavinta meidän tarvitsee vain kutsua asyncio-korutiini:
urls = [ "https://www.redfin.com/FL/Cape-Coral/402-SW-28th-St-33914/home/61856041", "https://www.redfin.com/FL/Cape- Coral/4202-NW-16th-Ter-33993/home/62053611", "https://www.redfin.com/FL/Cape-Coral/1415-NW-38th-Pl-33993/home/62079956",] if __name__ == "__main__": asyncio.run(scrape_properties(urls))
Yllä käytimmehttpx
noutaaksesi HTML-sivun ja ladataksesi sen aparsel.Valitsija
. Sitten löydämme komentosarjaelementin, joka sisältää javascriptin välimuistimuuttujan. Välimuistin purkamiseen käytämme yksinkertaista säännöllistä lauseketta, joka kaappaa tekstin väliltäInitialContext
avainsana ja};
merkki.
Tämä johtaa valtavaan Redfin-omaisuustietoon, ja koska tämä on sisäinen verkkotietojoukko, se on täynnä teknisiä tietokenttiä - meidän piti siivota vähän. Jäsennetään se!
Jäsennetään Redfin-tietoja
Kaavittu tietojoukko on valtava ja sisältää paljon hyödytöntä tietoa. Käytämme JMESPathia - suosittua JSON-jäsennyssyntaksia jäsentääksemme sen johonkin, jonka voimme sulattaa.
JMESPath on vähän samanlainen kuin XPath- tai CSS-valitsimet, mutta JSONille. Sen avulla voimme luoda polkusääntöjä siitä, mistä löytää tietokentät, jotka haluamme säilyttää.
Esimerkiksi hinnan määrittämiseksi käytämme JMESPath-polkua:
aboveTheFold.addressSectionInfo.priceInfo.amount
Katsotaanpa koko jäsennintä:
kirjoituksesta tuonti TypedDictimport jmespathclass PropertyResult(TypedDict): """tyyppivihje ominaisuuden tulokselle. eli määrittää, mitä kenttiä odotetaan kiinteistötietojoukossa""" kuvat: List[str] videot: List[str] hinta: int info: Dict[ str, str] palvelut: Lista[Dict[str, str]] tietueet: Dict[str, str] historia: Dict[str, str] pohjapiirros: Dict[str, str] aktiviteetti: Dict[str, str]def parse_redfin_proprety_cache( data_cache) -> PropertyResult: """jäsentää Redfinin välimuistitiedot ominaisuustietoja varten""" # tässä määritetään kentän nimi JMESPathin kartoitukseen parse_map = { # sivun yläosasta: perustiedot, videot ja valokuvat "kuvat": " edellä ""aboveTheFold.addressSectionInfo.{ bed_num: beds, bath_numr: baths, full_baths_num: numFullBaths, sqFt: sqFt, year_built: yearBuitlt, kaupunki: kaupunki, osavaltio: osavaltio, postinumero: postinumero, maa_koodi: maakoodi, ap: maakoodi, , redfin_age: timeOnRedfin, cumulative_days_on_market: cumulativeDaysOnMarket, property_type: propertyType, listing_type: listingType, url: url } """, # sivun alaosasta: palvelut, tietueet ja tapahtumahistoria "amenities": """amenitiesInfo. superGroups[].amenityGroups[].amenityEntries[].{ nimi: amenityName, arvot: amenityValues }""", "records": "belowTheFold.publicRecordsInfo", "history": "belowTheFold.propertyHistoryInfo", # muu: joskus siellä ovat pohjapiirrokset "floorplan": r"listingfloorplans.floorPlans", # ja siellä on aina sisäisiä Redfinin suorituskykytietoja: katselut, tallennukset jne. "activity": "activityInfo", } tulokset = {} avaimelle, polku parse_map.items( ): arvo = jmespath.search(polku, data_cache) tulokset[avain] = arvon palautustulokset
Esimerkkilähtö
{ "valokuvat": [ "https://ssl.cdn-redfin.com/photo/192/bigphoto/966/222084966_0.jpg", "https://ssl.cdn-redfin.com/photo/192/bigphoto /966/222084966_1_0.jpg", "https://ssl.cdn-redfin.com/photo/192/bigphoto/966/222084966_2_0.jpg", "https://ssl.cdn-redfin.com/photo/192 /bigphoto/966/222084966_3_0.jpg", "https://ssl.cdn-redfin.com/photo/192/bigphoto/966/222084966_4_0.jpg", "https://ssl.cdn-redfin.com/photo /192/bigphoto/966/222084966_5_0.jpg", "https://ssl.cdn-redfin.com/photo/192/bigphoto/966/222084966_6_0.jpg", "https://ssl.cdn-redfin.com /photo/192/bigphoto/966/222084966_7_0.jpg", "https://ssl.cdn-redfin.com/photo/192/bigphoto/966/222084966_8_0.jpg", "https://ssl.cdn-redfin .com/photo/192/bigphoto/966/222084966_9_0.jpg", "https://ssl.cdn-redfin.com/photo/192/bigphoto/966/222084966_10_0.jpg", "https://ssl.cdn -redfin.com/photo/192/bigphoto/966/222084966_11_0.jpg", "https://ssl.cdn-redfin.com/photo/192/bigphoto/966/222084966_12_0.jpg" ], "videot": [ " year_built": null, "city": "Cape Coral", "state": "FL", "zip": "33909", "country_code": "US", "fips": "12071", "apn": 304324C2137060780 home/178539241" }, "mukavuudet": [ { "nimi": "Pysäköinti", "arvot": [ "2+ paikkaa", "Ajotieltä päällystetty" ] }, { "nimi": "Palvelut", "arvot" : [ "Koripallo", "Business Center", "Clubhouse", "Community Pool", "Community Room", "Community Spa/Hot tub", "Harjoitteluhuone", "Pickleball", "Play Area", "Sidewalk" , "Tennis Court", "Underground Utility", "Lentopallo" ] }, ... // trucated for blog ], "records": { "basicInfo": { "propertyTypeName": "Townhouse", "lotSqFt": 1965 , "apn": "304324C2137060780", "propertyLastUpdatedDate": 1669759070845, "displayTimeZone": "US/Eastern" }, "taxInfo": {}, "allTaxInfo": [], "addressFInfo": []":"addressFInfo , "street": "1445 Weeping Willow Ct", "city": "Cape Coral", "state": "FL", "zip": "33909", "countryCode": "US" }, "mortgageCalculatorInfo": { "displayLevel": 1, "dataSourceId": 192, "listingPrice": 311485, "downPaymentPercentage": 20.0, "monthlyHoaDues": 312, "propertyTaxRate": 1.29, "homeInsuranceRate.1,7,0:surance1mortRate1",7,0:vakuutus1moraali " creditScore": 740, "lainatyyppi": 1, "kiinnityskorkotiedot": { "fifteenYearFixed": 5.725, "fiveOneArm": 5.964, "thirtyYearFixed": 6.437, "isFromBankrate},"sta":4 true1d" : 19, "countyName": "Lee County", "stateName": "Florida", "mortgageRatesPageLinkText": "Näytä kaikki hinnat", "baseMortgageRatesPageURL": "/mortgage-rates?location=33909&locationType=4&locationI5",=1&locationI5 zipCode": "33909", "isCoop": false }, "countyUrl": "/county/471/FL/Lee-County", "countyName": "Lee County", "countyIsActive": tosi, "sectionPreviewText": "Maakunnan tiedot päivitetty 29.11.2022" }, "historia": { "isHistoryStillGrowing": tosi, "hasAdminContent": false, "hasLoginContent": false, "dataSourceId": 192, "canSeeListing": tosiN, "listausI" ": false, "hasPropertyHistory": tosi, "showLogoInLists": false, "definitions": [], "displayTimeZone": "US/Eastern", "isAdminOnlyView": false, "events": [ { "isEventAdminOnly": false , "price": 311485, "isPriceAdminOnly": false, "eventDescription": "Listed", "mlsDescription": "Active", "source": "BEARMLS", "sourceId": "222084966", "dataSourceDisplay": { "dataSourceId": 192, "dataSourceDescription": "Bonita Springs Association of Realtors (BEARMLS)", "dataSourceName": "BEARMLS", "shouldShowLargerLogo": false }, "priceDisplayLevel": 1, "historyEventType":Date ": 1669708800000 } ], "mediaBrowserInfoBySourceId": {}, "addressInfo": { "isFMLS": false, "street": "1445 Weeping Willow Ct", "city": "Cape Coral", "osavaltio": "FL ", "zip": "33909", "countryCode": "US" }, "isFMLS": false, "historyHasHiddenRows": false, "priceEstimates": { "displayLevel": 1, "priceHomeUrl": "/what- is-my-home-worth?estPropertyId=178539241&src=ldp-estimates" }, "sectionPreviewText": "Tiedot lisätään, kun saamme ne" }, "floorplan": [ "https://ssl.cdn-redfin. com/photo/192/bigphoto/966/222084966_1_0.jpg", ], "activity": { "viewCount": 28, "favoritesCount": 1, "totalFavoritesCount": 1, "xOutCount": 0, "totalXOutCount": 0, "tourCount": 0, "totalTourCount": 0, "addressInfo": { "isFMLS": false, "street": "1445 Weeping Willow Ct", "city": "Cape Coral", "state": " FL", "zip": "33909", "countryCode": "US" }, "sectionPreviewText": "1 henkilö lisäsi tämän kodin suosikkeihin" } }
Olemme vähentäneet tuhansia rivejä pitkän Redfin-ominaisuustietojoukon vain muutamaan tusinaan tärkeimpiin kenttiin JMESPathin ja Pythonin avulla.
Voimme nähdä, kuinka helppoa on kaapata nykyaikaisia verkkosivustoja nykyaikaisilla kaavintatyökaluilla - Redfin-ominaisuuden kaappaamiseen käytimme vain muutaman rivin Python-koodia. Katsotaan seuraavaksi, kuinka voimme löytää listauksia kaavittavaksi.
Redfin-ominaisuuksien etsiminen
On olemassa useita tapoja löytää tietoja Redfinistä kaapimista varten. Vaikka ilmeisin ja nopein tapa on käyttää Redfinin sivustokarttoja.
Redfin tarjoaa laajan sivustokarttajärjestelmän, joka sisältää sivustokartat listauksille Yhdysvaltain osavaltion, naapuruston, koulupiirin ja niin edelleen. Katsotaanpa sitä varten/robots.txtsivu, erityisesti sivustokarttaosio.
Esimerkiksi kaikille sijaintihakemistoille on sivustokartat:
Ja vuokratiedot:
Lopuksi meillä on sivustokartat kohteille, joita ei ole listattuAgentit.
Redfin-listausmuutosten jälkeen
Uusien Redfin-listausten seuraamiseksi voimme käyttää uusimpien ja päivitettyjen listausten sivustokarttasyötteitä:
- uusinjoka ilmoittaa, kun uusia ilmoituksia julkaistaan.
- Viimeisinmikä ilmoittaa, kun listauksia päivitetään tai muutetaan.
Uusien listausten ja päivitysten löytämiseksi kaavimme nämä kaksi sivustokarttaa, jotka sisältävät luettelon URL-osoitteen ja aikaleiman, kun ne listattiin tai päivitettiin:
https://www.redfin.com/NH/Boscawen/1-Sherman-Dr-03303/home/96531826 2022-12-01T00:53:20.426-08: 00 päivittäin 1.0
⌚ Huomaa, että tämä sivustokartta käyttää UTC-8-aikavyöhykettä. Se osoitetaan päivämäärä-aika-merkkijonon viimeisellä numerolla: -08.00.
Käytämme näiden Redfin-syötteiden kaappaamiseen Pythonissahttpx
japaketti
aiemmin käyttämämme kirjastot:
tuontinuoli # päivämäärän käsittelyyn: pip install arrow from httpx import AsyncClientsession = AsyncClient(headers={ # käytä samoja otsikoita kuin suosittu selain (tässä tapauksessa Chrome Windowsissa) "User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, kuten Gecko) Chrome/91.0.4472.114 Safari/537.36", "Hyväksy": "text/html,sovellus/xhtml+xml,sovellus/xml;q=0.9,image/avi ,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9", "Accept-Language": "en-US,en;q=0.9", })async def scrape_feed(url) -> Dict[str, datetime]: """raavi Redfin-sivustokartta ja palauta url:datetime dictionary""" tulos = odota session.get(url) selector = Selector(text=result.text , type="xml") tulokset = {} kohteelle valikossa.xpath("//url"): url = item.xpath("loc/text()").get() julkaisupäivä = item.xpath(" lastmod/text()").get(%Y-%m-%dT%H:%M:%S.%f%z) tulokset[url] = arrow.get(julkaisupäivä).päivämäärän palautustulokset
Voimme sitten käyttää aiemmin kirjoittamaamme Python Redfin -kaavinta näiden URL-osoitteiden kaapimiseen kiinteistötietojoukkoja varten.
Ohita punaräpylä esto ScrapFlyllä
RaapiminenRedfin.comnäyttää kuitenkin erittäin suoraviivaiselta, kun kaavinta mittakaavassa, kaavinemme todennäköisesti tukkeutuvat tai niitä pyydetään ratkaisemaan captchas.

Voit kiertää tämän hyödyntämälläScrapFly APIjoka voi välttää kaikki nämä esteet meille!
ScrapFly tarjoaa useita tehokkaita ominaisuuksia, jotka auttavat meitä kiertämään Redfinin verkkokaapin eston:
- Anti-Craping Protection Bypass
- Javascriptin renderöinti
- 190 miljoonaa asuin- tai mobiilivälityspalvelinta
Tätä varten käytämmescrapfly-sdkpython-paketti jaAnti-Craping Protection Bypassominaisuus. Ensin asennetaanscrapfly-sdk
käyttämällä pipiä:
$ pip asenna scrapfly-sdk
Jotta voimme hyödyntää ScrapFlyn API:ta Redfin.com-verkkokaapimessamme, meidän tarvitsee vain muuttaahttpx
istuntokoodiscrapfly-sdk
asiakas pyytää:
import httpxresponse = httpx.get("some redfin.com url")# ScrapFly SDK:ssa tulee scrapfly-importista ScrapflyClient, ScrapeConfigclient = ScrapflyClient("SECRAPFLY KEY")result = client.scrapeConfig(Scm "Redfinl(Sc. # voimme valita tietyn välityspalvelimen maan country="US", # ja ottaa käyttöön kaapimisen eston ohituksen: asp=True))
Lisätietoja Redfin.com-sivuston kaapimisesta ScrapFlyllä on osoitteessaTäysi kaavinkoodiosio.
FAQ
Tämän oppaan päätteeksi tarkastellaan joitain usein kysyttyjä kysymyksiä Redfin-tietojen verkkokaappauksesta:
Onko Redfin.comin kaapiminen laillista?
Joo. Redfin.comin tiedot ovat julkisesti saatavilla; emme kerää mitään yksityistä. Redfinin kaapiminen hitaalla, kunnioittavalla nopeudella kuuluisi eettisen kaapimisen määritelmän piiriin.
Tästä huolimatta EU:ssa tulee kiinnittää huomiota GDRP-yhteensopivuuteen tallennettaessa henkilötietoja, kuten myyjän nimi, puhelinnumero jne. Katso lisätietojaOnko Web-raapiminen laillista?artikla.
Onko Redfin.comilla API?
Ei, kiinteistötiedoille ei kuitenkaan ole Redfin API:a, Redfin julkaisee markkinayhteenvetotietojoukottietokeskusosio. Yksityiskohtaisia kiinteistötietoja varten voimme raaputtaa Redfin-tiedot Pythonilla.
Kuinka indeksoida Redfin.com?
Kuten kaavinta, voimme myös indeksoida redfin.com-sivuston seuraamalla asiaan liittyviä vuokrasivuja jokaisella kiinteistön sivulla. Jos haluat kirjoittaa Redfin-indeksointirobotin, katso aiheeseen liittyvät ominaisuudet -kenttä tässä opetusohjelmassa kerätyissä tietojoukoissa.
Redfin kaavinta yhteenveto
Tässä opetusohjelmassa rakensimme aRedfinkaavin Pythonissa muutamalla ilmaisella yhteisöpaketilla. Aloitimme tarkastelemalla, kuinka yksittäinen omaisuussivu kaavitaan purkamalla piilotetut verkkovälimuistitiedot.
Kiinteistötietojen jäsentämiseen käytimme JMESPath JSON -jäsennyskieltä muutaman yksinkertaisen säännön kirjoittamiseen, mikä vähensi kaapatun tietojoukon tärkeiksi omaisuuden tietokentiksi.
Lopuksi, etsiäksemme kiinteistöilmoituksia ja seurataksemme uusia/päivitettyjä kohteita, tutkimme Redfinin sivustokarttajärjestelmää.
Tässä Redfin-datakaapimessa käytimme Pythoniahttpx,pakettijajmespathpaketteja. Estisten välttämiseksi käytimme ScrapFlyn API:ta, joka määrittää älykkäästi jokaisen verkkokaapimen yhteyden estymisen välttämiseksi.
Katso lisätietoja ScrapFlystä dokumentaatiostamme ja kokeile sitä ILMAISEKSI!
Täysi Redfin Scraper Code
Tässä on koko Redfin-verkkokaavinkoodi ScrapFly-integraatiolla:
💙 Tätä koodia tulee käyttää vain viitteenä. Jotta voit kaapata tietoja Redfinistä suuressa mittakaavassa, tarvitset virheenkäsittelyn, kirjaamisen ja uudelleenyrityslogiikkaa
tuonti asyncioimport jsonimport lähteestä datetime tuonti datetimefrom pathlib tuonti Polku kirjoittamisesta import Dict, Listimport arrowimport jmespath from scrapfly import ScrapeApiResponse, ScrapeConfig, ScrapflyClientfrom typing_extensions KEY", max_concurrency=2)def extract_cache(react_initial_context): "" "pura mikropalvelun välimuistitiedot react-palvelinagentista""" tulos = {} nimelle, välimuisti react_initial_context["ReactServerAgent.cache"]["dataCache"].items(): # ensin haetaan välimuistissa oleva vastaus ja katsotaan onko se onnistunut yritys: cache_response = cache["res"] paitsi KeyError: # tyhjä välimuisti jatka jos cache_response.get("status") != 200: print("ohitetaan non 200 cache") jatka # sitten pura välimuistissa olevan vastauksen runko ja tulkitse se JSON-muodossa cache_data = cache_response.get("body", {}).get("payload"), jos ei cache_data: cache_data = json.loads(cache_response["text"].split("&&", 1)[ -1]).get("hyötykuorma") jos ei cache_data: # ohita tyhjät välimuistit jatka # varten Redfin voimme puhdistaa välimuistin nimet kotidatan päätepisteille: jos "/home/details" nimessä: nimi = nimi.split(" /home/details/")[-1] tulos[nimi.korvaa("/", "")] = cache_data # ^huomautus: puhdistamme nimen vinoviivojen välttämiseksi, koska ne eivät ole sallittuja JMESPathin tulosluokissa PropertyResult(TypedDict) : """tyyppivihje ominaisuuden tulokselle. eli määrittää, mitä kenttiä odotetaan kiinteistötietojoukossa""" valokuvat: List[str] videot: List[str] hinta: int info: Dict[str, str] mukavuudet: List[Dict[str, str]] tietueet: Dict[ str, str] historia: Dict[str, str] pohjapiirros: Dict[str, str] aktiviteetti: Dict[str, str]def parse_redfin_proprety_cache(data_cache) -> PropertyResult: """jäsentää Redfinin välimuistitiedot ominaisuustietoja varten""" # tässä määritetään kentän nimi JMESPath-kartoitukseen parse_map = { # sivun yläosasta: perustiedot, videot ja valokuvat "photos": "aboveTheFold.mediaBrowserInfo.photos[*].photoUrls.fullScreenPhotoUrl", "videot": " edellä sqFt: sqFt, year_built: yearBuitlt, kaupunki: kaupunki, osavaltio: osavaltio, postinumero: zip, country_code: countryCode, fips: fips, apn: apn, redfin_age: timeOnRedfin, kumulatiiviset_päivät_markkinoilla: kumulatiivisetDaysOnMarket, kiinteistöjen_luettelo: tyyppi, kiinteistöluettelo: url } """, # sivun alaosasta: palvelut, tietueet ja tapahtumahistoria "amenities": """belowTheFold.amenitiesInfo.superGroups[].amenityGroups[].amenityEntries[].{ nimi: amenityName, arvot: amenityValues }""", "records": "belowTheFold.publicRecordsInfo", "history": "belowTheFold.propertyHistoryInfo", # muu: joskus on pohjapiirroksia "floorplan": r"listingfloorplans.floorPlans", # ja siellä on aina sisäinen Redfin suorituskykytiedot: katselut, tallennukset jne. "activity": "activityInfo", } tulokset = {} avaimelle, polku parse_map.items(): arvo = jmespath.search(polku, data_cache) tulokset[avain] = arvon palautus tulokset (r"ServerState.InitialContext = (\{.+\});", komentosarja) jos ei aloituskonteksti: print(f"sivu {tulos.konteksti['url']} ei ole omaisuusluettelosivu") return parse_redfin_proprety_cache (extract_cache(json.loads(initial_context[0])))async def scrape_properties(urls: List[str]) -> List[PropertyResult]: to_scrape = [ScrapeConfig(url=url, asp=True, country="US" , cache=True) for url in urls] properties = [] async tulokselle scrapfly.concurrent_scrape(to_scrape): properties.append(parse_property(result)) return propertiesasync def scrape_feed(url) -> Dict[str, date time]: """Scrape Redfin sitemap for URLs""" result = odota scrapfly.async_scrape(ScrapeConfig(url=url, country="US", cache=True, asp=True)) tulokset = {} kohteelle result.selectorissa. xpath("//url"): url = item.xpath("loc/text()").get() julkaisupäivä = item.xpath("lastmod/text()").get() tulokset[url] = arrow.get(pub_date).datetime return resultsasync def example_run(): urls = [ "https://www.redfin.com/FL/Cape-Coral/402-SW-28th-St-33914/home/61856041", "https://www.redfin.com/FL/Cape-Coral/4202-NW-16th-Ter-33993/home/62053611", "https://www.redfin.com/FL/Cape-Coral/1415 -NW-38th-Pl-33993/home/62079956", "https://www.redfin.com/FL/Cape-Coral/1026-NE-34th-Ln-33909/home/67830364", "https:/ /www.redfin.com/FL/Cape-Coral/1022-NE-34th-Ln-33909/home/62069246", "https://www.redfin.com/FL/Cape-Coral/4132-NE-21st -Ave-33909/home/67818227", "https://www.redfin.com/FL/Cape-Coral/2115-NW-8th-Ter-33993/home/62069405", "https://www.redfin .com/FL/Cape-Coral/1451-Weeping-Willow-Ct-33909/home/178539244", "https://www.redfin.com/FL/Cape-Coral/1449-Weeping-Willow-Ct-33909 /home/178539243", "https://www.redfin.com/FL/Cape-Coral/5431-SW-6th-Ave-33914/home/61888403", "https://www.redfin.com/FL /Cape-Coral/1445-Weeping-Willow-Ct-33909/home/178539241", ] feed = odota scrape_feed("https://www.redfin.com/stingray/api/gis-cms/city-sitemap/CA /San-Francisco?channel=buy") asyncio.run(scrape_feed("https://www.redfin.com/newest_listings.xml"))if __name__ == "__main__": asyncio.run(example_run())