def __init__(self): """ Alustaa wrapperin. """ self.vr_scraper = VRScraper() self.mh_scraper = MHScraper() self.auto_scraper = AutoScraper() self.scraperit = [self.vr_scraper, self.mh_scraper, self.auto_scraper] # Luetaan paikkatiedot erillisestä tiedostosta: paikat = json.load(open("paikat.json", "r")) for k, v in paikat.iteritems(): paikat[k] = [p.encode("utf-8") if p else None for p in v] self.paikat = paikat
class ScraperWrapper: """Käärii scraperit yhden rajapinnan alle.""" def __init__(self): """ Alustaa wrapperin. """ self.vr_scraper = VRScraper() self.mh_scraper = MHScraper() self.auto_scraper = AutoScraper() self.scraperit = [self.vr_scraper, self.mh_scraper, self.auto_scraper] # Luetaan paikkatiedot erillisestä tiedostosta: paikat = json.load(open("paikat.json", "r")) for k, v in paikat.iteritems(): paikat[k] = [p.encode("utf-8") if p else None for p in v] self.paikat = paikat def hae_matka( self, mista=None, mihin=None, lahtoaika=None, saapumisaika=None, bussi=True, juna=True, auto=True, aleluokka=0, max_lkm=6, polttoaine=0, kulutus=6.5, ): """ Palauttaa valitulle matkalle löytyneet yhteydet. """ assert type(mista) == type(mihin) == unicode assert lahtoaika is not None or saapumisaika is not None # TODO debug logging.info("hae_matka(mista=%s, mihin=%s" % (mista, mihin)) # Selvitetään haettuja paikkoja vastaavat MH:n, VR:n ja Googlen paikat: for k, v in self.paikat.iteritems(): if k == mista: mista = v if isinstance(mihin, list): break if k == mihin: mihin = v if isinstance(mista, list): break # Jos paikkoja ei löytynyt: if not isinstance(mista, list): return dict(virhe="mista") if not isinstance(mihin, list): return dict(virhe="mihin") mista_mh, mista_vr, mista_auto = mista mihin_mh, mihin_vr, mihin_auto = mihin dt = lahtoaika or saapumisaika pvm = dt.split()[0] def f(scraper): """ Apufunktio, joka tarkistaa välimuistin ja hakee tarvittaessa uuden tuloksen skreipperiltä. """ # Määritetään skreipperistä riippuva välimuistin avain: if scraper is self.mh_scraper: mista, mihin = mista_mh, mihin_mh tyyppi = "bussi" cache_avain = "mh_%s_%s_%s" % (mista, mihin, pvm) elif scraper is self.vr_scraper: # TODO Tälle ei tule paljoa osumia, parempi vaihtoehto? mista, mihin = mista_vr, mihin_vr tyyppi = "juna" cache_avain = "vr_%s_%s_%s" % (mista, mihin, dt) else: mista, mihin = mista_auto, mihin_auto tyyppi = "auto" cache_avain = "auto_%s_%s" % (mista, mihin) if not mista or not mihin: return None, tyyppi tulos = memcache.get(cache_avain) if tulos is not None: logging.info("CACHE HIT, key:" + cache_avain) else: try: tulos = scraper.hae_matka(mista, mihin, lahtoaika, saapumisaika) if tulos: if "virhe" in tulos: # TODO Virheiden käsittely return tulos, tyyppi else: memcache.set(cache_avain, tulos, 60 * 60 * 48) else: tulos = {"virhe": "ei yhteyksiä"} except IOError: tulos = {"virhe": "sivun avaaminen epäonnistui"} # Jos haetaan automatkaa, lasketaan polttoaineen hinta: if tyyppi == "auto": if tulos and "matkanpituus" in tulos: hinta = self.hae_bensan_hinnat()[polttoaine] pit = tulos["matkanpituus"] tulos["polttoaineen_hinta"] = hinta tulos["hinta"] = round(pit * (kulutus / 100.0) * hinta, 2) elif not "virhe" in tulos: tulos = self.rajaa_tulokset(tulos, max_lkm, lahtoaika, saapumisaika) ale = aleluokka if tyyppi == "juna": f = lambda x, y: self.vr_scraper.laske_alennus(x, ale) else: f = lambda x, y: self.mh_scraper.laske_alennus(x, ale, y) for matka in tulos: if "hinnat" in matka: if tyyppi == "bussi": mh_tyyppi = matka["vaihdot"][0]["tyyppi"].lower() else: mh_tyyppi = None matka["hinnat"] = f(matka["hinnat"], mh_tyyppi) assert tulos is not None # TODO debug return tulos, tyyppi # Palautetaan vain halutut matkustusvaihtoehdot: matkat = do_threaded_work(self.scraperit, f) lok = locals() matkat = {tyyppi: matka for matka, tyyppi in matkat if lok[tyyppi]} return matkat def hae_bensan_hinnat(self): """ Hakee bensan hinnat hinta_scraper-moduulia käyttäen. """ hinnat = memcache.get("hinnat") if hinnat not in [None, []]: # Hinnat löytyivät välimuistista logging.info("CACHE HIT, key: hinnat") return hinnat try: hinnat = hinta_scraper.hae_hinta() if not hinnat: logging.error("Polttoainehintojen skreippaaminen epäonnistui.") return HINNAT_BACKUP except IOError: logging.error("Polttoaine-urlin avaaminen epäonnistui") return HINNAT_BACKUP memcache.set("hinnat", hinnat, 60 * 60 * 24 * 7) return hinnat def rajaa_tulokset(self, tulos, max_lkm, lahtoaika, saapumisaika): """ Rajaa hakutuloksista halutun määrän tuloksia. """ if len(tulos) <= max_lkm: return tulos if lahtoaika: aika = lahtoaika.split()[1] attr = "lahtoaika" else: aika = saapumisaika.split()[1] attr = "saapumisaika" ret = None for i, matka in enumerate(tulos): if matka[attr] > aika: vas = min(int(ceil((max_lkm - 1) / 2.0)), i) oik = min(len(tulos) - 1 - i, max_lkm - 1 - vas) vas += max_lkm - vas - oik - 1 ret = tulos[i - vas : i + oik + 1] break if not ret: ret = tulos[-max_lkm:] assert len(ret) == min(max_lkm, len(tulos)) # TODO debug return ret