Загрузка курсов валют с сайта НБРБ

Материал из GedeminWiki
(Различия между версиями)
Перейти к: навигация, поиск
(Содержимое страницы заменено на « * Загрузка курсов валют с сайта НБРБ (XML) * [[Загрузка курсов валют с сай…»)
 
(не показана 1 промежуточная версия 1 участника)
Строка 1: Строка 1:
=== Вариант с XML ===
 
  
Предложено Леонидом Агафоновым. Предпочтительно использовать именно этот вариант, так как он не зависит визуального оформления, структуры HTML страницы.
+
* [[Загрузка курсов валют с сайта НБРБ (XML)]]
 
+
* [[Загрузка курсов валют с сайта НБРБ (HTML)]]
<source lang="vbnet">
+
sub ImportCurrRate_XML
+
 
+
Set Creator = New TCreator
+
Set CurrCode = CreateObject("Scripting.Dictionary")
+
CurrCode.Add "USD", "USD"
+
CurrCode.Add "EUR", "EUR"
+
CurrCode.Add "RUB", "RUB"
+
CurrCode.Add "PLN", "PLN"
+
 
+
BaseCurrID = gdcBaseManager.GetIDByRUIDString("200010_17")
+
 
+
Set Transaction = Creator.GetObject(null, "TIBTransaction", "")
+
Set Transaction.DefaultDatabase = gdcBaseManager.Database
+
 
+
Set ibsql = Creator.GetObject(null, "TIBSQL", "")
+
Set ibsql.Transaction = Transaction
+
Set ibsqlFind = Creator.GetObject(null, "TIBSQL", "")
+
Set ibsqlFind.Transaction = Transaction
+
 
+
Transaction.StartTransaction
+
 
+
ibsql.SQL.Text =_
+
  "SELECT COUNT(c.code) as CountCode " &_
+
  "FROM gd_curr c  " &_
+
  "WHERE c.SHORTNAME = :C "
+
 
+
For Each I in CurrCode
+
  ibsql.ParamByName("C").AsString = CurrCode.Item(I)
+
  ibsql.ExecQuery
+
  if ibsql.FieldByName("CountCode").AsInteger <> 1 then _
+
    CurrCode.Remove(I)
+
  ibsql.Close
+
Next
+
 
+
FromDate = Date + 1
+
ToDate = Date + 1
+
 
+
ibsql.SQL.Text =_
+
  "SELECT MAX(r.fordate) as MaxForDate " &_
+
  "FROM gd_currrate r JOIN gd_curr c ON r.fromcurr = c.id " &_
+
  "WHERE c.SHORTNAME = :FromCurr and r.tocurr = :ToCurr"
+
ibsql.ParamByName("ToCurr").AsInteger = BaseCurrID
+
 
+
For Each I in CurrCode
+
  ibsql.ParamByName("FromCurr").AsString = CurrCode.Item(I)
+
  ibsql.ExecQuery
+
  if ibsql.FieldByName("MaxForDate").AsDateTime < FromDate then _
+
    FromDate = ibsql.FieldByName("MaxForDate").AsDateTime
+
  ibsql.Close
+
Next
+
if FromDate <= CDate("01.01.2004") then _
+
  FromDate = CDate("01.01.2004")
+
 
+
if ToDate < FromDate then _
+
  exit sub
+
 
+
ibsql.SQL.Text = _
+
  "INSERT INTO gd_currrate (fromcurr, tocurr, fordate, coeff) " &_
+
  "SELECT ID, :TC, :FD, :R FROM gd_curr WHERE SHORTNAME = :FC "
+
ibsql.ParamByName("TC").AsInteger = BaseCurrID
+
 
+
ibsqlFind.SQL.Text =_
+
  "SELECT * " &_
+
  "FROM gd_currrate r JOIN gd_curr c ON r.fromcurr = c.id " &_
+
  "WHERE c.SHORTNAME = :FC and r.tocurr = :TC AND r.fordate = :FD"
+
ibsqlFind.ParamByName("TC").AsInteger = BaseCurrID
+
 
+
Set oXML = CreateObject("MSXML.DomDocument")
+
oXML.async = False
+
 
+
For D = FromDate to ToDate Step 1
+
  ibsqlFind.Close
+
  ibsqlFind.ParamByName("FD").AsDateTime = D
+
 
+
  ibsql.ParamByName("FD").AsDateTime = D
+
 
+
  On Error Resume Next
+
    oXML.Load ("http://www.nbrb.by/Services/XmlExRates.aspx?ondate=" &_
+
      Month(D) & "/" & Day(D) & "/" & Year(D))
+
 
+
    For Each I in CurrCode
+
 
+
      ibsqlFind.ParamByName("FC").AsString = CurrCode.Item(I)
+
      ibsqlFind.ExecQuery
+
      if ibsqlFind.EOF then
+
 
+
        On Error Resume Next
+
          ibsql.Close
+
          ibsql.ParamByName("R").AsCurrency = _
+
            CDbl(Replace(oXML.selectSingleNode("//Currency[CharCode='" & I & _
+
            "']/Rate").Text, ".", Application.DecimalSeparatorSys))
+
          ibsql.ParamByName("FC").AsString = CurrCode.Item(I)
+
          if Err.Number = 0 then
+
            ibsql.ExecQuery
+
            ibsql.Close
+
          end if
+
        On Error GoTo 0
+
      end if
+
      ibsqlFind.Close
+
    Next
+
  Transaction.CommitRetaining
+
  On Error GoTo 0
+
Next
+
 
+
Transaction.Commit
+
end sub
+
</source>
+
 
+
=== Вариант с "ручным" разбором HTML документа ===
+
 
+
<source lang="vbnet">
+
option explicit
+
 
+
' системные требования: Windows XP SP1, Windows 2000 SP3
+
' Windows 2003 Server
+
'
+
sub Curr_LoadRates
+
 
+
  Dim Creator
+
  Set Creator = New TCreator
+
 
+
  ' словарь CurrCode нужен нам для двух целей:
+
  ' во-первых, в нем задается список валют, курсы
+
  ' которых мы будем загружать с сайта
+
  ' во-вторых, в нем мы устанавливаем соответствие
+
  ' между кодом (буквенной аббревиатурой) валюты
+
  ' используемой на сайте (Key) и кодом валюты
+
  ' используемым в нашей базе данных (Item). Очевидно,
+
  ' что они могут как совпадать, так и различаться
+
  ' например, доллар США на сайте может обозначаться
+
  ' как USD, а у нас в базе он будет проходить как
+
  ' USD NBRB, что означает курс доллара США, установленный
+
  ' Национальным банком Республики Беларусь.
+
  ' Обратите внимание, что коды валют могут меняться во времени
+
  ' например в одно время сайт может вернуть курс польского злотого
+
  ' под кодом PLZ, а в другое -- PLN
+
  ' в таком случае, все коды одной и той же валюты, которые
+
  ' могут использоваться на сайте, должны быть перечислены
+
  ' через запятую
+
  Dim CurrCode
+
  Set CurrCode = CreateObject("Scripting.Dictionary")
+
  CurrCode.Add "USD", "USD"
+
  CurrCode.Add "EUR", "EUR"
+
  CurrCode.Add "RUB,RUR", "RUB"
+
  CurrCode.Add "PLN,PLZ", "PLN"
+
  CurrCode.Add "UAH", "UAH"
+
  CurrCode.Add "LTL", "LTL"
+
  CurrCode.Add "LVL", "LVL"
+
  CurrCode.Add "GBP", "GBP"
+
 
+
  ' идентификатор записи валюты, относительно которой
+
  ' задаются курсы валют на сайте
+
  ' в данном случае -- это наш родной белорусский рубль
+
  Dim BaseCurrID
+
  BaseCurrID = gdcBaseManager.GetIDByRUIDString("200010_17")
+
 
+
  ' даты: с какой и по какую загружать курсы валют с сайта
+
  ' по какую -- возьмем текущую системную дату
+
  ' с какой -- определим следующим образом: будем искать в нашей
+
  ' базе для каждой из заданных валют самую последнюю
+
  ' дату курса. из всех найденных дат возьмем наиболее раньнюю.
+
  Dim FromDate, ToDate
+
  ToDate = Date
+
  FromDate = ToDate
+
 
+
  Dim q, qFind, Tr
+
  Set Tr = Creator.GetObject(Application, "TIBTransaction", "")
+
  Set q = Creator.GetObject(Application, "TIBSQL", "")
+
  Set qFind = Creator.GetObject(Application, "TIBSQL", "")
+
 
+
  Set Tr.DefaultDatabase = gdcBaseManager.Database
+
  Set q.Transaction = Tr
+
  Set qFind.Transaction = Tr
+
 
+
  Tr.StartTransaction
+
 
+
  ' уберем коды валют которых нет нашей базе или
+
  ' которые встречаются более одного раза
+
  q.SQL.Text =_
+
    "SELECT COUNT(c.code) " &_
+
    "FROM gd_curr c  " &_
+
    "WHERE c.code = :C "
+
 
+
  Dim I
+
  For Each I in CurrCode
+
    q.ParamByName("C").AsString = CurrCode.Item(I)
+
    q.ExecQuery
+
    if q.Fields(0).AsInteger <> 1 then _
+
      CurrCode.Remove(I)
+
    q.Close
+
  Next
+
 
+
  q.SQL.Text =_
+
    "SELECT MAX(r.fordate) " &_
+
    "FROM gd_currrate r JOIN gd_curr c ON r.fromcurr = c.id " &_
+
    "WHERE c.code = :FC and r.tocurr = :TC"
+
  q.ParamByName("TC").AsInteger = BaseCurrID
+
 
+
  For Each I in CurrCode
+
    q.ParamByName("FC").AsString = CurrCode.Item(I)
+
    q.ExecQuery
+
    if Int(q.Fields(0).AsDateTime) < FromDate then _
+
      FromDate = Int(q.Fields(0).AsDateTime)
+
    q.Close
+
  Next
+
 
+
  ' проверим, может в базе уже есть все курсы
+
  if ToDate < FromDate then _
+
    exit sub
+
 
+
  ' если интервал слишком большой -- ограничим его
+
  if (ToDate - FromDate) > (365 * 1) then _
+
    FromDate = ToDate - 365 * 1
+
 
+
  ' подготовим запрос для вставки курса валюты
+
  q.SQL.Text = _
+
    "INSERT INTO gd_currrate (fromcurr, tocurr, fordate, coeff) " &_
+
    "SELECT ID, :TC, :FD, :R FROM gd_curr WHERE code = :FC "
+
  q.ParamByName("TC").AsInteger = BaseCurrID
+
 
+
  ' подготовим запрос для поиска курса валюты на указанную дату
+
  qFind.SQL.Text =_
+
    "SELECT * " &_
+
    "FROM gd_currrate r JOIN gd_curr c ON r.fromcurr = c.id " &_
+
    "WHERE c.code = :FC and r.tocurr = :TC AND r.fordate = :FD"
+
  qFind.ParamByName("TC").AsInteger = BaseCurrID
+
 
+
  Dim strResult
+
  Dim WinHttpReq
+
  Dim strURL
+
 
+
  ' если объект не удается создать (например, неподходящая
+
  ' версия Windows), то просто завершаем выполнение
+
  On Error Resume Next
+
  Set WinHttpReq = CreateObject("WinHttp.WinHttpRequest.5.1")
+
  if Err.Number <> 0 then _
+
    Exit Sub
+
  On Error GoTo 0
+
 
+
  ' если используется прокси для выхода в интернет
+
  ' откоментируйте следующую строку и укажите адрес прокси
+
  ' последний параметр, указывает адреса, к которым подключение
+
  ' будет происходить минуя прокси
+
  ' WinHttpReq.SetProxy 2, "proxy_server:80", "*.domain.com"
+
 
+
  Dim D, K, J, E, SS, Mo, Da, Arr, A
+
  For D = FromDate to ToDate Step 1
+
    qFind.Close
+
    qFind.ParamByName("FD").AsDateTime = D
+
 
+
    q.ParamByName("FD").AsDateTime = D
+
 
+
    if Month(D) < 10 then
+
      Mo = "0" & Month(D)
+
    else
+
      Mo = Month(D)
+
    end if
+
 
+
    if Day(D) < 10 then
+
      Da = "0" & Day(D)
+
    else
+
      Da = Day(D)
+
    end if
+
 
+
    strURL = "http://www.nbrb.by/statistics/rates/RatesDaily.asp?fromDate=" &_
+
      Year(D) & "-" & Mo & "-" & Da
+
   
+
    ' в случае если сайт не доступен -- просто
+
    ' заверши процедуру
+
    On Error Resume Next
+
 
+
    WinHttpReq.Open "GET", strURL, false
+
    WinHttpReq.Send
+
    strResult = WinHttpReq.ResponseText
+
   
+
    if Err.Number <> 0 then _
+
      Exit Sub
+
   
+
    On Error GoTo 0
+
 
+
    For Each I in CurrCode
+
      ' для каждой валюты проверим: нет ли в базе курса на
+
      ' указанную дату. если есть, то пропускаем эту валюту
+
      qFind.ParamByName("FC").AsString = CurrCode.Item(I)
+
      qFind.ExecQuery
+
     
+
      if qFind.EOF then
+
        Arr = Split(I, ",")
+
     
+
        For Each A in Arr
+
          K = InStr(strResult, ">" & A & "</td>")
+
         
+
          if K > 0 then
+
            For J = 1 to 4
+
              K = InStr(K + 1, strResult, ">")
+
              if K = 0 then _
+
                Exit For
+
            Next
+
           
+
            if K > 0 then
+
              K = K + 1
+
              E = InStr(K, strResult, "<")
+
 
+
              if E > 0 then
+
                SS = Replace(Mid(strResult, K, E - K), "&nbsp;", "")
+
                SS = Replace(SS, " ", "")
+
                SS = Replace(SS, Chr(160), "")
+
 
+
                ' на сайте используется точка в качестве десятичного
+
                ' разделителя. Заменим ее на разделитель, использующийся в нашей
+
                ' системе
+
                SS = Replace(SS, ".", Application.DecimalSeparatorSys)
+
 
+
                if SS > "" then
+
                  ' в случае если строку не удается перевести в число
+
                  ' или возникнет ошибка при добавлении записи --
+
                  ' проигнорируем их
+
                  On Error Resume Next
+
               
+
                  q.ParamByName("R").AsCurrency = CCur(SS)
+
                  q.ParamByName("FC").AsString = CurrCode.Item(I)
+
                 
+
                  if Err.Number = 0 then _
+
                    q.ExecQuery
+
                 
+
                  On Error GoTo 0
+
                end if
+
              end if
+
            end if
+
          end if
+
        Next
+
      end if
+
 
+
      qFind.Close
+
    Next
+
 
+
  Next
+
 
+
  ' подтверждаем запись в базу данных, только если все прошло успешно
+
  ' и не возникало ошибок
+
  Tr.Commit
+
 
+
end sub
+
</source>
+
 
+
[[Category:Учебный курс]]
+

Текущая версия на 13:39, 25 января 2017

Персональные инструменты
Пространства имён

Варианты
Действия
Навигация
Инструменты