С# логика парсинга из 3 циклов

Dmitriy Ka

Client
Регистрация
03.05.2016
Сообщения
773
Благодарностей
517
Баллы
93
Написал парсинг под свои задачи, получилось внутри цикла еще 2 цикла, уверен что логика не совсем верная, подскажите как сделать лучше.

C#:
IZennoList lstID = project.Lists["ID"];
string strApiKay = 12345671234567;
string strGroupID = 123213123;
int intAgeStart = 25;
int intAgeFrom = intAgeStart;
int intAgeStep = 6;
int intAgeStop = 49;


//Цикл для смены intAgeFrom intAgeTo

//* не совсем верная логика, т.к. в цикле do while при условиие Count >= 1000 intAgeTo уменьшается на 1, получаем дубли (использую решение: удаление дублей из списка), хочется получить более правильное решение
for (int i = intAgeFrom; i <= intAgeStop-intAgeStep; i+=intAgeStep) {

intAgeFrom = i;
int intAgeTo = intAgeFrom + intAgeStep;

        //Делаем гет запрос на массив данных
        int intCount;
        string strGetHttpArr;
            do
            {
                string strGet = ("https://api.vk.com/method/users.search?count=1000&country=1&sex=2&group_id=" + strGroupID +"&age_from=" + intAgeFrom + "&age_to=" + intAgeTo + "&birth_day=01&birth_month=01&fields=can_write_private_message,followers_count,last_seen&v=5.120&access_token=" + strApiKay);
                string strGetHttp = ZennoPoster.HttpGet(strGet, "","UTF-8", ZennoLab.InterfacesLibrary.Enums.Http.ResponceType.BodyOnly);

                intCount = int.Parse(Regex.Match(strGetHttp, @"(?<=""count"":).*?(?=,"")").Value);

                project.SendInfoToLog("", strGet, true);
                project.SendInfoToLog("", strGetHttp, true);

                intAgeTo--;
            strGetHttpArr = strGetHttp;   

            } while (intCount >= 1000);
            
        //Добавляем ID по условия can_write_private_message=1 в список
        if (Regex.IsMatch(strGetHttpArr, "\\{\"first_name\".*?}"))
          foreach (var r in Regex.Matches(strGetHttpArr, "\\{\"first_name\".*?}"))
            if (Regex.IsMatch(r.ToString(), "(?<=\"can_write_private_message\":)1.*?(?=,)"))
              lstID.Add(Regex.Match(r.ToString(), "(?<=\"id\":).*?(?=,)").Value);

}
//удаляем дубли из списка
List<string> lstDistinct = lstID.Distinct().ToList();
lstID.Clear();
lstID.AddRange(lstDistinct);

project.SendInfoToLog("", "End", true);
 

Phoenix78

Client
Read only
Регистрация
06.11.2018
Сообщения
11 789
Благодарностей
5 721
Баллы
113
какая разница как проверять на дубли ? что при получении данных и сверять со списком или в конце циклов одним махом удалить все дубли , что в бровь , что полбу :-)
 

Alexmd

Client
Регистрация
10.12.2018
Сообщения
1 021
Благодарностей
1 423
Баллы
113
Какой смысл делать этот слайд по возрасту? В итоге все равно не сильно сэкономишь на количестве запросов. Не лучше ли сразу запросить по каждому году?
Да и ВК отдает все красиво по полочкам в json. Зачем этот цирк с регулярками?
К тому же, в Вашем варианте, если Вы сузите фильтр до 1 года, а count будет больше 1000 то уйдете в вечный цикл, пока не потеряете токен. Но, даже без токена будете продолжать слать запросы.

Этот пример сделал по документации и не проверял, но должно быть гуд. По крайней мере, для наглядности того, как было бы лучше, более, чем сойдет.
C#:
IZennoList lstID = project.Lists["ID"];
string strApiKay = "12345671234567";
string strGroupID = "123213123";
int intAgeFrom = 25;
int intAgeStop = 49;
int errors = 0;
for(int i = intAgeFrom; i <= intAgeStop; i++){
    Thread.Sleep(300);// не забываем про лимит запросов 3шт/1сек
    string strGet = ("https://api.vk.com/method/users.search?count=1000&country=1&sex=2&group_id=" + strGroupID +"&age_from=" + i + "&age_to=" + i + "&birth_day=01&birth_month=01&fields=can_write_private_message,followers_count,last_seen&v=5.120&access_token=" + strApiKay);
    string strGetHttp = ZennoPoster.HttpGet(strGet, "","UTF-8", ZennoLab.InterfacesLibrary.Enums.Http.ResponceType.BodyOnly);
    try{
        project.Json.FromString(strGetHttp);
        //воткните тут return 0; и посмотрите, как все красиво лежит распаршенном в json.
        try{
            project.SendWarningToLog(project.Json.error.error_msg.ToString(), true);
            return null;
        }
        catch{}
    }
    catch{
        i--;
        project.SendWarningToLog("Запрос не прошел", true);
        if(errors++ < 5)
            continue;
    }
    errors = 0;
    for(int k = 0; k < project.Json.response.items.Count; k++)
        if(project.Json.response.items[k].can_write_private_message == 1)
            if(lstID.IndexOf(project.Json.response.items[k].id.ToString())==-1)
                lstID.Add(project.Json.response.items.id[k].ToString());
    project.SendInfoToLog(lstID.Count.ToString(), true);
}
project.SendInfoToLog("Done", true);
А, если мне не изменяет память, то в группах работает тот самый offset. Тогда можно вообще переделать цикл на смещение единственного offset в рамках желаемого возрастного диапазона и не париться ни с дублями, ни с возрастом, а сделать всего count/1000+1 запросов к группе


upd. добавил пару элементарных проверок на ошибки
 
Последнее редактирование:

Dmitriy Ka

Client
Регистрация
03.05.2016
Сообщения
773
Благодарностей
517
Баллы
93
upd. добавил пару элементарных проверок на ошибки
Интересное решение, возьму себе на заметку.
С# я изучаю недавно, много не понятно.
Не смог разобраться в последнем цикле for с добавлением строк в список. Для чего нужен IndexOf и почему он -1 (как я понял чтобы каждый ID записывался с новой строки, но почему он -1 не понял) и у меня выдает ошибку: "IZennoList не содержит определения для IndexOf"
 

Кто просматривает тему: (Всего: 1, Пользователи: 0, Гости: 1)