2012-12-02 10 views
37

Piszę mały program Java, aby uzyskać wyniki dla danego wyszukiwanego hasła. Z jakiegoś powodu w Javie dostaję 403 Forbidden, ale otrzymuję właściwe wyniki w przeglądarkach internetowych. Kod:403 Zabrania się używania Javy, ale nie przeglądarki internetowej?

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

} 

i błąd:

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) 

Dlaczego to robi?

+0

może mieć coś wspólnego z sesjami? – kishu27

+0

Dlaczego używasz punktu końcowego SSL? – Perception

+0

@Perception um ... jaki jest punkt końcowy SSL? (przepraszam, nie mam pojęcia o takich rzeczach) – Doorknob

Odpowiedz

68

Trzeba tylko ustawić nagłówek agenta użytkownika do jego pracy:

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 był przejrzysty obsługiwane dla Ciebie, jak można było zobaczyć z stacktrace wyjątków.

Uzyskanie kwoty wyniku nie jest tak proste, jednak musisz sfałszować, że jesteś przeglądarką, pobierając plik cookie i analizując link tokenu przekierowania.

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

} 

Running the full code uzyskać 2930000000L wyniku.

+0

Stary, jestem ci winien beczkę piwa, to jest idealne rozwiązanie mojego problemu! Czy Google może ograniczyć/ograniczyć wyniki za pomocą tej metody? – gudthing

+0

@Gudthing throttling jest oparte na ip, więc nie chodzi o metodę, ale o to, czy zmienisz swoje IP :-) – Esailija

+0

Rozumiem! Prosty restart routera (dla zmiany WAN) rozwiąże problem :). Dzięki jeszcze raz!! – gudthing

1

Prawdopodobnie nie ustawiasz poprawnych nagłówków. Użyj LiveHttpHeaders (lub odpowiednika) w przeglądarce, aby zobaczyć, jakie nagłówki wysyła przeglądarka, a następnie emuluj je w swoim kodzie.

+0

Próbowałem '" https://www.google.com/search?q= "+ query +" & rlz = 1C1RNNN_enUS371 & aq = f & oq = "+ query +" & sugexp = chrome, mod = 6 & sourceid = chrome & ie = UTF-8 "' , nadal nie działa – Doorknob

+0

@PicklishDoorknob dodałeś parametr ciąg zapytania, nie zmieniłeś nagłówków. Możesz ustawić nagłówki z '.setRequestProperty()' na obiekcie 'URLConnection' – Esailija

+0

Oto artykuł SO, który mówi o dodawaniu nagłówków żądań: http://stackoverflow.com/questions/480153/how-to-modify-the-header -of-a-httpurlconnection –

0

To dlatego, że witryna korzysta z protokołu SSL. Spróbuj użyć klienta HTTP firmy Jersey. Prawdopodobnie będziesz musiał również dowiedzieć się trochę o HTTPS i certyfikatach, ale sądzę, że Jersey może postawić zakład, aby zignorować większość szczegółów dotyczących faktycznego bezpieczeństwa.

+1

Nie, nie działa, działa tylko emulując nagłówki HTTP przeglądarki, takie jak @KevinDay w swojej odpowiedzi. – Esailija

+2

@Ben Brunk - tu jest dobra lekcja - w rdzeniu wszystko programowanie składa się z warstwy po warstwie dodatkowej abstrakcji. Zrozumienie niskiego poziomu jest bardzo przydatne. Używanie klienta o wyższym poziomie, takiego jak ty, może zadziałać - ale tylko dlatego, że wykonuje niskopoziomowe połączenie, które sam możesz wykonać, jeśli zdecydujesz. Nigdy nie zapomnę, jak pouczające było dla mnie usiąść i wejść w interakcję z serwerem sieciowym za pomocą klienta telnet i ręcznie opracować żądanie HTTP. Cheerio! –

+0

Właściwie nadal nie jestem pewien, dlaczego ten kod zadziałał, ponieważ zazwyczaj musisz dodać publiczny certyfikat witryny do lokalnego magazynu kluczy Java, aby używać takiego SSL, nawet z URLConnection, więc coś nie zsumuje tego adresu URL . Co sprawia, że ​​myślisz, że nigdy nie łączyłem się z witryną za pomocą telnetu? Robię to dla życia i często zapominam, że na tej stronie jest wielu ludzi, którzy są studentami lub programistami hobby. Po prostu staram się być hepful. –

Powiązane problemy