Довольно часто встречается задача получения курсов валют и сохранение результатов в базу. Задача достаточно проста, чтобы привлекать для этого "тяжелую артиллерию" типа java, поэтому предлагается воспользоваться Python.
Почему Python?
Во-первых, это современный и популярный язык, во-вторых, python повсеместно используется для автоматизации задач в Linux, так что практически на любом хосте с Linux будет Python, ну и в-третьих интересно было попробовать Python на реальной задаче.
Итак, имеем базу данных на MSSQL 2000, в которую нужно сохранить список курсов валют на каждый день. В базу нужно сохранять не все доступные курсы, а только те, которые актуальны для приложения. Таблица со списком актуальных валют также находится в базе данных.
Еще имеется внешний ресурс, который выдает список курсов, он расположен по адресу http://www.cbr.ru/scripts/XML_daily.asp. Курсы выдаются в формате XML.
Алгоритм работы скрипта выглядит следующим образом:
Сначала установим pip:
Примеры использования pymssql можно найти на странице проекта, а у меня получение списка валют выглядит следующим образом:
Затем, получение и парсинг списка курсов валют:
Для загрузки файла используется метод urlopen из библиотеки urllib2. Он возвращает поток, который можно сохранить в файл, а можно напрямую передать парсеру, как в данном случае. Для разбора полученного XML используется стандартный SAX-парсер. Чтобы парсер мог что-то сделать с полученным файлом ему необходим обработчик. Код обработчика представлен в классе CurrencyRateHandler, который наследуется от библиотечного класса xml.sax.handler.ContentHandler. Код обработчика:
Почему Python?
Во-первых, это современный и популярный язык, во-вторых, python повсеместно используется для автоматизации задач в Linux, так что практически на любом хосте с Linux будет Python, ну и в-третьих интересно было попробовать Python на реальной задаче.
Итак, имеем базу данных на MSSQL 2000, в которую нужно сохранить список курсов валют на каждый день. В базу нужно сохранять не все доступные курсы, а только те, которые актуальны для приложения. Таблица со списком актуальных валют также находится в базе данных.
Еще имеется внешний ресурс, который выдает список курсов, он расположен по адресу http://www.cbr.ru/scripts/XML_daily.asp. Курсы выдаются в формате XML.
Алгоритм работы скрипта выглядит следующим образом:
- Получить из базы список актуальных валют,
- Получить и распарсить XML с курсами валют от cbr.ru,
- Найти среди списка курсов курсы нужных валют и сохранить в базу,
- Отправить сообщение на электронную почту с результатами работы скрипта.
- Linux - ну это понятно, я использовал Ubuntu 12, но скорее всего подойдет любой современный дистрибутив,
- Python 2.6 и выше
- База данных, у меня используется MSSQL 2000
- Библиотека pymssql для создания запросов к БД
Сначала установим pip:
sudo apt-get install python-pipЗатем установим библиотеку Cython, которая нужна для сборки pymssql и не только его:
sudo pip install cythonИ еще pyrex, если она не установлена
sudo pip install pyrexПосле чего наконец можно установить pymssql:
sudo pip install pymssql
Примеры использования pymssql можно найти на странице проекта, а у меня получение списка валют выглядит следующим образом:
def load_currencies(): currencies = [] conn = pymssql.connect(host = 'dbhost', user='user',password='secret',database='my_database') try: cur = conn.cursor() cur.execute('SELECT ShortName, ID FROM [Currency] where not exists(select * from Currency_Exchange_Rate \ where ListID = %d and FromCurrency = Currency.ID and [Date] = dbo.GetDay(GETDATE()))', 1) row = cur.fetchone() while row: currencies.append({'Name':row[0], 'ID':row[1]}) row = cur.fetchone() finally: conn.close() return currenciesФункция load_currencies возвращает список актуальных валют, для которых не установлен курс на текущую дату.
Затем, получение и парсинг списка курсов валют:
u = urllib2.urlopen("http://www.cbr.ru/scripts/XML_daily.asp", timeout=10) parser = xml.sax.make_parser() handler = CurrencyRateHandler() parser.setContentHandler(handler) parser.parse(u) print handler.mapping
class CurrencyRateHandler(xml.sax.handler.ContentHandler): def __init__(self): self.inTag = "" self.charCode = "" self.mapping = {} def startElement(self, name, attributes): if name in set(["CharCode","Nominal", "Value"]): self.buffer = "" self.inTag = name else: self.inTag = "" def characters(self, data): if self.inTag: self.buffer += data def endElement(self,name): if name == "CharCode": self.charCode = self.buffer self.mapping[self.charCode] = {} elif name == "Nominal": self.mapping[self.charCode][self.inTag] = int(self.buffer) elif name == "Value": self.mapping[self.charCode][self.inTag] = float(self.buffer.replace(',','.')) self.inTag = ""SAX-обработчик получает события startElement и endElement при обработке открывающего и закрывающего тегов XML соответственно. Содержимое тега поступает в метод characters. Обработчик устроен достаточно просто он проверяет на соответствие имени тега с определенными шаблонами и аггрегирует данные в словарь mapping. В результате разбора получается словарь ключами, которого являются коды валют, а значениями словари, каждый из которых содержит информацию о курсе валюты и номинале обмена (1, 10 или 100 единиц). Затем нам нужно из полученного от парсера словаря отфильтровать только те валюты, которые нас интересуют и записать значения их курсов в базу. Фильтрация словаря выполняется с помощью функции filter:
update_rates(filter(lambda c: rates.has_key(c['Name']), currencies), rates)Функция update_rates выполняет запись в базу следующим образом:
def update_rates(currencies, rates): conn = get_connection() try: cur = conn.cursor() cur.executemany('INSERT INTO Currency_Exchange_Rate(Date,ListID, FromCurrency, Factor,Amount)\ VALUES(dbo.GetDay(GETDATE()),1,%d,%d,%s)', map(lambda c: (c['ID'], rates[c['Name']]['Nominal'], rates[c['Name']]['Value']), currencies)) conn.commit() finally: conn.close()самое интересное в этой функции находится в строке 6, там для формирования списка значений для команды INSERT используется функция map и лямбда-функция, возвращающая кортеж значений для вставки в базу из словаря курсов валют. Вот в общем-то и все, остаются всякие полезные мелочи вроде логгирования и отправки сообщения по электронной почте. Полученный скрипт можно поместить в /etc/cron.daily, чтобы он выполнялся ежедневно по расписанию. Для этого в заголовке нужно указать оболочке какой интерпретатор следует использовать (python конечно же):
#!/usr/bin/env python import sys import pymssql import urllib2 import xml.sax.handlerи дать файлу разрешение на выполнение:
sudo chmod 744 updater.py
Комментариев нет:
Отправить комментарий