Нужна помощь в обходе защиты от бота, готов оплатить за результат!

Регистрация
26.05.2020
Сообщения
495
Благодарностей
172
Баллы
43
Дано: пилю бота для планирования поставок на wildberries. На днях они выкатили защиту от ботов, что представляет из себя скрытую капчу, которую гадает сам же вб и подставляет ответ на вопрос в фоновом режиме. При этом запускается нижеследующий механизм ПОСЛЕ нажатия на кнопку "Перенести поставку" и итоговый токен подставляется в заголовки запроса.
Выглядит это следующим образом:

125538

Первым запросом мы запрашиваем токен для подстановки в проверку (непонятно, откуда берется client_id для подстановки в параметр запроса)

125539

Вторым запросом (solve.wasm) происходит расчет ответа на запрос капчи на серверах самого вб. При этом в параметрах запроса и ответе пустота.
Третьим запросом подставляем в параметры ответ из первого запроса с добавлением вычислений по капче. Также запускается еще javascript параллельно, возможно он гадает и выдает результат, но я не знаю, как его получить...

125541

В ответ получаем токен для подстановки в наш основной запрос, которого на скринах нет.

Собственно, вопроса два: где брать client_id и ответ на загадку капчи?

Готов к созвону с демонстрацией экрана, дабы обсудить возможные решения. Также могу предоставить доступ по anydesk. Бюджет на конечное решение - 10к скрепных деревянных рубликов.
 
Регистрация
26.05.2020
Сообщения
495
Благодарностей
172
Баллы
43
Апну темку. Неужто никто не может/хочет помочь и заработать?
 

volody00

Client
Регистрация
06.09.2016
Сообщения
918
Благодарностей
953
Баллы
93
Регистрация
26.05.2020
Сообщения
495
Благодарностей
172
Баллы
43

samsonnn

Client
Регистрация
02.06.2015
Сообщения
1 777
Благодарностей
1 447
Баллы
113
Регистрация
26.05.2020
Сообщения
495
Благодарностей
172
Баллы
43

samsonnn

Client
Регистрация
02.06.2015
Сообщения
1 777
Благодарностей
1 447
Баллы
113
Регистрация
26.05.2020
Сообщения
495
Благодарностей
172
Баллы
43
Регистрация
26.05.2020
Сообщения
495
Благодарностей
172
Баллы
43
UP, актуально до сих пор!..
 

Demiz

Client
Регистрация
19.12.2017
Сообщения
187
Благодарностей
121
Баллы
43
Для начала заного отснифай запросы через fiddler, через траффик зенно не всегда получается найти. Возможно увидишь там нужные значения, которые тебе необходимы
В ответ получаем токен для подстановки в наш основной запрос, которого на скринах нет.
Чтобы токен получить возможно нужно гетнуть страницу чтобы он появился, по скринам не совсем понятно
 

Pashka_Fol

Новичок
Регистрация
22.09.2024
Сообщения
3
Благодарностей
1
Баллы
3
Регистрация
26.05.2020
Сообщения
495
Благодарностей
172
Баллы
43
Для начала заного отснифай запросы через fiddler, через траффик зенно не всегда получается найти. Возможно увидишь там нужные значения, которые тебе необходимы

Чтобы токен получить возможно нужно гетнуть страницу чтобы он появился, по скринам не совсем понятно
не, там wasm скрипт генерит ответ на капчу, и как его стартануть - хз
 
Регистрация
26.05.2020
Сообщения
495
Благодарностей
172
Баллы
43

Pashka_Fol

Новичок
Регистрация
22.09.2024
Сообщения
3
Благодарностей
1
Баллы
3

Pashka_Fol

Новичок
Регистрация
22.09.2024
Сообщения
3
Благодарностей
1
Баллы
3
Я хз куда отписать тебе, писать в лс я чет не могу :(
 
  • Спасибо
Реакции: Андрейка2020

Alex91

Активный пользователь
Регистрация
15.08.2024
Сообщения
216
Благодарностей
60
Баллы
28
  • Спасибо
Реакции: Pashka_Fol

samsonnn

Client
Регистрация
02.06.2015
Сообщения
1 777
Благодарностей
1 447
Баллы
113
Регистрация
26.05.2020
Сообщения
495
Благодарностей
172
Баллы
43
Зачем вы на перед ему заплатили? Оплата всегда должна быть только по результату выполненной работы.
ибо лох, очевидно ж... :D:D:D
Так бывает, когда давно не встречаешь говноедов в окружении, расслабляешься, доверие, вся фигня...
 

Super_KC

Client
Регистрация
19.12.2021
Сообщения
8
Благодарностей
3
Баллы
3
не, там wasm скрипт генерит ответ на капчу, и как его стартануть - хз
Тема тоже интересна, но я реализую для личного пользования. Chat GPT подсказал, что это криптографическая капча. Он там прислал c# код, но хз как он работает)
Вб вместе с этим обновлением сделал ограничение по запросу переноса. 2 за 5 минут, у некоторых 1 за 15 мин.
И появились ещё доп. запросы "sentry", как я понял, по ним и отслеживают время.
Так вот, что даст решение этой капчи, если есть ограничение по запросам?
 

Ilshakin

Client
Регистрация
14.02.2017
Сообщения
639
Благодарностей
581
Баллы
93
Регистрация
26.05.2020
Сообщения
495
Благодарностей
172
Баллы
43
Он там прислал c# код, но хз как он работает)
не разобрался? В итоге сделали мне в браузерном режиме через исполнение js на текущей странице:
JavaScript:
// Инициализация глобальной переменной в объекте window
window.globalTransferResult2 = null;

function waitForElementContent(selector, timeout = 10000) {
  return new Promise((resolve, reject) => {
    const checkContent = () => {
      const elements = document.querySelectorAll(selector);
      if (elements.length > 0 && elements[0].children && elements[0].children.length > 0) {
        return resolve(elements);
      }
    };

    if (checkContent()) return;

    const observer = new MutationObserver(() => {
      if (checkContent()) {
        observer.disconnect();
      }
    });

    observer.observe(document.body, {
      childList: true,
      subtree: true
    });

    setTimeout(() => {
      observer.disconnect();
      reject(new Error(`Контент в элементе ${selector} не появился в течение ${timeout}ms`));
    }, timeout);
  });
}

function findAndClickTransferButton() {
  const transferDiv = document.querySelector('div[class^="Calendar-plan-buttons--transfer__"]');
  if (transferDiv) {
    console.log('Найден div для переноса:', transferDiv);
    const button = transferDiv.querySelector('button');
    if (button) {
      console.log('Найдена кнопка для переноса:', button);
      button.click();
      console.log('Выполнен клик по кнопке переноса');
      return true;
    } else {
      console.log('Кнопка для переноса не найдена');
    }
  } else {
    console.log('Div для переноса не найден');
  }
  return false;
}

function findTargetDateCell(tbody, targetDate) {
  console.log('Ищем ячейку с датой:', targetDate);
  const cells = tbody.querySelectorAll('td[class^="Calendar-cell__"]');
  console.log('Найдено ячеек:', cells.length);

  for (const cell of cells) {
    console.log('Проверяем ячейку:', cell.outerHTML);
    
    const dateContainer = cell.querySelector('div[class^="Calendar-cell__date-container__"]');
    if (dateContainer) {
      const dateSpan = dateContainer.querySelector('span[class*="Text--body-m-bold__"]');
      if (dateSpan) {
        const cellText = dateSpan.textContent.trim();
        console.log('Текст даты в ячейке:', cellText);
        
        const datePart = cellText.split(',')[0].trim();
        console.log('Извлеченная часть даты:', datePart);

        if (datePart === targetDate) {
          console.log('Найдена подходящая ячейка:', cell.outerHTML);
          return cell;
        }
      }
    }
  }

  console.log('Ячейка с целевой датой не найдена');
  return null;
}

async function findClickAndWait(targetDate, palletCount) {
  console.log('Начало выполнения findClickAndWait с датой:', targetDate, 'и количеством паллет:', palletCount);
  const elements = document.querySelectorAll('div[class^="Supply-detail-options__buttons__"]');
  if (!elements || elements.length === 0) {
    console.log('Элементы не найдены');
    return false;
  }
  console.log('Найдены элементы:', elements);
 
  for (const element of elements) {
    console.log('Текущий элемент:', element.outerHTML);
    const buttons = element.querySelectorAll('button');
    if (!buttons || buttons.length !== 2) {
      console.log(`Найдено ${buttons ? buttons.length : 0} кнопок вместо 2, пропускаем этот элемент`);
      continue;
    }
    
    const safeButtons = Array.from(buttons).filter(button => !button.classList.contains('danger'));
    if (safeButtons.length > 0) {
      const safeButton = safeButtons[0];
      console.log('Найдена подходящая кнопка:', safeButton.outerHTML);
      
      safeButton.click();
      console.log('Выполнен клик по кнопке');
      
      try {
        const tbodyElements = await waitForElementContent('tbody[class^="Calendar-plan-table-view__calendar-tbody"]');
        console.log('Контент в блоке tbody появился:', tbodyElements);
        
        if (tbodyElements && tbodyElements.length > 0) {
          console.log('Блок найден в документе:', tbodyElements[0].outerHTML);

          const amountPalletInputs = document.querySelectorAll('#amountPallet');
          console.log(amountPalletInputs);
          
          if (amountPalletInputs.length > 0) {
            amountPalletInputs.forEach(input => {
              if (!input) {
                console.log('Элемент input является undefined');
                return;
              }
          
              const reactKey = Object.keys(input).find(key => key.startsWith('__reactProps$'));
              
              if (reactKey) {
                const reactProps = input[reactKey];
                console.log('React props:', reactProps);
                
                // Симулируем изменение значения через React
                if (reactProps.onChange && typeof reactProps.onChange === 'function') {
                  console.log('Вызываем onChange');
                  try {
                    const syntheticEvent = {
                      target: input,
                      currentTarget: input,
                      preventDefault: () => {},
                      stopPropagation: () => {},
                      persist: () => {}
                    };
                    input.value = palletCount.toString(); // Устанавливаем значение перед вызовом onChange
                    reactProps.onChange(syntheticEvent);
                  } catch (error) {
                    console.error('Ошибка при вызове onChange:', error);
                  }
                } else {
                  // Если onChange не найден, просто устанавливаем значение
                  input.value = palletCount.toString();
                }
                
                // Вызываем onMouseEnter, если он существует
                if (reactProps.onMouseEnter && typeof reactProps.onMouseEnter === 'function') {
                  console.log('Вызываем onMouseEnter');
                  try {
                    reactProps.onMouseEnter();
                  } catch (error) {
                    console.error('Ошибка при вызове onMouseEnter:', error);
                  }
                }
              } else {
                console.log('React props не найдены для этого элемента');
                // Если React props не найдены, устанавливаем значение напрямую
                input.value = palletCount.toString();
              }
              
              // Генерируем события для DOM
              try {
                // Вызываем событие input для DOM
                const inputEvent = new Event('input', { bubbles: true });
                input.dispatchEvent(inputEvent);
                
                // Вызываем событие change для DOM
                const changeEvent = new Event('change', { bubbles: true });
                input.dispatchEvent(changeEvent);
                
                console.log(`Установлено значение ${palletCount} для инпута amountPallet и вызваны события`);
              } catch (error) {
                console.error('Ошибка при вызове событий:', error);
              }
            });
          } else {
            console.log('Инпуты с id amountPallet не найдены');
          }

          //Остальная логика
          const targetCell = findTargetDateCell(tbodyElements[0], targetDate);
          if (targetCell) {
            console.log('Найдена ячейка с целевой датой:', targetCell.outerHTML);
            
            const reactKey = Object.keys(targetCell).find(key => key.startsWith('__reactProps$'));
            if (reactKey) {
              const reactProps = targetCell[reactKey];
              console.log('React props:', reactProps);
              
              if (reactProps.onMouseEnter && typeof reactProps.onMouseEnter === 'function') {
                console.log('Вызываем onMouseEnter');
                reactProps.onMouseEnter();
                
                await new Promise(resolve => setTimeout(resolve, 500));
                
                const button = targetCell.querySelector('button');
                if (button) {
                  console.log('Найдена кнопка в ячейке:', button.outerHTML);
                  button.click();
                  console.log('Выполнен клик по кнопке в ячейке');
                  
                  // Ждем появления кнопки переноса
                  await new Promise(resolve => setTimeout(resolve, 1000));
                  
                  // Вызываем функцию для поиска и клика по кнопке переноса
                  if (findAndClickTransferButton()) {
                    console.log('Клик по кнопке переноса выполнен успешно');
                    
                    try {
                      // Ждем появления контента в блоке с уведомлениями
                      const notificationElements = await waitForElementContent('div[class^="Notifications-modals-container"]', 15000);
                      if (notificationElements.length > 0) {
                        const notificationText = notificationElements[0].textContent.trim();
                        console.log('Получено уведомление:', notificationText);
                        return notificationText;
                      } else {
                        console.log('Блок с уведомлениями не найден');
                        return false;
                      }
                    } catch (error) {
                      console.error('Ошибка при ожидании уведомления:', error.message);
                      return false;
                    }
                  } else {
                    console.log('Не удалось выполнить клик по кнопке переноса');
                    return false;
                  }
                } else {
                  console.log('Кнопка в ячейке не найдена');
                  return false;
                }
              } else {
                console.log('onMouseEnter не найден или не является функцией');
                return false;
              }
            } else {
              console.log('React props не найдены');
              return false;
            }
          } else {
            console.log('Ячейка с целевой датой не найдена');
            return false;
          }
          
        } else {
          console.log('Блок tbody не найден в документе');
          return false;
        }
      } catch (error) {
        console.error('Произошла ошибка:', error.message);
        return false;
      }
    } else {
      console.log('Не найдена кнопка без класса danger, пропускаем этот элемент');
    }
  }
  console.log('Подходящая кнопка не найдена во всех проверенных элементах');
  return false;
}

async function executeTransfer(date, palletCount) {
  const result = await findClickAndWait(date, palletCount);
  window.globalTransferResult2 = result;  // Сохраняем результат в глобальную переменную window
  console.log('Результат выполнения:', result);
  return result;
}

// Обновленная функция для запуска процесса переноса
function startTransfer(date, palletCount) {
  executeTransfer(date, palletCount).then(() => {
    console.log('Перенос завершен. Глобальный результат:', window.globalTransferResult2);
    // Здесь можно добавить дополнительную логику или вызовы функций,
    // которые должны выполниться после завершения переноса
  }).catch(error => {
    console.error('Произошла ошибка при выполнении переноса:', error);
    window.globalTransferResult2 = false;
  });
}

// Использование:
//ПОДСТАВИТЬ ПЕРЕМЕННЫЕ
startTransfer('{-Variable.dateText-}');
 

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