Watir: простой парсинг сложных сайтов. Спарсить курс валют
Парсер курсов валют на PHP
Хочу поделиться с вами некоторыми наработками в области парсинга(граббинга), в данном случае речь пойдет о парсинге курсов валют. В качестве донора мы будем рассматривать сайт ЦБРФ, т.к. он всегда поддерживает актуальные данные, всегда доступен и вообще многие сайты берут информацию о курсах именно с него.
Для чего нам парсить курсы валют, думаю на этот вопрос каждый сможет ответить сам, ведь очень часто в проектах связанных с недвижимостью, финансами, банками или вообще любой другой торговой деятельностью возникает нужда представлять цены в валютах разных стран (да еще и с автоматическим конвертированием).
Я предлагаю рассмотреть два рабочих варианта, два скрипта написанных на PHP, но работающих по разному с данными в разных форматах. Тем самым не только достичь поставленной цели, а также научится парсить HTML(разбором дерева DOM) таблицы и XML потоки.
Вариант первый, DOM, таблицы.
<?php $date = date('d.m.Y'); $url="http://www.cbr.ru/currency_base/D_print.aspx?date_req=$date"; // URL страницы с курсами валют на сегодня $html = file_get_contents($url); // Читаем содержимое HTML страницы $charset = 'UTF-8'; // кодировка получаемой страницы // на данном этапе, находим на в коде блок с классом header2, и все что до него удаляем, т.к. оно нам ненужно, там содержится ненужная нам информация $pos=mb_strpos($html,'<table>', 0, $charset); // позиция $html=mb_substr($html,$pos,mb_strlen($html, $charset), $charset); // обрезаем до указанной позиции, удаляя все лишнее $dom = new domDocument; // создаем объект дерева DOM $dom->loadHTML($html); // загружаем в него спарсенную страницу $dom->preserveWhiteSpace = false; //echo $html; $tables = $dom->getElementsByTagName('table'); // получаем из дерева DOM первую таблицу, ею является как раз таблица содержащая курсы валют $rows = $tables->item(0)->getElementsByTagName('tr'); // получаем из таблицы все строки $i=0; $curs = array(); // массив который будет хранить данные foreach ($rows as $row) // беребор полученных строк { if($i==0) {$i++; continue;} // первую строку пропускаем, т.к. она содержит заголовки столбцов а не данные $cols = $row->getElementsByTagName('td'); // разбираем все строки по столбцам // записываем в полученные данные в массив, для удобного представления и работы дальше $curs[$i][0]=$cols->item(0)->nodeValue; // Цифр. код $curs[$i][1]=$cols->item(1)->nodeValue; // Букв. код $curs[$i][2]=$cols->item(2)->nodeValue; // Единиц $curs[$i][3]=$cols->item(3)->nodeValue; // Валюта $curs[$i][4]=$cols->item(4)->nodeValue; // Курс $i++; } print_r($curs);// выводим полученный массив |
Вариант второй, XML.
<?php $url = "http://www.cbr.ru/scripts/XML_daily.asp"; // URL, XML документ, всегда содержит актуальные данные $curs = array(); // массив с данными // функция полчуния даты из спарсенного XML function get_timestamp($date) { list($d, $m, $y) = explode('.', $date); return mktime(0, 0, 0, $m, $d, $y); } if(!$xml=simplexml_load_file($url)) die('Ошибка загрузки XML'); // загружаем полученный документ в дерево XML $curs['date']=get_timestamp($xml->attributes()->Date); // получаем текущую дату foreach($xml->Valute as $m){ // перебор всех значений // для примера будем получать значения курсов лишь для двух валют USD и EUR if($m->CharCode=="USD" || $m->CharCode=="EUR"){ $curs[(string)$m->CharCode]=(float)str_replace(",", ".", (string)$m->Value); // запись значений в массив } } print_r($curs); |
Вот два простых примера как можно быстро получать всегда актуальные данные курсов валют с помощью PHP, а далее уже работать с ними в своем скрипте, сохранять в базу данных и т.д.
Разумеется таким же образом можно получать и другие не менее важные данные с других сайтов доноров.
Похожие записи
rche.ru
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 | unit ZaprosRascheta; interface uses Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics, Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.ExtCtrls, Vcl.StdCtrls, Vcl.DBCtrls, Vcl.Buttons, Vcl.Mask, Vcl.ComCtrls, WinInet; type TForm_ZaprosRascheta = class(TForm) BitBtn2: TBitBtn; procedure Button2Click(Sender: TObject); private { Private declarations } public { Public declarations } end; Tvaluta = record ValutaName: String; Value: Extended; FullName: String; Nominal: Extended; end; var Form_ZaprosRascheta: TForm_ZaprosRascheta; XMLDoc: String; DateUpdate: TDate; implementation {$R *.dfm} uses DannieRascheta; function GetCursFile (const fileURL:string): string; const BufferSize = 1024; var hSession, hURL: HInternet; Buffer: array[1..BufferSize] of char; BufferLen: DWORD; sAppName: String; begin result:=''; sAppName := ExtractFileName(Application.ExeName); hSession :=InternetOpen(PChar(sAppName), INTERNET_OPEN_TYPE_PRECONFIG, nil, nil, 0); try hURL := InternetOpenURL(hSession, PChar(fileURL), nil, 0, 0, 0); try repeat InternetReadFile(hURL, @Buffer, SizeOf(Buffer), BufferLen); result:=result+Buffer; until BufferLen = 0; finally InternetCloseHandle(hURL) end finally InternetCloseHandle(hSession) end end; function CopyTextFromTeg(s:string;s1,s2:string):string; var i1,i2:integer; sm:string; begin i1:=pos(s1,s); sm:=copy(s,i1,length(s)); i2:=pos(s2,sm)+i1-1; result:=copy(s,i1+length(s1),i2-i1-length(s1)); end; function GetKursValutFromCBRF(Valuta:STring;XMLDoc:string):Tvaluta; var ValutaList:TstringList; x:integer; s:string; ValueE,nominalE:Extended; // Валюта разрядность begin ValutaList:=TstringList.Create; ValutaList.text:=XMLDoc; for X:=1 to ValutaList.count-1 do if pos('<CharCode>'+Valuta+'</CharCode>', ValutaList[x])>0 then begin s:=ValutaList[x+1]; nominalE:=StrTofloat(CopyTextFromTeg(s,'<Nominal>','</Nominal>')); s:=ValutaList[x+3]; ValueE:=StrTofloat(CopyTextFromTeg(s,'<Value>','</Value>')); result.Value:=ValueE/nominalE; result.ValutaName:=Valuta; s:=ValutaList[x+2]; result.FullName:=CopyTextFromTeg(s,'<Name>','</Name>'); result.Nominal:=nominalE; end; ValutaList.free; end; Function GetListValuta(XMLDoc:string):String; var x:integer; ValutaList:TstringList; begin ValutaList:=TstringList.Create; ValutaList.Text:=XMLDoc; result:=''; for X:=0 to ValutaList.count-1 do begin if pos('<CharCode>',ValutaList[x])>0 then result:=result+CopyTextFromTeg(ValutaList[x],'<CharCode>','</CharCode>')+#13+#10; end; ValutaList.free; end; function GetUrlCBRF(Date: TDate):string; begin result:='http://www.cbr.ru/scripts/XML_daily.asp?date_req='+FormatDateTime('DD.MM.YYYY',date); end; procedure TForm_ZaprosRascheta.INSERT_ZaprosRascheta_Table; var ValUSD, ValEUR, ValKZT, ValRUB: String; begin ValUSD := 'USD'; ValEUR := 'EUR'; ValKZT := 'KZT'; ValRUB := '1'; if DateUpdate <> DateTimePicker1.Date then begin Form_DannieRascheta.GroupBox2.Caption := ' Курс валюты, на '+DateToStr(DateTimePicker1.Date)+' '; XMLDoc:=GetCursFile(GetUrlCBRF(DateTimePicker1.Date)); Form_DannieRascheta.panel28.Caption := FloatToStr(GetKursValutFromCBRF(ValUSD,XMLDoc).Value); Form_DannieRascheta.panel29.Caption := FloatToStr(GetKursValutFromCBRF(ValEUR,XMLDoc).Value); Form_DannieRascheta.panel30.Caption := FloatToStr(GetKursValutFromCBRF(ValKZT,XMLDoc).Value); Form_DannieRascheta.panel31.Caption := ValRUB; DateUpdate := DateTimePicker1.Date; ValUSD := GetListValuta(XMLDoc); ValEUR := GetListValuta(XMLDoc); ValKZT := GetListValuta(XMLDoc); end; end; end. |
forundex.ru
Парсер курса валют на PHP
Главная > PHP > Парсер курса валют на PHPПарсер курса валют на PHP
Приветствую! После небольшого перерыва, продолжаю публиковать статьи для начинающих PHP программистов. На этот раз решил поделиться решением распространенной задачи — отображение текущего курса валют на сайте.
С начала, как обычно, постановка задачи:Нам нужно отображать текущий курс доллара и евро относительно рубля, а также разницу между текущем курсом и вчерашним. Для простоты интеграции скрипта с различными сайтами, сделаем его без использования баз данных, курсы валют будут храниться в файле.
Реализация:Получать текущий курс валюты будем с сайта ЦБРФ. Курс доступен в XML формате по адресу http://www.cbr.ru/scripts/XML_daily.asp. Для парсинга данных воспользуемся расширением PHP под названием SimpleXML (посмотрите phpinfo(), чтобы узнать установлено он или нет).
Стоит отметить, что XML на сайте центробанка обновляется раз в день, с понедельника по пятницу.
Алгоритм работы следующий: Читаем файл с данными. Если данные актуальны, то выводим информацию пользователю. В противном случае парсим XML с сайта ЦБРФ, сохраняем данные в файл и выводим пользователю. Данные в файле будем хранить в сериализованом виде, причем текущий курс и курс за прошедший день (для того чтобы показывать разницу).
Теперь можно написать сам класс для парсинга куса валют:
-
class curs
-
{
-
const REFRESH_INTERVAL=3600;
-
private $dataFile;
-
private $source = "http://www.cbr.ru/scripts/XML_daily.asp";
-
private $refreshTime;
-
public $cursNew;
-
public $cursOld;
-
-
private $error;
-
-
public function __construct($dataFile)
-
{
-
$this->dataFile=$dataFile;
-
-
if(!$f=fopen($this->dataFile, "r")) {
-
$this->refresh();
-
$this->error=true;
-
return false;
-
}
-
$data=fread($f, filesize($this->dataFile));
-
fclose($f);
-
$data=unserialize($data);
-
$this->refreshTime=$data['refresh_time'];
-
$this->cursNew=$data['curs']['new'];
-
$this->cursOld=$data['curs']['old'];
-
$this->refresh();
-
}
-
-
public function save()
-
{
-
$data=array(
-
"refresh_time"=>$this->refreshTime,
-
"curs" => array(
-
"new"=>$this->cursNew,
-
"old"=>$this->cursOld
-
)
-
);
-
-
-
if(!$f=fopen($this->dataFile, "w+")) return false;
-
fwrite($f, serialize($data));
-
fclose($f);
-
}
-
-
public function refresh()
-
{
-
if((time()-self::REFRESH_INTERVAL)<$this->refreshTime) return true;
-
-
if(isset($this->cursNew['date']) && $this->cursNew['date']>=$this->get_timestamp(date("d.m.y"))) return true;
-
-
$new_data=$this->readFromCbr();
-
$this->refreshTime=time();
-
if(is_array($new_data)){
-
if($new_data['date']>$this->cursNew['date']){
-
$this->cursOld=$this->cursNew;
-
$this->cursNew=$new_data;
-
$this->save();
-
} else {
-
return true;
-
}
-
} else {
-
return false;
-
}
-
}
-
-
private function readFromCbr()
-
{
-
if(!$xml=simplexml_load_file($this->source)) return false;
-
$curs['date']=self::get_timestamp($xml->attributes()->Date);
-
foreach($xml->Valute as $m){
-
if($m->CharCode=="USD" || $m->CharCode=="EUR"){
-
$curs[(string)$m->CharCode]=(float)str_replace(",", ".", (string)$m->Value);
-
}
-
}
-
return $curs;
-
}
-
-
public static function get_timestamp($date)
-
{
-
list($d, $m, $y) = explode('.', $date);
-
return mktime(0, 0, 0, $m, $d, $y);
-
}
-
}
Немного о том как пользоваться классом. Конструктор принимает один параметр — путь к файлу, в котором будут хранится данные парсинга валют (файл должен быть доступен для записи).
-
$curs=new curs('./cursData.txt'); //Задаем файл для хранения данных
-
$curs->cursNew["date"]; //Актуальая дата курса
-
$curs->cursNew["USD"]; //Курс евро текущий
-
$curs->cursNew["EUR"]; //Курс доллара текущий
-
$curs->cursOld["USD"]; //Курс евро вчерашний
-
$curs->cursOld["EUR"]; //Курс доллара вчерашний
Скачать пример можно здесь
www.sterehov.ru
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 | unit ZaprosRascheta; interface uses Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics, Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.ExtCtrls, Vcl.StdCtrls, Vcl.DBCtrls, Vcl.Buttons, Vcl.Mask, Vcl.ComCtrls, WinInet; type TForm_ZaprosRascheta = class(TForm) BitBtn2: TBitBtn; procedure Button2Click(Sender: TObject); private { Private declarations } public { Public declarations } end; Tvaluta = record ValutaName: String; Value: Extended; FullName: String; Nominal: Extended; end; var Form_ZaprosRascheta: TForm_ZaprosRascheta; XMLDoc: String; DateUpdate: TDate; implementation {$R *.dfm} uses DannieRascheta; function GetCursFile (const fileURL:string): string; const BufferSize = 1024; var hSession, hURL: HInternet; Buffer: array[1..BufferSize] of char; BufferLen: DWORD; sAppName: String; begin result:=''; sAppName := ExtractFileName(Application.ExeName); hSession :=InternetOpen(PChar(sAppName), INTERNET_OPEN_TYPE_PRECONFIG, nil, nil, 0); try hURL := InternetOpenURL(hSession, PChar(fileURL), nil, 0, 0, 0); try repeat InternetReadFile(hURL, @Buffer, SizeOf(Buffer), BufferLen); result:=result+Buffer; until BufferLen = 0; finally InternetCloseHandle(hURL) end finally InternetCloseHandle(hSession) end end; function CopyTextFromTeg(s:string;s1,s2:string):string; var i1,i2:integer; sm:string; begin i1:=pos(s1,s); sm:=copy(s,i1,length(s)); i2:=pos(s2,sm)+i1-1; result:=copy(s,i1+length(s1),i2-i1-length(s1)); end; function GetKursValutFromCBRF(Valuta:STring;XMLDoc:string):Tvaluta; var ValutaList:TstringList; x:integer; s:string; ValueE,nominalE:Extended; // Валюта разрядность begin ValutaList:=TstringList.Create; ValutaList.text:=XMLDoc; for X:=1 to ValutaList.count-1 do if pos('<CharCode>'+Valuta+'</CharCode>', ValutaList[x])>0 then begin s:=ValutaList[x+1]; nominalE:=StrTofloat(CopyTextFromTeg(s,'<Nominal>','</Nominal>')); s:=ValutaList[x+3]; ValueE:=StrTofloat(CopyTextFromTeg(s,'<Value>','</Value>')); result.Value:=ValueE/nominalE; result.ValutaName:=Valuta; s:=ValutaList[x+2]; result.FullName:=CopyTextFromTeg(s,'<Name>','</Name>'); result.Nominal:=nominalE; end; ValutaList.free; end; Function GetListValuta(XMLDoc:string):String; var x:integer; ValutaList:TstringList; begin ValutaList:=TstringList.Create; ValutaList.Text:=XMLDoc; result:=''; for X:=0 to ValutaList.count-1 do begin if pos('<CharCode>',ValutaList[x])>0 then result:=result+CopyTextFromTeg(ValutaList[x],'<CharCode>','</CharCode>')+#13+#10; end; ValutaList.free; end; function GetUrlCBRF(Date: TDate):string; begin result:='http://www.cbr.ru/scripts/XML_daily.asp?date_req='+FormatDateTime('DD.MM.YYYY',date); end; procedure TForm_ZaprosRascheta.INSERT_ZaprosRascheta_Table; var ValUSD, ValEUR, ValKZT, ValRUB: String; begin ValUSD := 'USD'; ValEUR := 'EUR'; ValKZT := 'KZT'; ValRUB := '1'; if DateUpdate <> DateTimePicker1.Date then begin Form_DannieRascheta.GroupBox2.Caption := ' Курс валюты, на '+DateToStr(DateTimePicker1.Date)+' '; XMLDoc:=GetCursFile(GetUrlCBRF(DateTimePicker1.Date)); Form_DannieRascheta.panel28.Caption := FloatToStr(GetKursValutFromCBRF(ValUSD,XMLDoc).Value); Form_DannieRascheta.panel29.Caption := FloatToStr(GetKursValutFromCBRF(ValEUR,XMLDoc).Value); Form_DannieRascheta.panel30.Caption := FloatToStr(GetKursValutFromCBRF(ValKZT,XMLDoc).Value); Form_DannieRascheta.panel31.Caption := ValRUB; DateUpdate := DateTimePicker1.Date; ValUSD := GetListValuta(XMLDoc); ValEUR := GetListValuta(XMLDoc); ValKZT := GetListValuta(XMLDoc); end; end; end. |
forundex.ru
простой парсинг сложных сайтов / Хабр
Каждый, кто пишет парсеры, знает, что можно распарсить сто сайтов, а на сто-первом застрять на несколько дней. Структура очередного отмороженного сайта может быть сколь угодно сложной, и, когда дело касается сжатых javascript-ов и ajax-запросов, расшифровать их и извлечь информацию с помощью обычного curl-а и регекспов становится дороже самой информации.Грубо говоря, проблема в том, что в браузере работает javascript, а на сервере его нет. Нужно либо писать интерпретатор js на одном из серверных языков (jParser и jTokenizer), либо ставить на сервер браузер, посылать в него запросы и вытаскивать итоговое dom-дерево.
В древности в таких случаях мы строили свой велосипед: на отдельной машине запускали браузер, в нем js, который постоянно стучался на сервер и получал от него задания (джобы), сам сайт грузился в iframe, а скрипт извне отправлял dom-дерево ифрейма обратно на сервер.
Сейчас появились более продвинутые средства — xulrunner (crowbar) и watir. Первый — безголовый firefox. У crowbar есть даже ff-плагин для визуального выделения нужных данных, который генерит специальный парсер-js-код, однако там не поддерживаются cookies, а допиливать неохота. Watir позиционируется разработчиками как средство отладки, но мы будем его использовать по прямому назначению и в качестве примера вытащим какие-нибудь данные с сайта travelocity.com.
Watir — это ruby gem, через который идет взаимодействие с браузером. Есть версии для разных платформ — watir, firewatir и safariwatir. Несмотря на подробный мануал по установке, у меня возникли проблемы как в винде, так и в убунте. В windows (ie6) watir не работает на ruby 1.9.1. Пришлось поставить версию 1.8.6, тогда заработало. В убунте — для того, чтобы работал FireWatir (или обычный watir через firefox), в браузер нужно поставить плагин jssh. Но версия, предлагаемая для FireWatir на странице установки не заработала с моим FireFox 3.6 на Ubuntu 10.04.
Чтобы проверить, работает у вас jssh или нет, нужно запустить firefox -jssh, а потом послать что-нибудь на 9997 порт (telnet localhost 9997). Если порт не открывается, либо происходит аварийное завершение работы firefox (как у меня), значит нужно собрать свой jssh, подробная инструкция о сборке находится здесь.
Начнем писать парсер отелей с travelocity.com. Для примера выберем цены комнат во всех отелях по направлению New York, NY, USA на сегодня. Будем работать с FireWatir на Ubuntu 10.4.
Запускаем браузер и грузим страницу с формой:
require "rubygems"<br>require "firewatir"<br>ff = FireWatir::Firefox.new<br>ff.goto("http://www.travelocity.com/Hotels")<br> Заполняем форму нужными значениями и делаем submit:
ff.text_field(:id,"HO_to").val("New York, NY, USA")<br>ff.text_field(:id,"HO_fromdate").val(Time.now.strftime("%m/%d/%Y"))<br>ff.text_field(:id,"HO_todate").val(Time.tomorrow.strftime("%m/%d/%Y"))<br>ff.form(:name,"formHO").submit<br> Ждем окончания загрузки:
ff.wait_until{ff.div(:id,"resultsList").div(:class,"module").exists?}<br> wait_until — очень важная инструкция. При сабмите формы на сайте делается несколько редиректов, а после — ajax запрос. Нужно дождаться финальной загрузки страницы, и только ПОСЛЕ этого работать с dom-деревом. Как узнать, что страница загрузилась? Нужно посмотреть, какие элементы появляются на странице после выполнения ajax. В нашем случае после запроса к /pub/gwt/hotel/esf/hotelresultlist.gwt-rpc в resultsPage появляется несколько элементов <div>. Ждем, пока они не появятся. Замечу, что некоторые команды, например text_field, submit, уже включают в себя wait_until, поэтому перед ними данная команда не нужна.
Теперь делаем переход по страницам:
while true do<br> ff.wait_until{ff.div(:id,"resultsList").div(:class,"module").exists?}<br> ...<br> next_link = ff.div(:id,"resultcontrol-top").link(:text,"Next")<br> if (next_link.exists?) then next_link.click else break end<br>end<br> Там, где в коде стоит многоточие, находится непосредственное вытаскивание данных. Возникает искушение применить watir и в этом случае, к примеру, пробежать по всем дивам в resultsList такой командой:
ff.div(:id,"resultsList").divs.each.do |div|<br> if (div.class_name != "module") then next end<br> ...<br>end<br> И из каждого дива вытащить название отеля и цену:
m = div.h3(:class,"property-name").html.match(/propertyId=(\d+)[^<>]*>([^<>]*)<\/a[^<>]*>/)<br>data["id"] = m[1] unless m.nil?<br>data["name"] = m[2] unless m.nil?<br>data["price"] = div.h4(:class,"price").text<br> Но так делать не следует. Каждая команда watir-а к элементам dom-дерева — это лишний запрос к браузеру. У меня работает около секунды. Гораздо эффективнее за ту же секунду за раз выдернуть весь dom и мгновенно распарсить обычными регулярками:
ff.div(:id,"resultsList").html.split(/<div[^<>]*class\s*=\s*["']?module["']?[^<>]*>/).each do |str|<br>m = str.match(/<a[^<>]*propertyId=(\d+)[^<>]*>([\s\S]*?)<\/a[^<>]*>/)<br> data["id"] = m[1] unless m.nil?<br> data["name"] = m[2] unless m.nil?<br> m = str.match(/<h4[^<>]*class\s*=\s*["']?price["']?[^<>]*>([\s\S]*?)<\/h4[^<>]*>/)<br> data["price"] = m[1] unless m.nil?<br>end<br> Советую применять watir только там, где это необходимо. Заполнение и сабмит форм, ожидание, пока браузер не выполнит js код, и затем — получение финального html-кода. Да, доступ к значениям элементов через watir кажется надежнее, чем парсинг потока кода без dom-структуры. Чтобы вытащить внутренность некоторого дива, внутри которого могут быть другие дивы, нужно написать сложночитаемое регулярное выражение. Но все равно это гораздо быстрее. Если таких дивов много, самое простое решение — несложной рекурсивной функцией разбить весь код по уровням вложенности тегов. Я писал такую штуку в одном своем классе на php.
habr.com
Решение: Спарсить курс валюты с сайта, обновляемый скриптом
Формулировка задачи:
Необходимо средствами C# спарсить курс валюты (Текущая цена) с сайта https://www.bancor.network/bnt, которого нет в коде страницы. Насколько я понял оно подгружается с помощью javascriptа. В отладчике хрома вроде нашел нужный скрипт (bnt.js). И даже переменную, содержащую нужную цифру, но вытащить в visual studio не могу( Как это сделать?
Узнать стоимость выполнения Вашей работы
Код к задаче: «Спарсить курс валюты с сайта, обновляемый скриптом - C#»
textual {"data":{"rate":"0.01014"}}Вы всегда можете заказать любую учебную работу у наших авторов от 20 руб.
Заказать
СДЕЛАЙТЕ РЕПОСТ
studassistent.ru
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 | unit ZaprosRascheta; interface uses Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics, Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.ExtCtrls, Vcl.StdCtrls, Vcl.DBCtrls, Vcl.Buttons, Vcl.Mask, Vcl.ComCtrls, WinInet; type TForm_ZaprosRascheta = class(TForm) BitBtn2: TBitBtn; procedure Button2Click(Sender: TObject); private { Private declarations } public { Public declarations } end; Tvaluta = record ValutaName: String; Value: Extended; FullName: String; Nominal: Extended; end; var Form_ZaprosRascheta: TForm_ZaprosRascheta; XMLDoc: String; DateUpdate: TDate; implementation {$R *.dfm} uses DannieRascheta; function GetCursFile (const fileURL:string): string; const BufferSize = 1024; var hSession, hURL: HInternet; Buffer: array[1..BufferSize] of char; BufferLen: DWORD; sAppName: String; begin result:=''; sAppName := ExtractFileName(Application.ExeName); hSession :=InternetOpen(PChar(sAppName), INTERNET_OPEN_TYPE_PRECONFIG, nil, nil, 0); try hURL := InternetOpenURL(hSession, PChar(fileURL), nil, 0, 0, 0); try repeat InternetReadFile(hURL, @Buffer, SizeOf(Buffer), BufferLen); result:=result+Buffer; until BufferLen = 0; finally InternetCloseHandle(hURL) end finally InternetCloseHandle(hSession) end end; function CopyTextFromTeg(s:string;s1,s2:string):string; var i1,i2:integer; sm:string; begin i1:=pos(s1,s); sm:=copy(s,i1,length(s)); i2:=pos(s2,sm)+i1-1; result:=copy(s,i1+length(s1),i2-i1-length(s1)); end; function GetKursValutFromCBRF(Valuta:STring;XMLDoc:string):Tvaluta; var ValutaList:TstringList; x:integer; s:string; ValueE,nominalE:Extended; // Валюта разрядность begin ValutaList:=TstringList.Create; ValutaList.text:=XMLDoc; for X:=1 to ValutaList.count-1 do if pos('<CharCode>'+Valuta+'</CharCode>', ValutaList[x])>0 then begin s:=ValutaList[x+1]; nominalE:=StrTofloat(CopyTextFromTeg(s,'<Nominal>','</Nominal>')); s:=ValutaList[x+3]; ValueE:=StrTofloat(CopyTextFromTeg(s,'<Value>','</Value>')); result.Value:=ValueE/nominalE; result.ValutaName:=Valuta; s:=ValutaList[x+2]; result.FullName:=CopyTextFromTeg(s,'<Name>','</Name>'); result.Nominal:=nominalE; end; ValutaList.free; end; Function GetListValuta(XMLDoc:string):String; var x:integer; ValutaList:TstringList; begin ValutaList:=TstringList.Create; ValutaList.Text:=XMLDoc; result:=''; for X:=0 to ValutaList.count-1 do begin if pos('<CharCode>',ValutaList[x])>0 then result:=result+CopyTextFromTeg(ValutaList[x],'<CharCode>','</CharCode>')+#13+#10; end; ValutaList.free; end; function GetUrlCBRF(Date: TDate):string; begin result:='http://www.cbr.ru/scripts/XML_daily.asp?date_req='+FormatDateTime('DD.MM.YYYY',date); end; procedure TForm_ZaprosRascheta.INSERT_ZaprosRascheta_Table; var ValUSD, ValEUR, ValKZT, ValRUB: String; begin ValUSD := 'USD'; ValEUR := 'EUR'; ValKZT := 'KZT'; ValRUB := '1'; if DateUpdate <> DateTimePicker1.Date then begin Form_DannieRascheta.GroupBox2.Caption := ' Курс валюты, на '+DateToStr(DateTimePicker1.Date)+' '; XMLDoc:=GetCursFile(GetUrlCBRF(DateTimePicker1.Date)); Form_DannieRascheta.panel28.Caption := FloatToStr(GetKursValutFromCBRF(ValUSD,XMLDoc).Value); Form_DannieRascheta.panel29.Caption := FloatToStr(GetKursValutFromCBRF(ValEUR,XMLDoc).Value); Form_DannieRascheta.panel30.Caption := FloatToStr(GetKursValutFromCBRF(ValKZT,XMLDoc).Value); Form_DannieRascheta.panel31.Caption := ValRUB; DateUpdate := DateTimePicker1.Date; ValUSD := GetListValuta(XMLDoc); ValEUR := GetListValuta(XMLDoc); ValKZT := GetListValuta(XMLDoc); end; end; end. |
forundex.ru