def get_for_date(self, date): if date < self._min_supported_date: return log.info("Getting Sberbank %s rates for %s...", self._name, date) day_urls = self._get_urls(date) if not day_urls: log.debug("There is no data for Sberbank %s rates for %s.", self._name, date) return for url_id, url in enumerate(day_urls): try: xls_contents = fetch_url(url).content except RequestException as e: if e.response is not None and e.response.status_code == requests.codes.not_found: # It's a common error when we have 2 reports per day (log.warning if url_id == len(day_urls) - 1 else log.debug)( "Unable to download '%s': %s. Skipping it...", url, e) else: raise Error("Failed to get Sberbank currency rates from {}: {}.", url, e) else: break else: return try: rates = self.parse(xls_contents) except Exception as e: raise Error("Error while reading Sberbank currency rates obtained from {}: {}", url, e) log.debug("Gotten rates: %s", rates) return rates
def _get_month_urls(self, date): month_rates_url = "{prefix}moscow/ru/quotes/{archive}/index.php?year115={year}&month115={month}".format( prefix=self.__url_prefix, archive=self._sberbank_archive_name, year=date.year, month=date.month) rate_list_html = fetch_url(month_rates_url).text base_url = "/common/img/uploaded/banks/uploaded_mb/c_list/{}/download/".format(self._sberbank_rates_list_name) rate_url_matches = list(re.finditer( r'"(?P<url>' + re.escape(base_url) + r'(?P<year>\d{4})/(?P<upload_month>\d{2})/' + self._sberbank_rates_name + r'(?P<month>\d{2})(?P<day>\d{2})(_\d)?.xls)"', rate_list_html, re.VERBOSE)) day_urls = {} if not rate_url_matches and not _is_month_may_be_empty(date): raise Error("Server returned an unexpected response") for match in rate_url_matches: rate_year, rate_month = int(match.group("year")), int(match.group("month")) if (rate_year, rate_month) != (date.year, date.month): # If we ask for data that Sberbank doesn't have it returns data for previous/current month/year. if not day_urls and _is_month_may_be_empty(date): return day_urls raise Error("Server returned data for invalid month ({:02d}.{} instead of {:02d}.{}) on {}", rate_month, rate_year, date.month, date.year, month_rates_url) url = match.group("url") if "://" not in url: url = self.__url_prefix + url.lstrip("/") day_urls.setdefault(int(match.group("day")), []).append(url) return day_urls
def _get_tinkoff_rates(): rates = {} try: for rate in fetch_url("https://www.tinkoff.ru/api/v1/currency_rates").json()["payload"]["rates"]: if ( rate["category"] == "DepositPayments" and rate["fromCurrency"]["name"] in ("USD", "EUR") and rate["toCurrency"]["name"] == "RUB" ): rates[rate["fromCurrency"]["name"] + "_SBRF"] = (Decimal(rate["sell"]), Decimal(rate["buy"])) if len(rates) != 2: raise Error("Unable to find all requested rates in API response") except Exception as e: raise Error("Failed to get currency rates from Tinkoff: {}.", e) return rates