PowerShell и ЖЖ: функция «getevents», скачивание постов (интерфейс «flat»), ч.1

Mar 04, 2023 20:26

Ранее в этой серии постов:
...
26. PowerShell: возврат массива из функции
27. PowerShell и ЖЖ: функция «syncitems» и данные от нее, ч.3
28. PowerShell и ЖЖ: функция «syncitems» и данные от нее, ч.4 (тесты)

Окружение: операционная система «Windows 10», программа-оболочка «PowerShell» версии 7.

В наборе удалённых функций (документация для интерфейса «flat») программы-сервера ЖЖ («Живого Журнала») для получения постов журнала по протоколу обмена данными между ЖЖ и программой-клиентом на базе протокола HTTP(S) предназначена удалённая функция «getevents». В предыдущих постах я уже немного пользовался этой функцией в примерах для получения одного конкретного поста журнала. Теперь я хочу рассмотреть использование этой функции для получения (загрузки на свой компьютер, скачивания) всех постов журнала.

Четыре способа работы функции «getevents»

Удалённая функция «getevents» может работать одним из четырех возможных способов. Выбранный способ вы можете указать во входном параметре «selecttype» этой функции. Вот какие возможные значения предусмотрены для параметра «selecttype»: «day», «lastn», «one» и «syncitems».

Сразу отмечу, что ни один из этих способов не позволяет просто скачать к себе на компьютер сразу все посты определенного журнала с сервера ЖЖ одной порцией, если ваш журнал больше определенного размера. Это сразу стоит уяснить, потому что лично я долго искал этот способ, роясь в документации. Почему это так, я точно не знаю, а свои догадки на эту тему тут излагать не буду.

Способ «day» позволяет скачать все посты журнала, опубликованные в определенный день (информация о дате при этом указывается в дополнительных входных параметрах «year», «month» и «day»). Предполагается, что этот способ будет использоваться при работе пользователя с календарем в его веб-клиенте (если, конечно, календарь в этом веб-клиенте реализован). Я не пробовал этот способ на практике.

Способ «lastn» позволяет скачать указанное в дополнительном входном параметре «howmany» количество самых последних (самых свежих) постов в журнале. По умолчанию (если дополнительный параметр «howmany» не указан) будет скачано 20 самых последних постов. Максимально возможное число постов, которое можно скачать этим способом - 50 самых последних постов. Это ограничение указано в документации. Предполагается, что этот способ будет использоваться, если пользователь хочет поработать в своем веб-клиенте с самыми свежими постами своего журнала (просмотреть их или отредактировать). Я не пробовал этот способ на практике.

Способ «one» позволяет скачать один пост журнала, идентификатор которого указан в дополнительном входном параметре «itemid». Я много раз испробовал этот способ на практике, экспериментируя с разными удалёнными функциями программы-сервера ЖЖ. Я неоднократно описывал это в предыдущих постах.

Способ «syncitems» позволяет скачать некоторое количество постов журнала, созданных или измененных после определенной даты, указанной в дополнительном входном параметре «lastsync». Предполагается, что этот способ будет использоваться для выполнения синхронизации оригинала журнала на серевере ЖЖ с копией журнала на компьютере пользователя. Если дополнительный входной параметр «lastsync» не указывать, то будут возвращены посты, начиная с самых старых. Количество возвращаемых при этом способе постов определяется сервером ЖЖ (вероятно, это количество могут менять). На данный момент это количество равно 100 постам.

Какой способ использовать для скачивания всех постов журнала

Любой из четырех перечисленных выше способов можно использовать для скачивания на свой компьютер всех постов журнала. Однако, рекомендуемым для этого является способ «syncitems». Почему выбран именно этот способ?

Способ «lastn» можно использовать только для скачивания журналов, в которых число постов не превышает 50. Это следует из описанного ранее ограничения этого способа, установленного в программе-сервере ЖЖ. Если в журнале больше 50 постов, то этот способ использовать для скачивания всех постов журнала не получится.

Способ «day» является неэффективным для использования. Например, предположим, что у вас в журнале 150 постов, которые вы писали один раз в день. Тогда при использовании способа «day» для скачивания всех постов журнала придется выполнить 150 HTTP(S)-запросов к программе-серверу ЖЖ. Это чересчур много. А ведь журнал со 150 постами считается по меркам ЖЖ маленьким. В больших журналах могут содержаться тысячи постов. Те же выкладки применимы к способу «one».

Таким образом, для скачивания всех постов остается использовать только способ «syncitems» (в принципе, скачивание всех постов журнала на свой компьютер является частным случаем синхронизации, для выполнения которой предназначен этот способ). С помощью этого способа можно скачивать посты журнала порциями по 100 штук, действуя по определенному алгоритму, который описан в документации. Для журнала со 150 постами понадобится выполнить 2 HTTP(S)-запроса к программе-серверу ЖЖ (плюс еще один «подготовительный» HTTP(S)-запрос к удалённой функции «syncitems» и плюс HTTP(S)-запросы, касающиеся аутентификации).

Работа с функцией «getevents» способом «syncitems» на практике

Сначала я решил просто получить данные от одного вызова удалённой функции «getevents» способом «syncitems», а не писать сразу скрипт для скачивания всего журнала, для того, чтобы изучить, как этот способ работает. Пробую я эту функцию на журнале «vbgtut», как и в предыдущих постах. Для аутентификации буду использовать способ «challenge-response», так как мне нужно будет пока что вызвать удалённую функцию только один раз (для множественной отправки HTTP(S)-запросов в будущем эффективнее будет, наверное, использовать способ аутентификации с помощью «cookie»).

Подготовка вспомогательных функций

Как обычно, загружаю в текущий сеанс работы с программой-оболочкой «PowerShell» две вспомогательные функции toHashTable (для преобразования многострочной строки, полученной в теле HTTP(S)-ответа, в хеш-таблицу) и getHash (для получения хеш-суммы заданной строки по заданному алгоритму):

function toHashTable($str) {
$arr = $str -split '\r?\n'
$hash = @{}
$len = if ($arr.Length % 2) { $arr.Length - 1 } else { $arr.Length }
for ($i = 0; $i -lt $len; $i += 2) {
$hash[$arr[$i]] = $arr[$i + 1]
}
return $hash
}

function getHash($str, $alg) {
$stringAsStream = [System.IO.MemoryStream]::new()
$writer = [System.IO.StreamWriter]::new($stringAsStream)
$writer.write($str)
$writer.Flush()
$stringAsStream.Position = 0
(Get-FileHash -InputStream $stringAsStream -Algorithm $alg).Hash.ToLower()
}

Запуск удалённой функции «getevents» способом «syncitems»

$body = @{
mode = "getchallenge"
}
$Response = Invoke-WebRequest -URI "https://www.livejournal.com/interface/flat" `
-Body $body -Method "POST"
$params = toHashTable($Response.Content)
$hPass = getHash "пароль" "MD5"
$hResp = getHash ($params["challenge"] + $hPass) "MD5"
$body = @{
mode = "getevents"
user = "vbgtut"
auth_method = "challenge"
auth_challenge = $params["challenge"]
auth_response = $hResp
selecttype = "syncitems"
ver = "1"
}
$Response = Invoke-WebRequest -URI "https://www.livejournal.com/interface/flat" `
-Body $body -Method "POST"
$params = toHashTable($Response.Content)
$params["success"]

OK

Анализ полученных данных

PS C:\> ($Response.Content).Length
473540 # количество символов, не байтов
PS C:\> $params.Count
1434 # количество параметров, не строк
PS C:\> $params["events_count"]
100
PS C:\> $params["prop_count"]
277

Как видно из блока кода выше, в теле HTTP(S)-ответа я получил многострочную строку (multiline string), состоящую из 473 тысяч 540 символов. Тут следует во избежание путаницы напомнить, что это именно количество символов, а не количество байтов, используемых для хранения полученных символов (количество байтов для хранения символов зависит от используемой при сохранении символов кодировки, то есть может быть разным). Это станет видно далее.

После преобразования многострочной строки из тела HTTP(S)-ответа в хеш-таблицу с параметрами я получил в хеш-таблице 1434 параметра (напомню, каждый параметр располагается на двух линиях многострочной строки, то есть в теле HTTP(S)-ответа в многострочной строке было 2868 или 2869 линий).

Также из блоков кода выше видно, что в параметрах содержится три общих параметра: «success», «events_count» и «prop_count». Параметр «success» содержит значение «OK», что говорит об успешности выполнения удалённой функции «getevents». Параметр «events_count» содержит число возвращенных постов (100 штук). Кроме постов функция «getevents» возвращает метаданные к постам, то есть «свойства» постов (по-английски «properties» или сокращенно «props»). Общий параметр «prop_count» содержит количество возвращенных функцией «getevents» свойств постов (277 штук).

Из опытов, описанных в предыдущих постах, нам известно, что в журнале «vbgtut» всего 147 постов на данный момент. Таким образом, из блока кода выше видно, что программа-сервер ЖЖ вернула не все посты указанного журнала, а только самые старые (по дате создания или по дате изменения) 100 штук из них. То есть на данный момент от сервера ЖЖ нельзя получить за один раз более 100 постов журнала (я уже упоминал об этом ограничении выше). Дополнительный входной параметр «lastsync» я специально не указал в этот раз, чтобы посмотреть, как в этом случае сработает удалённая функция «getevents» (она вернула самые старые 100 постов журнала, то есть можно считать, что по умолчанию параметр «lastsync» равен некой дате, которая старше даты создания журнала; возможно, это дата начала «эпохи Unix»).

В данном случае каждый полученный пост журнала занимает по 6 параметров: «anum», «event», «eventtime», «itemid», «subject» и «url». Такой состав параметров характерен для общедоступного (публичного) поста. Для постов с ограниченным доступом (для друзей или личных) существуют дополнительные параметры, но тут я их пока что рассматривать не буду, так как в журнале «vbgtut» нет постов с ограниченным доступом.

К каждому посту может быть разное количество свойств поста. Поэтому прямой (пропорциональной) связи между числом 100 (количество полученных постов) и 277 (количество полученных свойств постов) нет. Каждое свойство поста занимает по 3 параметра: «itemid», «name» и «value». Параметр «itemid» связывает отдельное свойство поста с его постом. Параметр «name» содержит название свойства поста, а параметр «value» содержит значение свойства поста. Например, метки поста содержатся в одном из свойств поста.

Подведем итог анализа:

1434 параметра = (100 постов * 6) + (277 свойств * 3) + 3 общих = 600 + 831 + 3 = 1434

Приведенный выше расчет дал мне примерное представление о том, что я получил в теле HTTP(S)-ответа.

Сохранение данных в текстовый файл и обратная загрузка из файла

Для последующего анализа я сохраняю полученные в теле HTTP(S)-ответа данные в текстовый файл на своем рабочем столе, чтобы не запрашивать их у программы-сервера ЖЖ еще раз (простейший кэш):

$Response.Content | Out-File -FilePath "C:\Users\Илья\Desktop\getEvents vbgtut.txt" `
-NoNewline -NoClobber

По умолчанию командлет «Out-File» из программы-оболочки «PowerShell» версии 7 сохраняет текст в кодировке UTF-8 (без метки BOM). У меня получившийся текстовый файл занимает 480 тысяч 442 байта, это около 469 Кб (480442 / 1024).

Как можно видеть, размер получившегося текстового файла в байтах не совпал с количеством символов, полученных в теле HTTP(S)-ответа (см. выше, там было число 473540). Для кодировки UTF-8 число символов и число байтов для хранения этих символов может совпадать в случае, если все полученные от сервера ЖЖ символы входят в таблицу ASCII (например, символы латиницы и арабские цифры). Тексты постов тоже не будут давать разницы, так как к ним дополнительно применено процентное кодирование. А вот названия постов (в параметре «subject») и метки постов (в соответствующем свойстве поста) получены от сервера ЖЖ в той кодировке, в которой я их вводил при написании поста, то есть в кодировке UTF-8. Они написаны буквами русского алфавита, для хранения которых в кодировке UTF-8 используется по 2 байта. За счет этого и возникает разница между числом символов 473540 и числом байтов 480442.

Проверим возможность и правильность обратной загрузки данных тела HTTP(S)-ответа из текстового файла (кэша) на моем рабочем столе:

PS C:\> $fromCache = Get-Content -Path "C:\Users\Илья\Desktop\getEvents vbgtut.txt" -Raw
PS C:\> $fromCache.Length
473540

Как видно из блока кода выше, при обратной загрузке данных из файла размером в 480442 байта в переменной $fromCache получилась строка длиной в 473540 символов, как и должно быть.

Далее я буду анализировать содержимое параметров, представляющих полученные посты.

Продолжение следует...

Инструмент, Образование, Сайтостроение, Программирование, Английский язык, ЖЖ

Previous post Next post
Up