web-dev-qa-db-fra.com

403 Interdit avec Java mais pas navigateur Web?

J'écris un petit programme Java pour obtenir le nombre de résultats pour un terme de recherche Google donné. Pour une raison quelconque, j’obtiens un 403 Forbidden en Java mais j’obtiens les bons résultats dans les navigateurs Web. Code:

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;
    }

}

Et l'erreur:

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)

Pourquoi ça fait ça?

39
Doorknob

Il vous suffit de définir l’en-tête de l’agent utilisateur pour que cela fonctionne:

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());

Le protocole SSL a été traité de manière transparente pour vous comme vous pouvez le voir sur votre pile de traces d’exceptions.

Obtenir le montant du résultat n’est pas si simple, après cela, vous devez simuler que vous êtes un navigateur en récupérant le cookie et en analysant le lien de jeton de redirection.

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;
    }

}

En cours d'exécution le code complet je reçois 2930000000L en conséquence.

83
Esailija

Vous ne définissez probablement pas les bons en-têtes. Utilisez LiveHttpHeaders (ou l’équivalent) dans le navigateur pour voir les en-têtes qu’il envoie, puis les émuler dans votre code.

2
Kevin Day

C'est parce que le site utilise SSL. Essayez d’utiliser le client HTTP Jersey. Vous devrez probablement également en savoir un peu plus sur HTTPS et les certificats, mais je pense que Jersey peut parier de manière à ignorer la plupart des détails relatifs à la sécurité réelle.

0
user785262

Pour moi, cela a fonctionné en ajoutant l'en-tête: "Accepter": "*/*"

0
rpajaziti