Задать вопрос
@cedFlame

Как спарсить данные с помощью 2Captcha и SpringBoot?

Мне нужно спарсить данные со страницы а именно телефон, но засекречен кнопкой "показать телефон" и reCAPTCHA V2

Я решил использовать Selenium, сначала я закрыл всплывающее окно новым гостям страницы, затем нажал кнопку "показать телефон", после чего отправил капчу на API 2Captcha он её решил, я всунул ответ, но телефон не показываеться и вообще капча не решаеться, я не знаю как решить эту проблему(

Вот код:

import lombok.extern.log4j.Log4j;
import org.openqa.selenium.*;
import org.openqa.selenium.chrome.ChromeDriver;
import org.openqa.selenium.logging.LogEntries;
import org.openqa.selenium.logging.LogEntry;
import org.openqa.selenium.logging.LogType;
import org.openqa.selenium.support.ui.ExpectedConditions;
import org.openqa.selenium.support.ui.WebDriverWait;
import org.springframework.stereotype.Component;
import ru.shmatov.telegramwebparser.utils.HttpUtils;

import java.io.IOException;
import java.util.HashMap;
import java.util.Map;

@Component
@Log4j
public class CaptchaSolver {

    private final String twoCaptchaApiKey = "API_KEY";
    private WebDriver driver;

    public CaptchaSolver() {
        System.setProperty("webdriver.chrome.driver",
                System.getProperty("user.dir") + "/src/main/resources/chromedriver");
        this.driver = new ChromeDriver();
    }

    public String solveCaptcha(String url) throws IOException, InterruptedException {
        driver.get(url);

        new WebDriverWait(driver, 15).until(
                webDriver -> ((JavascriptExecutor) webDriver).executeScript("return document.readyState").equals("complete")
        );
        log.debug("Страница загружена");

        try {
            WebElement closeButtonOne = new WebDriverWait(driver, 10)
                    .until(ExpectedConditions.elementToBeClickable(By.className("tutorial__close")));
            closeButtonOne.click();
            log.debug("Закрыто первое всплывающее окно");
        } catch (TimeoutException e) {
            log.debug("Первое всплывающее окно отсутствует.");
        }

        WebElement showPhoneButton = new WebDriverWait(driver, 10)
                .until(ExpectedConditions.elementToBeClickable(By.className("show-phones")));
        showPhoneButton.click();
        log.debug("Нажали кнопку 'Показать телефон'");

        //
        WebElement captchaFrame = new WebDriverWait(driver, 15)
                .until(ExpectedConditions.presenceOfElementLocated(By.cssSelector("iframe[src*='recaptcha/api2/anchor']")));
        String siteKey = captchaFrame.getAttribute("src").split("k=")[1].split("&")[0];
        log.debug("siteKey извлечен: " + siteKey);

        String captchaResponse = sendCaptchaTo2Captcha(siteKey, url);
        if (captchaResponse == null) {
            throw new IllegalStateException("Не удалось получить ответ от 2Captcha.");
        }
        log.debug("Ответ от 2Captcha получен: " + captchaResponse);

        JavascriptExecutor js = (JavascriptExecutor) driver;
        js.executeScript("document.getElementById('g-recaptcha-response').style.display = 'block';");
        js.executeScript("document.getElementById('g-recaptcha-response').value = arguments[0];", captchaResponse);

        js.executeScript("document.getElementById('g-recaptcha-response').dispatchEvent(new Event('change', {bubbles: true}));");
        js.executeScript("document.getElementById('g-recaptcha-response').dispatchEvent(new Event('input', {bubbles: true}));");
        js.executeScript("document.getElementById('g-recaptcha-response').dispatchEvent(new Event('blur', {bubbles: true}));");
        log.debug("Решение капчи вставлено и события вызваны");

        LogEntries logs = driver.manage().logs().get(LogType.BROWSER);
        for (LogEntry entry : logs) {
            log.error("JavaScript error: " + entry.getMessage());
        }

        try {
            WebElement submitButton = driver.findElement(By.cssSelector("button[type='submit']"));
            submitButton.click();
            log.debug("Клик по кнопке подтверждения выполнен.");
        } catch (NoSuchElementException e) {
            log.debug("Кнопка подтверждения не найдена. Продолжаем.");
        }

        try {
            WebElement phoneNumberElement = new WebDriverWait(driver, 30)
                    .until(ExpectedConditions.visibilityOfElementLocated(By.className("offer__contacts-phones")));
            log.debug("Номер телефона получен: " + phoneNumberElement.getText());
            return phoneNumberElement.getText();
        } catch (TimeoutException e) {
            log.error("Телефон не появился на странице. Возможно, капча была отклонена.");
            throw new IllegalStateException("Телефон не отображается после решения капчи.");
        }
    }


    private String sendCaptchaTo2Captcha(String siteKey, String url) throws IOException, InterruptedException {
        Map<String, String> params = new HashMap<>();
        params.put("key", twoCaptchaApiKey);
        params.put("method", "userrecaptcha");
        params.put("googlekey", siteKey);
        params.put("pageurl", url);

        // Отправляем запрос на 2Captcha
        String response = HttpUtils.postForm("http://2captcha.com/in.php", params);
        log.debug("Ответ от 2Captcha (создание задачи): " + response);

        if (!response.startsWith("OK|")) {
            throw new IllegalStateException("Ошибка 2Captcha при создании задачи: " + response);
        }

        // Извлекаем Task ID
        String taskId = response.split("\\|")[1];
        log.debug("Task ID: " + taskId);

        // Ждем результат решения
        Thread.sleep(5000);
        while (true) {
            response = HttpUtils.get("http://2captcha.com/res.php?key=" + twoCaptchaApiKey + "&action=get&id=" + taskId);
            log.debug("Ответ от 2Captcha (проверка результата): " + response);

            if (response.startsWith("OK|")) {
                return response.split("\\|")[1]; // Возвращаем решение капчи
            } else if (response.equals("CAPCHA_NOT_READY")) {
                log.debug("Капча еще не готова, ждем...");
                Thread.sleep(5000);
            } else {
                throw new IllegalStateException("Ошибка 2Captcha: " + response);
            }
        }
    }
}


Вот код утилиты HttpUtils

import okhttp3.*;

import java.io.IOException;
import java.util.Map;

public class HttpUtils {

    private static final OkHttpClient client = new OkHttpClient();

    public static String postForm(String url, Map<String, String> params) throws IOException {
        FormBody.Builder formBuilder = new FormBody.Builder();
        for (Map.Entry<String, String> entry : params.entrySet()) {
            formBuilder.add(entry.getKey(), entry.getValue());
        }

        Request request = new Request.Builder()
                .url(url)
                .post(formBuilder.build())
                .build();

        try (Response response = client.newCall(request).execute()) {
            if (!response.isSuccessful()) {
                throw new IOException("Ошибка HTTP: " + response);
            }
            return response.body().string();
        }
    }

    public static String get(String url) throws IOException {
        Request request = new Request.Builder()
                .url(url)
                .get()
                .build();

        try (Response response = client.newCall(request).execute()) {
            if (!response.isSuccessful()) {
                throw new IOException("Ошибка HTTP: " + response);
            }
            return response.body().string();
        }
    }
}


Код сервиса и кнотроллеры бота не кидаю, они стандартны и настроены правильно
  • Вопрос задан
  • 62 просмотра
Подписаться 1 Средний 1 комментарий
Решения вопроса 1
@andry36
Скорее всего сайт не видит, что капча решена. Само простое «вставить токен в #g-recaptcha-response» редко достаточно. Часто нужно действительно вызвать grecaptcha.execute() или повторить тот JS, который сайт вызывается при реальной проверке (например, по клику на «submit»).

Попробуй понаблюдать в DevTools, что происходит, когда ты вручную разгадываешь капчу: какие сетевые запросы уходят, какие JS-события или функции (onloadCallback, grecaptcha.execute(), onSubmit) вызываются. Затем повтори эти действия в Selenium - не просто пихни токен на страницу, а заставь сайт пройти ровно тот же workflow:
Переключись в нужный iframe (если нужно),
Подставь капча-токен,
Выполни нужные скрипты/клики/сабмиты.
Если сайт использует серверную проверку, то обязательно должен быть запрос с передачей g-recaptcha-response. Без этого сайт даже не узнает, что капча решена. Проверяй, уходит ли он вообще и с каким телом. Обычно этого хватает, чтобы скрытый телефон начал отображаться.
Ответ написан
Пригласить эксперта
Ответы на вопрос 1
azerphoenix
@azerphoenix Куратор тега Spring
Java Software Engineer
Здравствуйте.
Кстати, есть готовый сервис для решения капчи - https://anti-captcha.com/
Сам когда-то очень давно использовал...
Ответ написан
Комментировать
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы
08 янв. 2025, в 01:41
300 руб./за проект
08 янв. 2025, в 00:29
5000 руб./за проект