
Я хочу еще раз поговорить о простейших способах работы с API ВКонтакте и очень надеюсь, что эта статья может стать отправной точкой для начинающих разработчиков. Мы будем работать с довольно разнообразным методом messages.getHistory, а с помощью XDocument получать фотографию. Всех, кто научился проходить авторизацию и хочет опробовать работу с API, прошу под кат.
Начнем?
Итак, мы авторизовались, получили токен. Что дальше? Я хочу привести пример с довольно интересным методом, который поможет начинающим освоиться в мире API ВКонтакте. Если вы не нашли упомянутый выше метод в списке основных методов, то переходим сюда и видим большой список различных возможностей. С одной из них мы и начнем работу.
Наша задача на сегодня состоит в том, чтобы получить все сообщения с пользователем, обработать узлы xml и скачать фотографии из всей переписки. Так выглядит узел, который нам нужен

Очевидно, что в описании содержится
Описание:
Возвращает историю сообщений для указанного пользователя или групповой беседы.
Результат:
Возвращает массив объектов message – личных сообщений в указанном диалоге с пользователем или групповой беседе. Каждый объект message содержит набор полей, описание которых доступно здесь.
В нашем распоряжении целых 6 параметров, 2 из которых обязательные. Подробнее о каждом:
uid – наверное, самый важный параметр. Сервер должен знать, с каким пользователем мы хотим получить историю сообщений.
chat_id – необязательный параметр в случае, если мы указали uid.
offset – смещение для выборки. Проще говоря, тот параметр, без которого мы не сможем получить большую переписку из-за ограничения в 200 сообщений в одном ответе.
count – то самое количество сообщений, которое мы хотим получить от сервера. Помните об ограничении в 200 сообщений за один запрос.
start_mid – идентификатор сообщения, начиная с которого необходимо получить последующие сообщения. Прошу не путать с count. В этот аргумент мы заносим id сообщения, а не его порядковый номер.
rev – с какого сообщения нам нужна переписка. Последнее или первое. 0 по умолчанию, что означает обратный хронологический порядок.
Самое необходимое
Неплохо, да? Давайте опробуем.
Напоминаю, что работать мы будем с LINQ to XML. Подключаем необходимое пространство имен
using System.Xml.Linq;
Теперь у нас есть доступ к очень мощному, на мой взгляд, парсеру XML. Так давайте объявим его
XDocument doc;
Все получилось? Тогда продолжаем. Мы помним, что если у нас очень большая переписка, то нам надо использовать смещение и указывать параметр offset. Тогда создадим счетчик, который будет увеличиваться на 200 каждую итерацию. А также, создадим счетчик для динамических имен фотографий при сохранении
int m=0;
int k=0;
Конечно не забудем про WebClient, который поможет нам скачать фотографию
WebClient src_client = new WebClient();
Думаю, что стоит создать отдельную папку, чтобы не засорить ностальгическими фотографиями все остальные файлы с программой
Directory.CreateDirectory("img/");
Надеюсь, что у вас по-прежнему все получается. А теперь самое интересное. Сейчас мы сделаем запрос к серверу и укажем ему те аргументы, которые нам нужны для достижения нашей задачи
doc = XDocument.Load("https://api.vk.com/method/messages.getHistory.xml?uid=123456&offset=" + m + "&count=200&access_token=" + token);
Во-первых обратите внимание, что мы указали формат получаемых данных .xml для метода messages.getHistory. Обычно он возвращает JSON, с которым LINQ to XML не справится. Также мы указали uid пользователя, с которым хотим историю. Ну и конечно offset, который мы будем изменять каждый раз, пока не дойдем до конца. count ставим тот, который вам нужен. Но помните, что не больше 200, а то сервер
Работа с XML
А теперь рассмотрим сам цикл. Я не претендую на оптимизированный код и понимаю, что его можно сократить, но хочу показать подробную работу парсера с подобными XML.
while (true)
{
doc = XDocument.Load("https://api.vk.com/method/messages.getHistory.xml?uid=12345&offset=" + m + "&count=200&access_token=" + token);// Загружаем наш xml с сервера и начнем обработку
foreach (XElement el in doc.Root.Elements())// Раскрываем корневой узел
{
// И ищем в нем узел с говорящим названием
if (el.Name.ToString() == "message")
{
foreach (XElement el_msg in el.Elements())// Теперь в узле message
{
// ищем узел с приложениями
if (el_msg.Name == "attachment")
{
foreach (XElement el_attch in el_msg.Elements())
{
// Аналогично ищем в нем узел, который укажет нам, что тут фото
if (el_attch.Name == "photo")
{
foreach (XElement el_photo in el_attch.Elements())
{
// Получаем элемент большой фотографии
if (el_photo.Name == "src_xbig")
{
// Скачиваем фотографию в img/
src_client.DownloadFile(el_photo.Value, "img/img" + k + ".jpg");
k++;
}
}
}
}
}
}
}
}
// Ну и конечно увеличение параметра count
m += 200;
}
LINQ
Спасибо Atreides07 за LINQ версию. К сожалению, я не додумался написать её сразу.
while (true)
{
var doc = XDocument.Load("https://api.vk.com/method/messages.getHistory.xml?uid=12345&offset=" + m + "&count=" + n + "&access_token=" + token);// Загружаем наш xml с сервера и начнем обработку
var photoElements=
doc.Root.Elements("message")
.SelectMany(el => el.Elements("attachment")
.SelectMany(el_msg => el_msg.Elements("photo")
.SelectMany(elAttch => elAttch.Elements("src_xbig"))));
foreach (var el_photo in photoElements)
{
// Скачиваем фотографию в img/
src_client.DownloadFile(el_photo.Value, "img/img" + k + ".jpg");
k++;
}
// Ну и конечно увеличение параметра count
m += n;
}
XPath
using System.Xml.XPath;
Также думаю, что стоит показать вариант с XPath.
// Создаем запрос
XPathDocument document_x = new XPathDocument("https://api.vk.com/method/messages.getHistory.xml?uid=12345&offset=" + m + "&count=200&access_token=" + token);
XPathNavigator navigator = document_x.CreateNavigator();
// Выражение
string str_exp = "//message//attachment//photo//src_big";
XPathExpression expres = XPathExpression.Compile(str_exp);
XmlNamespaceManager manager = new XmlNamespaceManager(navigator.NameTable);
expres.SetContext(manager);
XPathNodeIterator nodes = navigator.Select(expres);
while (nodes.MoveNext())// Пробегаемся по найденному
src_client.DownloadFile(nodes.Current.ToString(), "img/imj" + k + ".jpg");// Скачиваем
Конечно не забываем про цикл и увеличение m.
Вот собственно и все. Открываем папку, откуда запускали нашу программу, находим папку img и наслаждаемся результатом.
Вывод
Как мы видим, работа с API ВКонтакте довольно проста, а с удобными возможностями LINQ to XML она становится подробной и более понятной. Надеюсь, что вам понравилось. Спасибо за прочтение.
Пожалуйста, указывайте на любые недочеты в статье. Буду учиться.