Подтвердить что ты не робот

403 Запрещено с Java, но не с веб-браузером?

Я пишу небольшую программу Java, чтобы получить количество результатов для данного поискового запроса Google. По какой-то причине в Java я получаю запрет 403, но я получаю правильные результаты в веб-браузерах. Код:

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.URL;


public class DataGetter {

    public static void main(String[] args) throws IOException {
        getResultAmount("test");
    }

    private static int getResultAmount(String query) throws IOException {
        BufferedReader r = new BufferedReader(new InputStreamReader(new URL("https://www.google.com/search?q=" + query).openConnection()
                .getInputStream()));
        String line;
        String src = "";
        while ((line = r.readLine()) != null) {
            src += line;
        }
        System.out.println(src);
        return 1;
    }

}

И ошибка:

Exception in thread "main" java.io.IOException: Server returned HTTP response code: 403 for URL: https://www.google.com/search?q=test
    at sun.net.www.protocol.http.HttpURLConnection.getInputStream(Unknown Source)
    at sun.net.www.protocol.https.HttpsURLConnectionImpl.getInputStream(Unknown Source)
    at DataGetter.getResultAmount(DataGetter.java:15)
    at DataGetter.main(DataGetter.java:10)

Почему это делается?

4b9b3361

Ответ 1

Вам просто нужно установить заголовок пользовательского агента, чтобы он работал:

URLConnection connection = new URL("https://www.google.com/search?q=" + query).openConnection();
connection.setRequestProperty("User-Agent", "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.11 (KHTML, like Gecko) Chrome/23.0.1271.95 Safari/537.11");
connection.connect();

BufferedReader r  = new BufferedReader(new InputStreamReader(connection.getInputStream(), Charset.forName("UTF-8")));

StringBuilder sb = new StringBuilder();
String line;
while ((line = r.readLine()) != null) {
    sb.append(line);
}
System.out.println(sb.toString());

SSL был прозрачно обработан для вас, как это видно из вашего исключения stacktrace.

Получение суммы результата на самом деле не так просто, но после этого вы должны подделать, что вы являетесь браузером, извлекая файл cookie и анализируя ссылку на токен перенаправления.

String cookie = connection.getHeaderField( "Set-Cookie").split(";")[0];
Pattern pattern = Pattern.compile("content=\\\"0;url=(.*?)\\\"");
Matcher m = pattern.matcher(response);
if( m.find() ) {
    String url = m.group(1);
    connection = new URL(url).openConnection();
    connection.setRequestProperty("User-Agent", "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.11 (KHTML, like Gecko) Chrome/23.0.1271.95 Safari/537.11");
    connection.setRequestProperty("Cookie", cookie );
    connection.connect();
    r  = new BufferedReader(new InputStreamReader(connection.getInputStream(), Charset.forName("UTF-8")));
    sb = new StringBuilder();
    while ((line = r.readLine()) != null) {
        sb.append(line);
    }
    response = sb.toString();
    pattern = Pattern.compile("<div id=\"resultStats\">About ([0-9,]+) results</div>");
    m = pattern.matcher(response);
    if( m.find() ) {
        long amount = Long.parseLong(m.group(1).replaceAll(",", ""));
        return amount;
    }

}

Запустив полный код, я получаю 2930000000L в результате.

Ответ 2

Вероятно, вы не устанавливаете правильные заголовки. Используйте LiveHttpHeaders (или эквивалент) в браузере, чтобы узнать, какие заголовки отправляются браузером, затем эмулируйте их в своем коде.

Ответ 3

Это потому, что сайт использует SSL. Попробуйте использовать HTTP-клиент Джерси. Вам, вероятно, также придется немного узнать о HTTPS и сертификатах, но я думаю, что Джерси может сделать ставку, чтобы игнорировать большинство деталей, относящихся к реальной безопасности.