Добавить в папку C:\Program Files (x86)\ZennoLab\RU\ZennoPoster Standard\5.11.3.0\Progs\ExternalAssemblies\ - Newtonsoft.Json
Статические блоки: 1.Ссылки из GAC: System System.Core System.Drawing System.Data mscorlib System.Windows.Forms Microsoft.CSharp Newtonsoft.Json System.Xml 2.OwnCodeUsings 3.InputSettings 4.Таблица
//ПРИМЕЧАНИЯ //1. Перечисление методов по работе с группами - на этой странице: https://apiok.ru/dev/methods/rest/group/ //2. Метод для парсинга участников группы: group.getMembers: https://apiok.ru/dev/methods/rest/group/group.getMembers //3. Перечисление методов по работе с пользователями - на этой странице: https://apiok.ru/dev/methods/rest/users/ //4. Метод для получения информации об отдельном пользователе (users.getInfo): https://apiok.ru/dev/methods/rest/users/users.getInfo
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading;
using System.IO;
using System.Text.RegularExpressions;
using ZennoLab.CommandCenter;
using ZennoLab.InterfacesLibrary;
using ZennoLab.InterfacesLibrary.ProjectModel;
using ZennoLab.InterfacesLibrary.ProjectModel.Collections;
using ZennoLab.InterfacesLibrary.ProjectModel.Enums;
using ZennoLab.Macros;
using Global.ZennoExtensions;
using ZennoLab.Emulation;
using System.Security.Cryptography;
using System.Xml;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
namespace ZennoLab.OwnCode
{
/// <summary>
/// A simple class of the common code
/// </summary>
public class CommonCode
{
/// <summary>
/// Lock this object to mark part of code for single thread execution
/// </summary>
public static object SyncObject = new object();
// Insert your code here
}
}
List<string> lstUsersId = new List<string>(); //Список для хранения id-шников пользователей, состоящих в группе
//Парамерты, применяемые во всех запросах
string strAppKey = project.Variables["cfg_application_key"].Value;
string strFormat = "json"; //Возможные значения: json, xml
bool blnShowDataToLog = Convert.ToBoolean(project.Variables["bln_show_data_to_log"].Value);
string strGroupID = project.Variables["cfg_group_id"].Value; //id группы для парсинга участников (демонстрирую на группе https://ok.ru/yahudeiu)
//Параметры, примеряемые только при поиске пользователей
string strAccessToken = project.Variables["cfg_access_token"].Value;
string strSessionSecretKey = project.Variables["cfg_session_secret_key"].Value;
string strUsersPerStep = project.Variables["cfg_group_users_per_step"].Value;
int intMaxUsers = Convert.ToInt32(project.Variables["cfg_max_users"].Value);
string strDirection = "FORWARD"; //Возможные значения: FORWARD, BACKWARD, AROUND
string strStatuses = "ACTIVE,PASSIVE"; //Возможные значения: ACTIVE, ADMIN, BLOCKED, MAYBE, MODERATOR, PASSIVE; несколько статусов можно перечислять через запятую
//Параметры, применяемые только при парсинге пользователей
string strApplicationSecretKey = project.Variables["cfg_application_secret_key"].Value;
int intQueryUidsPerStep = Convert.ToInt32(project.Variables["cfg_users_query_per_step"].Value);
string strDataFields = "first_name,last_name,birthday,gender,last_online,location";
/*-------------------ТЕСТИРУЕМЫЙ КОД - НИЖЕ-------------------*/
string strAnchor = String.Empty;
string strQuery = String.Format("&application_key={0}&count={1}&direction={2}&format={3}&method=group.getMembers&statuses={4}&uid={5}", strAppKey, strUsersPerStep, strDirection, strFormat, strStatuses, strGroupID);
if (strAnchor!=String.Empty) strQuery = "anchor=" + strAnchor + strQuery; //добавляем анкор, если запрашиваем страницу вывода отличную от первой
//вычисляем MD5-подпись для запроса (не забудьте прописать using System.Security.Cryptography; в своём проекте)
MD5 md5 = MD5.Create();
string strMD5 = BitConverter.ToString(md5.ComputeHash(Encoding.UTF8.GetBytes(strQuery.Replace("&",String.Empty)+strSessionSecretKey))).Replace("-",string.Empty).ToLower();
//формируем итоговый запрос
strQuery = strQuery + "&sig=" + strMD5 + "&access_token=" + strAccessToken;
//выполняем запрос
string strAPIResponse = ZennoPoster.HttpGet("https://api.ok.ru/fb.do?" + strQuery, "30", "UTF-8", ZennoLab.InterfacesLibrary.Enums.Http.ResponceType.BodyOnly);
return strAPIResponse;
IZennoTable tblResult = project.Tables["tbl_result"];
tblResult.Clear();
List<string> lstUsersId = new List<string>(); //Список для хранения id-шников пользователей, состоящих в группе
//Парамерты, применяемые во всех запросах
string strAppKey = project.Variables["cfg_application_key"].Value;
string strFormat = "xml"; //Возможные значения: json, xml
bool blnShowDataToLog = Convert.ToBoolean(project.Variables["bln_show_data_to_log"].Value);
string strGroupID = project.Variables["cfg_group_id"].Value; //id группы для парсинга участников (демонстрирую на группе https://ok.ru/yahudeiu)
project.SendWarningToLog(String.Format("Начинаем парсить участников группы {0}", strGroupID), true);
//Параметры, примеряемые только при поиске пользователей
string strAccessToken = project.Variables["cfg_access_token"].Value;
string strSessionSecretKey = project.Variables["cfg_session_secret_key"].Value;
string strUsersPerStep = project.Variables["cfg_group_users_per_step"].Value;
int intMaxUsers = Convert.ToInt32(project.Variables["cfg_max_users"].Value);
string strDirection = "FORWARD"; //Возможные значения: FORWARD, BACKWARD, AROUND
string strStatuses = "ACTIVE,PASSIVE"; //Возможные значения: ACTIVE, ADMIN, BLOCKED, MAYBE, MODERATOR, PASSIVE; несколько статусов можно перечислять через запятую
string strAnchor = String.Empty;
while(true) {
string strQuery = String.Format("&application_key={0}&count={1}&direction={2}&format={3}&method=group.getMembers&statuses={4}&uid={5}",
strAppKey, strUsersPerStep, strDirection, strFormat, strStatuses, strGroupID);
if (strAnchor!=String.Empty) strQuery = "anchor=" + strAnchor + strQuery; //добавляем анкор, если запрашиваем страницу вывода отличную от первой
//вычисляем MD5-подпись для запроса (не забудьте прописать using System.Security.Cryptography; в своём проекте)
MD5 md5 = MD5.Create();
string strMD5 = BitConverter.ToString(md5.ComputeHash(Encoding.UTF8.GetBytes(strQuery.Replace("&",String.Empty)+strSessionSecretKey))).Replace("-",string.Empty).ToLower();
//формируем итоговый запрос
strQuery = strQuery + "&sig=" + strMD5 + "&access_token=" + strAccessToken;
//выполняем запрос
string strAPIResponse = ZennoPoster.HttpGet("https://api.ok.ru/fb.do?" + strQuery, "", "UTF-8", ZennoLab.InterfacesLibrary.Enums.Http.ResponceType.BodyOnly);
//помещаем результат запроса в поток, создаём объект xmlDataDocument, грузим в него данные из потока
MemoryStream msXmlData = new MemoryStream(Encoding.UTF8.GetBytes(strAPIResponse)); //создаём поток из массива байтов, полученного из результата выполнения запроса
XmlDataDocument xmldoc = new XmlDataDocument();
xmldoc.Load(msXmlData);
//формируем множество узлов (нод) xml-документа с заданным именем (member)
XmlNodeList nodeList = xmldoc.GetElementsByTagName("member");
project.SendWarningToLog(String.Format("Пользователей в ответе на запрос: {0} (не все будут добавлены в список)", nodeList.Count), true);
//перебираем множество полученных нод
foreach (XmlNode userNode in nodeList) {
string strUserId = userNode.SelectSingleNode("userId")!=null ? userNode.SelectSingleNode("userId").InnerText : String.Empty; //тру-программисты ругаются на тернарные операторы, но пофиг :)
string strUserStatus = userNode.SelectSingleNode("status")!=null ? userNode.SelectSingleNode("status").InnerText : String.Empty;
if (blnShowDataToLog) project.SendInfoToLog(string.Format("{0} - {1}", strUserId, strUserStatus));
if (strUserStatus=="ACTIVE") {
lstUsersId.Add(strUserId); //добавляем в список для дальнейшего парсинга только "активных" пользователей
//ВНИМАНИЕ! ограничить статусы, возвращаемые по запросу, мы могли ещё на этапе формирования запроса. Отдельный подсчёт собранных пользователей сделан для демонстрационных целей
if (intMaxUsers>0&&lstUsersId.Count>=intMaxUsers) break;
}
}
strAnchor = xmldoc.GetElementsByTagName("anchor")[0].InnerText;
bool blnHasMore = Convert.ToBoolean(xmldoc.GetElementsByTagName("has_more")[0].InnerText);
if (!blnHasMore) {
project.SendWarningToLog("Распарсили всех участников", true);
break;
}
if (intMaxUsers>0&&lstUsersId.Count>=intMaxUsers) {
project.SendWarningToLog("Распарсили максимальное количество пользователей, указанное в настройках", true);
break;
}
}
//раскомментируйте строку ниже, если хотите сохранить собранные uid пользователей в текстовый файл в папке проекта (для тестирования)
//File.WriteAllLines(project.Path + "uids.txt", lstUsersId.GetRange(0, lstUsersId.Count-1));
project.SendWarningToLog(String.Format("Начинаем парсить пользователей. В списке {0} записей", lstUsersId.Count), true);
//Параметры, применяемые только при парсинге пользователей
string strApplicationSecretKey = project.Variables["cfg_application_secret_key"].Value;
int intQueryUidsPerStep = Convert.ToInt32(project.Variables["cfg_users_query_per_step"].Value);
string strDataFields = "first_name,last_name,birthday,gender,last_online,location";
int intCurrentListPosition = 0;
int intListElementsToTake = 0;
while(true) {
string strUids = String.Empty;
if (intCurrentListPosition>=lstUsersId.Count) {
project.SendWarningToLog("Распарсили всех пользователей. Проверьте содержимое файла Result.xlsx", true);
break;
}
if (intCurrentListPosition+intQueryUidsPerStep>lstUsersId.Count) {
intListElementsToTake = lstUsersId.Count-intCurrentListPosition;
}else{
intListElementsToTake = intQueryUidsPerStep;
}
project.SendWarningToLog(String.Format("Получаем элементы списка. current: {0}, next: {1}, to take: {2}", intCurrentListPosition, intCurrentListPosition+intListElementsToTake, intListElementsToTake));
strUids = String.Join(",", lstUsersId.GetRange(intCurrentListPosition,intListElementsToTake));
intCurrentListPosition = intCurrentListPosition+intListElementsToTake;
string strQuery = String.Format("application_key={0}&fields={1}&format={2}&method=users.getInfo&uids={3}",
strAppKey, strDataFields, strFormat, strUids
);
//вычисляем MD5-подпись для запроса (не забудьте прописать using System.Security.Cryptography; в своём проекте)
MD5 md5 = MD5.Create();
string strMD5 = BitConverter.ToString(md5.ComputeHash(Encoding.UTF8.GetBytes(strQuery.Replace("&",String.Empty)+strApplicationSecretKey))).Replace("-",string.Empty).ToLower();
//формируем итоговый запрос
strQuery = strQuery + "&sig=" + strMD5;
//выполняем запрос
string strAPIResponse = ZennoPoster.HttpGet("https://api.ok.ru/fb.do?" + strQuery, "", "UTF-8", ZennoLab.InterfacesLibrary.Enums.Http.ResponceType.BodyOnly);
MemoryStream msXmlData = new MemoryStream(Encoding.UTF8.GetBytes(strAPIResponse)); //создаём поток из массива байтов, полученного из результата выполнения запроса
XmlDataDocument xmldoc = new XmlDataDocument();
xmldoc.Load(msXmlData);
XmlNodeList nodeList = xmldoc.GetElementsByTagName("user");
project.SendWarningToLog(String.Format("Получены данные по {0} пользователей в ответе на запрос", nodeList.Count), true);
foreach (XmlNode userNode in nodeList) {
string strId = userNode.SelectSingleNode("uid")!=null ? userNode.SelectSingleNode("uid").InnerText : String.Empty;
string strFirstName = userNode.SelectSingleNode("first_name")!=null ? userNode.SelectSingleNode("first_name").InnerText : String.Empty;
string strLastName = userNode.SelectSingleNode("last_name")!=null ? userNode.SelectSingleNode("last_name").InnerText : String.Empty;
string strBirthDay = userNode.SelectSingleNode("birthday")!=null ? userNode.SelectSingleNode("birthday").InnerText : String.Empty;
string strGender = userNode.SelectSingleNode("gender")!=null ? userNode.SelectSingleNode("gender").InnerText : String.Empty;
//обратите внимание: ниже получаем подсвойство
string strCountry = userNode.SelectSingleNode("location/country_name")!=null ? userNode.SelectSingleNode("location/country_name").InnerText : String.Empty;
string strCity = userNode.SelectSingleNode("location/city")!=null ? userNode.SelectSingleNode("location/city").InnerText : String.Empty;
if (blnShowDataToLog) project.SendInfoToLog(string.Format("{0} - {1} {2}", strId, strFirstName, strLastName), true);
tblResult.AddRow(new String[]{strId, strFirstName, strLastName, strBirthDay, strGender, strCountry, strCity});
}
}
IZennoTable tblResult = project.Tables["tbl_result"];
tblResult.Clear();
List<string> lstUsersId = new List<string>(); //Список для хранения id-шников пользователей, состоящих в группе
//Парамерты, применяемые во всех запросах
string strAppKey = project.Variables["cfg_application_key"].Value;
string strFormat = "json"; //Возможные значения: json, xml
bool blnShowDataToLog = Convert.ToBoolean(project.Variables["bln_show_data_to_log"].Value);
string strGroupID = project.Variables["cfg_group_id"].Value; //id группы для парсинга участников (демонстрирую на группе https://ok.ru/yahudeiu)
project.SendWarningToLog(String.Format("Начинаем парсить участников группы {0}", strGroupID), true);
//Параметры, примеряемые только при поиске пользователей
string strAccessToken = project.Variables["cfg_access_token"].Value;
string strSessionSecretKey = project.Variables["cfg_session_secret_key"].Value;
string strUsersPerStep = project.Variables["cfg_group_users_per_step"].Value;
int intMaxUsers = Convert.ToInt32(project.Variables["cfg_max_users"].Value);
string strDirection = "FORWARD"; //Возможные значения: FORWARD, BACKWARD, AROUND
string strStatuses = "ACTIVE,PASSIVE"; //Возможные значения: ACTIVE, ADMIN, BLOCKED, MAYBE, MODERATOR, PASSIVE; несколько статусов можно перечислять через запятую
string strAnchor = String.Empty;
while(true) {
string strQuery = String.Format("&application_key={0}&count={1}&direction={2}&format={3}&method=group.getMembers&statuses={4}&uid={5}",
strAppKey, strUsersPerStep, strDirection, strFormat, strStatuses, strGroupID);
if (strAnchor!=String.Empty) strQuery = "anchor=" + strAnchor + strQuery; //добавляем анкор, если запрашиваем страницу вывода отличную от первой
//вычисляем MD5-подпись для запроса (не забудьте прописать using System.Security.Cryptography; в своём проекте)
MD5 md5 = MD5.Create();
string strMD5 = BitConverter.ToString(md5.ComputeHash(Encoding.UTF8.GetBytes(strQuery.Replace("&",String.Empty)+strSessionSecretKey))).Replace("-",string.Empty).ToLower();
//формируем итоговый запрос
strQuery = strQuery + "&sig=" + strMD5 + "&access_token=" + strAccessToken;
//выполняем запрос
string strAPIResponse = ZennoPoster.HttpGet("https://api.ok.ru/fb.do?" + strQuery, "", "UTF-8", ZennoLab.InterfacesLibrary.Enums.Http.ResponceType.BodyOnly);
//Создаём объект Json и грузим в него контент, формируем множество узлов (токенов) с заданным именем
JObject objParsedJson = JObject.Parse(strAPIResponse);
IEnumerable<JToken> userTokens = objParsedJson.SelectTokens("members[*]", false);
project.SendWarningToLog(String.Format("Пользователей в ответе на запрос: {0} (не все будут добавлены в список)", userTokens.Count()), true);
//Перебираем множество токенов members
foreach (JToken userToken in userTokens) {
string strUserId = (string)userToken.SelectToken("userId");
string strUserStatus = (string)userToken.SelectToken("status"); //примечание: можно отсекать "плохие" статусы на уровне JSONPath - при вызове метода SelectTokens
if (blnShowDataToLog) project.SendInfoToLog(string.Format("{0} - {1}", strUserId, strUserStatus));
if (strUserStatus=="ACTIVE") {
lstUsersId.Add(strUserId); //добавляем в список для дальнейшего парсинга только "активных" пользователей.
//ВНИМАНИЕ! ограничить статусы, возвращаемые по запросу, мы могли ещё на этапе формирования запроса. Отдельный подсчёт собранных пользователей сделан для демонстрационных целей
if (intMaxUsers>0&&lstUsersId.Count>=intMaxUsers) break;
}
}
strAnchor = (string)objParsedJson.SelectToken("anchor");
bool blnHasMore = (bool)objParsedJson.SelectToken("has_more");
if (!blnHasMore) {
project.SendWarningToLog("Распарсили всех участников", true);
break;
}
if (intMaxUsers>0&&lstUsersId.Count>=intMaxUsers) {
project.SendWarningToLog("Распарсили максимальное количество пользователей, указанное в настройках", true);
break;
}
}
//раскомментируйте строку ниже, если хотите сохранить собранные uid пользователей в текстовый файл в папке проекта (для тестирования)
//File.WriteAllLines(project.Path + "uids.txt", lstUsersId.GetRange(0, lstUsersId.Count-1));
project.SendWarningToLog(String.Format("Начинаем парсить пользователей. В списке {0} записей", lstUsersId.Count), true);
//Параметры, применяемые только при парсинге пользователей
string strApplicationSecretKey = project.Variables["cfg_application_secret_key"].Value;
int intQueryUidsPerStep = Convert.ToInt32(project.Variables["cfg_users_query_per_step"].Value);
string strDataFields = "first_name,last_name,birthday,gender,last_online,location";
int intCurrentListPosition = 0;
int intListElementsToTake = 0;
while(true) {
string strUids = String.Empty;
if (intCurrentListPosition>=lstUsersId.Count) {
project.SendWarningToLog("Распарсили всех пользователей. Проверьте содержимое файла Result.xlsx", true);
break;
}
if (intCurrentListPosition+intQueryUidsPerStep>lstUsersId.Count) {
intListElementsToTake = lstUsersId.Count-intCurrentListPosition;
}else{
intListElementsToTake = intQueryUidsPerStep;
}
project.SendWarningToLog(String.Format("Получаем элементы списка. current: {0}, next: {1}, to take: {2}", intCurrentListPosition, intCurrentListPosition+intListElementsToTake, intListElementsToTake));
strUids = String.Join(",", lstUsersId.GetRange(intCurrentListPosition,intListElementsToTake));
intCurrentListPosition = intCurrentListPosition+intListElementsToTake;
string strQuery = String.Format("application_key={0}&fields={1}&format={2}&method=users.getInfo&uids={3}",
strAppKey, strDataFields, strFormat, strUids
);
//вычисляем MD5-подпись для запроса (не забудьте прописать using System.Security.Cryptography; в своём проекте)
MD5 md5 = MD5.Create();
string strMD5 = BitConverter.ToString(md5.ComputeHash(Encoding.UTF8.GetBytes(strQuery.Replace("&",String.Empty)+strApplicationSecretKey))).Replace("-",string.Empty).ToLower();
//формируем итоговый запрос
strQuery = strQuery + "&sig=" + strMD5;
//выполняем запрос
string strAPIResponse = ZennoPoster.HttpGet("https://api.ok.ru/fb.do?" + strQuery, "", "UTF-8", ZennoLab.InterfacesLibrary.Enums.Http.ResponceType.BodyOnly);
JObject objParsedJson = JObject.Parse("{users:" + strAPIResponse + "}"); //на лету приводим получаемый json к "каноническому" виду
IEnumerable<JToken> userTokens = objParsedJson.SelectTokens("users[*]", false);
project.SendWarningToLog(String.Format("Получены данные по {0} пользователей в ответе на запрос.", userTokens.Count()), true);
foreach (JToken userToken in userTokens) {
string strId = (string)userToken.SelectToken("uid");
string strFirstName = (string)userToken.SelectToken("first_name") ?? String.Empty;
string strLastName = (string)userToken.SelectToken("last_name") ?? String.Empty;
string strBirthDay = (string)userToken.SelectToken("birthday") ?? String.Empty; //конструкция ?? проверяет значение слева, и если оно равно null, то присваивает значение справа
string strGender = (string)userToken.SelectToken("gender") ?? String.Empty;
string strCountry = (string)userToken.SelectToken("location.countryName") ?? String.Empty; //обратите внимание: получаем подсвойство
string strCity = (string)userToken.SelectToken("location.city") ?? String.Empty;
if (blnShowDataToLog) project.SendInfoToLog(string.Format("{0} - {1} {2}", strId, strFirstName, strLastName), true);
tblResult.AddRow(new String[]{strId, strFirstName, strLastName, strBirthDay, strGender, strCountry, strCity});
}
}
using System.Security.Cryptography;
using System.Xml;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;