Добрый день коллеги.
Сегодня мы отвлечемся немного от OTL и поговорим о духовном – поговорим о кино, вернее о сайте kinopoisk.ru и поиске описаний фильмов. К сожалению кинопоиск не предполагает никого API для поиска и получения информации о фильмах и что сразу приходит на ум это парсирование страниц и вытаскивание из них нужной нам информации, что возможно но довольно таки трудоемко.
Однако не все потеряно, и поиск в интернете меня привел на следующую страничкугде один энтузиаст, написав серверную часть по выдаче информации о фильмах, описывает соответствующее API данной серверной части с помощью которой можно более просто получать информацию о фильмах без парсирования страниц кинопоиска.
По мотивам этого родился этот пост.
Итак, поиск фильмов осуществляется по ссылке
http://kinopoiskinfo.appspot.com/?action=list&format=json&title=Название, где вместо "Название" указать свою строку поиска фильма.
Информация приходит в виде строки (JSON-объектов) на примере фильма “Край”:
{"status": 200, "list":
[
{"год": "2010", "сериал": false, "название": "Край", "id": 460432, "оригинал": "Kray"},
{"год": "2010", "сериал": false, "название": "Край", "id": 495724, "оригинал": "Edge"},
{"год": "2010", "сериал": false, "название": "Край", "id": 497088, "оригинал": "La lisière"},
{"год": "2008", "сериал": false, "название": "Фар Край", "id": 197147, "оригинал": "Far Cry"},
{"год": "2006", "сериал": false, "название": "Дикари", "id": 271513, "оригинал": "Dikari"},
{"год": "2004", "сериал": false, "название": "Птицы 2: Путешествие на край света", "id": 94151, "оригинал": "La marche de l'empereur"}
]
}
После чего получив ID фильма можно запросить информацию по фильму
Информация придет также в виде JSON:
"status": 200,
"film":
{"rating":
{"kinopoisk":
{"count": 5083, "value": 6.414}, "imdb": {"count": 614, "value": 6.7} },
"сериал": false,
"название": "Край",
"режиссер": "Алексей Учитель",
"оператор": "Юрий Клименко",
"релиз на DVD": "21 октября 2010, «Мистерия Звука», «Монолит», ...",
"сценарий": "Александр Гоноровский",
"слоган": "-",
"продюсер": "Алексей Учитель, Александр Максимов, Константин Эрнст",
"композитор": "Дэвид Холмс",
"время": "110 мин.", "год": "2010",
"жанр": "драма, история, ...",
"описание": "В августе 1945-го в далекий поселок с названием Край с войны возвращается бывший танкист Игнат, чья страсть — паровозы. Он узнает, что на уединенном острове с довоенных времен брошен немецкий паровоз, и принимается его восстанавливать. Но, оказывается, у паровоза уже есть имя — «Густав», и есть хозяйка — Эльза, дочь немецкого инженера, арестованного в начале войны. Да и для сельчан одержимый мечтой, свободный Игнат — чужак. Страсти закипают шекспировские, причем в них задействованы не только люди, но и несколько паровозов, почти живые существа, у каждого свое имя…",
"сборы в России": "$5 122 737",
"страна": "Россия",
"релиз на Blu-Ray": "21 октября 2010, «Мистерия Звука», «Монолит», ...",
"бюджет": "$11 000 000", "id": 460432,
"зрители": "854.3 тыс.",
"оригинал": ""
}
}
Однако как мы видим информация придет не полная, не хватает артистов, их я вытаскиваю с самого кинопоиска парся html с помощью регулярных выражений.
Вообщем с теорией все ясно, практическая часть представлена выборочно ниже
procedure TFrame_VideoBase.aKinopoiskFindInfoExecute(Sender: TObject);
var
I,I2 : Integer;
js : TlkJSONobject;
Buf : TStringList;
NameFilms : string;
Res,tmp : String;
FilmName : String;
Ganr : String;
FilmID : Integer;
ListFilms : TlkJSONbase;
Films : TlkJSONbase;
ArrFilmID : ARRAY of Integer; // массив идентификаторов найденных фильмов
R : TRegExpr;
P,P1,P2,P3,PE : Integer;
begin
FormMain.LoadConfig;
Try
Buf := TStringList.Create;
IdHTTP.HandleRedirects := True;
// Настраиваем IdHttp
IdHttp.ProxyParams.ProxyServer := как нужно вам;
IdHttp.ProxyParams.ProxyPort := как нужно вам;
IdHttp.ProxyParams.BasicAuthentication
:= как нужно вам;
IdHttp.ProxyParams.ProxyUsername := как нужно вам;
IdHttp.ProxyParams.ProxyPassword := как нужно вам;
// Запрос фильма
NameFilms := InputBox('Поиск фильма','Фильм:',’’);
IdHTTP.Request.UserAgent := 'Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US) AppleWebKit/533.4 (KHTML, like Gecko) Chrome/5.0.375.55 Safari/533.4';
Res := IdHTTP.Get('http://kinopoiskinfo.appspot.com/?action=list&format=json&title=' + URLEncode(NameFilms));
//Res := _myFunctions.Strings.ReplaceSub(Res, '"название"', '"namefilm"');
js := TlkJSON.ParseText(UTF8Encode(Res)) as TlkJSONobject;
if assigned(js) then
begin
if VarToStr(js.Field['status'].value) <> '200' then
begin
KdnMessage('Данные не могут быть получены из-за ошибки или отсутствия их на сервере!');
Exit;
end;
frmListFilms.ListBox.Clear;
SetLength(ArrFilmID,0);
ListFilms := js.Field['list'];
for I := 0 to ListFilms.Count-1 do
begin
Films := ListFilms.Child[i];
if Assigned(Films) then
begin
FilmName := '';
tmp := VarToStr( Films.Field['название'].Value );
FilmName := tmp;
tmp := VarToStr( Films.Field['оригинал'].Value );
if Trim(tmp) <> '' then
FilmName := FilmName + ' - ' + tmp;
tmp := VarToStr( Films.Field['год'].Value );
if Trim(tmp) <> '' then
FilmName := FilmName + ' (' + tmp + ')';
tmp := VarToStr( Films.Field['сериал'].Value );
if tmp = 'true' then
FilmName := FilmName + ' *** сериал ***';
FilmID := Films.Field['id'].Value;
SetLength(ArrFilmID, Length(ArrFilmID) + 1);
ArrFilmID[i] := FilmID;
frmListFilms.ListBox.AddItem(Html2Str(FilmName),nil);
end;
end;
end
else
Exit;
if frmListFilms.ListBox.Items.Count = 0 then
begin
KdnMessage('По запросу ничего не найдено!');
Exit;
end
else
frmListFilms.ListBox.ItemIndex := 0;
// Выбор фильма
IF frmListFilms.ShowModal = mrOk Then
begin
if frmListFilms.ListBox.ItemIndex < 0 then
P := 0
else
P := frmListFilms.ListBox.ItemIndex;
// Получаем информацию о фильме
FilmID := ArrFilmID[P];
Res := IdHTTP.Get('http://kinopoiskinfo.appspot.com/?action=get&format=json&id=' + IntToStr(FilmID));
if Assigned(js) then js.Free;
js := TlkJSON.ParseText(UTF8Encode(Res)) as TlkJSONobject;
if assigned(js) then
begin
if VarToStr(js.Field['status'].value) <> '200' then
begin
KdnMessage(''Данные не могут быть получены из-за ошибки или отсутствия их на сервере!');
Exit;
end;
Films := js.Field['film'];
end;
// К сожалению список артистов вытаскивать нужно вручную
Res := IdHTTP.Get('http://www.kinopoisk.ru/level/1/film/' + IntToStr(FilmID));
// Парсим текст на выдергивание артистов
P1 := Pos('В главных ролях:',Res);
P2 := Pos('Роли дублировали:',Res);
P3 := Pos('показать всех',Res);
if P2 <> 0 then PE := P2 else PE := P3;
Res := Copy(Res,P1,PE-P1);
if Trim(Res) <> '' then
begin
//поиск
try
R := TRegExpr.Create;
// ГЛОБАЛЬНЫЕ МОДИФИКАТОРЫ
R.ModifierI := true; // регистро-независимый режим
R.ModifierR := false; // русский
R.ModifierS := true; // если установлен, то '.' совпадает с любым символом, (если сброшен, то '.' не совпадает с LineSeparators и LinePairedSeparator
R.ModifierM := true; // воспринимать входной текст как многострочный
R.Expression:= '<a href="/level/\d*/people/\d*/">([А-Яа-я\s]*)</a>';
tmp:= '';
if R.Exec(Res) then
REPEAT
tmp := tmp + Trim(r.Match[1]) + ','
UNTIL not r.ExecNext;
tmp := Copy(tmp,1, Length(tmp)-1);
finally
R.Free;
end;
end;
// в tmp – список артистов
// Получаем инфу о фильме
Ganr := Html2Str(VarToStr(Films.Field['жанр'].Value));
// по аналогии
{
Html2Str(VarToStr(Films.Field['режиссер'].Value));
Html2Str(VarToStr(Films.Field['описание'].Value));
Html2Str(VarToStr(Films.Field['оригинал'].Value));
Html2Str(VarToStr(Films.Field['страна'].Value));
Html2Str(VarToStr(Films.Field['год'].Value));
}
end;
Finally
if Assigned(js) then js.Free;
Buf.Free;
end;
end;
для работы вам понадобится JSON парсер, который вам нужно взять с
и пару вспомогательных функций:
function HTML2Str(HTML2Str : String) : String;
begin
{Обратная замена}
Result := HTML2Str;
Result := ReplaceSub(Result,'<' ,'<');
Result := ReplaceSub(Result,'>' ,'>');
Result := ReplaceSub(Result,'&' ,'&');
Result := ReplaceSub(Result,'"','"');
Result := ReplaceSub(Result,'"','"');
Result := ReplaceSub(Result,' ',' ');
Result := ReplaceSub(Result,'«','"');
Result := ReplaceSub(Result,'»' ,'"');
Result := ReplaceSub(Result,'—' ,'');
Result := ReplaceSub(Result,'…' ,'');
Result := ReplaceSub(Result,'<br><br>' ,#10#13);
Result := ReplaceSub(Result,'<br /><br />',#10#13);
Result := ReplaceSub(Result,'<br />',#10#13);
Result := ReplaceSub(Result,'<br>' ,#10#13);
end;
ReplaceSub- это замена найденной части строки на другую строку, replacesub – нестандартая функция, но ее легко заменить на стандартную функцию замены
Также для корректного формирования GET-запроса возьмем распространненые в инете функции
function DigitToHex(Digit: Integer): Char;
begin
case Digit of
0..9: Result := Chr(Digit + Ord('0'));
10..15: Result := Chr(Digit - 10 + Ord('A'));
else
Result := '0';
end;
end; // DigitToHex
function URLEncode(const S: string): string;
var
i, idx, len: Integer;
begin
len := 0;
for i := 1 to Length(S) do
if ((S[i] >= '0') and (S[i] <= '9')) or
((S[i] >= 'A') and (S[i] <= 'Z')) or
((S[i] >= 'a') and (S[i] <= 'z')) or (S[i] = ' ') or
(S[i] = '_') or (S[i] = '*') or (S[i] = '-') or (S[i] = '.') then
len := len + 1
else
len := len + 3;
SetLength(Result, len);
idx := 1;
for i := 1 to Length(S) do
if S[i] = ' ' then
begin
Result[idx] := '+';
idx := idx + 1;
end
else if ((S[i] >= '0') and (S[i] <= '9')) or
((S[i] >= 'A') and (S[i] <= 'Z')) or
((S[i] >= 'a') and (S[i] <= 'z')) or
(S[i] = '_') or (S[i] = '*') or (S[i] = '-') or (S[i] = '.') then
begin
Result[idx] := S[i];
idx := idx + 1;
end
else
begin
Result[idx] := '%';
Result[idx + 1] := DigitToHex(Ord(S[i]) div 16);
Result[idx + 2] := DigitToHex(Ord(S[i]) mod 16);
idx := idx + 3;
end;
end; // URLEncode
function URLDecode(const S: string): string;
var
i, idx, len, n_coded: Integer;
function WebHexToInt(HexChar: Char): Integer;
begin
if HexChar < '0' then
Result := Ord(HexChar) + 256 - Ord('0')
else if HexChar <= Chr(Ord('A') - 1) then
Result := Ord(HexChar) - Ord('0')
else if HexChar <= Chr(Ord('a') - 1) then
Result := Ord(HexChar) - Ord('A') + 10
else
Result := Ord(HexChar) - Ord('a') + 10;
end;
begin
len := 0;
n_coded := 0;
for i := 1 to Length(S) do
if n_coded >= 1 then
begin
n_coded := n_coded + 1;
if n_coded >= 3 then
n_coded := 0;
end
else
begin
len := len + 1;
if S[i] = '%' then
n_coded := 1;
end;
SetLength(Result, len);
idx := 0;
n_coded := 0;
for i := 1 to Length(S) do
if n_coded >= 1 then
begin
n_coded := n_coded + 1;
if n_coded >= 3 then
begin
Result[idx] := Chr((WebHexToInt(S[i - 1]) * 16 +
WebHexToInt(S[i])) mod 256);
n_coded := 0;
end;
end
else
begin
idx := idx + 1;
if S[i] = '%' then
n_coded := 1;
if S[i] = '+' then
Result[idx] := ' '
else
Result[idx] := S[i];
end;
end; // URLDecode
function HTTPEncode(const AStr: String): String;
const
NoConversion = ['A'..'Z','a'..'z','*','@','.','_','-'];
var
Sp, Rp: PChar;
begin
SetLength(Result, Length(AStr) * 3);
Sp := PChar(AStr);
Rp := PChar(Result);
while Sp^ <> #0 do
begin
if Sp^ in NoConversion then
Rp^ := Sp^
else
if Sp^ = ' ' then
Rp^ := '+'
else
begin
FormatBuf(Rp^, 3, '%%%.2x', 6, [Ord(Sp^)]);
Inc(Rp,2);
end;
Inc(Rp);
Inc(Sp);
end;
SetLength(Result, Rp - PChar(Result));
end;
Окошко показывающее найденные фильмы списком выглядит просто:
К сожалению указанный в посте апп уже не работает =( Автор, не назодили ли вы адекватной замены? Вообще любые адекватные апи для взятия описаний фильмов. Постеров например...
ОтветитьУдалить