Delphi - Pobieranie źródła strony

1

Witam. Mogę śmiało powiedzieć, że przeszukałem całe forum i nie znalazłem odpowiedzi na moje pytanie, dlatego piszę posta. Szukam od kilku dni. Chciałbym za pomocą IdHttp pobrać źróło strony wyszukiwania w Google.pl. Konkretnie chodzi o taką stronę:

http://www.google.pl/search?q=DW0504&hl=pl&client=opera&rls=pl&prmd=i&source=lnt&tbs=lr:lang_1pl&lr=lang_pl&sa=X&ei=ny7dTN3LFMuHhQflm4y_DQ&ved=0CAYQpwU

Przy każdej próbie pobrania źródła program wyrzuca błąd: "Invalid argument to data encode". Gdybym robił to w podstawowy sposób, to ok, ale używam takiego kodu:

 
var
odp:TStringStream;
begin
odp:=TStringStream.Create;
IdHttp.Request.UserAgent:='Opera/7.11 (Windows NT 5.1; U) [pl]';
IdHttp.HandleRedirects:=True;

IdHttp.Get('http://www.google.pl/search?q=DW0504&hl=pl&client=opera&rls=pl&prmd=i&source=lnt&tbs=lr:lang_1pl&lr=lang_pl&sa=X&ei=ny7dTN3LFMuHhQflm4y_DQ&ved=0CAYQpwU', odp); 


Memo1.Text:=odp.DataString;
odp.Free;
end;

Jeśli ktoś zna sposób na pozbycie się tego błędu to proszę o pomoc.

P.S. Wcześniej używałem WebBrowser'a do pobierania źródła (Pobrać źródło różnych wyszukań Google muszę wiele razy w programie) i po pobraniu jednego źródła, potem zawsze pobierał to samo źródło (tej samej strony).

0

W Indy 10 (kompilowane w Delphi 7) działa .

0

Delphi (zresztą nie tylko ono) ma taką magiczną rzecz jak DEBUGER. Po pierwsze w której linijce Ci to wyskakuje, a po drugie przed tą linijką posprawdzaj jaką wartość mają zmienne.
Na 99% wyskakuje to w Memo1.Text:=odp.DataString; Jeśli tak to zapisz sobie tego StringStream do pliku i zobacz jak to tam wygląda.
A jeśli błąd występuje linijkę wcześniej to zamień TStringStream na TMemoryStream

0

Dzieki panowie za odpowiedzi. Misiekd niestety, nic nie dziala. A blad, wystepuje w linijce z Idhttp.Get za kazdym razem. Nie wazne czy uzywam MemoryStream czy zapisuje do pliku. Tam jest blad za kazdym razem. Mam Delphi 7 Enterprise. Tam zdaje sie jest Indy 9. Ale czy nie ma innego rozwiazania niz instalacja nowszego indy?

0

Jeżeli przeinstalowanie Indy nic nie da, a Twoj kod na pewno jest
prawidłowy, to sprawdza się moja teoria że Indy jest zawodne, w
takim przypadku może spróbuj Synapse. Wielu haterów, ktorzy tu
sami prawie nic nie piszą i nie pomagają, zarzuca mi że ów pakiet
po prostu uwielbiam. Ale taka prawda mam w swoim Delphi Indy,
no i to chyba 9, bo w jakiejś 10tce nie działało na przyklad wcale
wznawianie przy pobieraniu z FTPa - jednak kiedy mam w kodzie,
coś pobrać z www to korzystam z Synapse. I taki pro jak Misiekd
też używa tego pakietu i mnie przekonał. Używam do HTTP, FTP i
obslugi POP3 oraz SMTP. Przykłady masz w google. A sam pakiet
posiada jako taką dokumentacje oraz dołączone kilka przykładów
użycia. Także jeżeli z Indy nie idzie to może sprobuj Synapse, no
ale nie namawiam, bo haterzy mnie zaszlachtują. Zrobisz to - co
chcesz, bo niestety Synapse ma jedną wadę, nie działa od Delphi
2009 wzwyż. Jednak poniższy kod działa. Pokazal mi to Misiekd w
jakimś swoim kodzie, bo nie umialem też łatwo zapisać tekstu - z
TMemoryStram jakim jest Document w Synapse do string, robiłem
to wczytując go do TStringList. Ale sprawdziłem ten kod działa i
używam najnowszej Opery dlatego lepiej podać nowy UserAGent.

//...
uses
  httpsend;

procedure TForm1.Button1Click(Sender: TObject);
const
  Opera_UserAgent = 'Opera/9.80 (Windows NT 5.1; U; pl) Presto/2.6.30 Version/10.63';
var
  Reply : string;
  Http : THttpSend;
begin
  Http := THttpSend.Create;
  Http.UserAgent := Opera_UserAgent;
  Http.HTTPMethod('GET', 'http://www.google.pl/search?q=DW0504&hl=pl&client=opera&rls=pl&prmd=i&source=lnt&tbs=lr:lang_1pl&lr=lang_pl&sa=X&ei=ny7dTN3LFMuHhQflm4y_DQ&ved=0CAYQpwU');
  SetLength(Reply, Http.Document.Size);
  Http.Document.Write(Pointer(Reply)^, Length(Reply));
  Memo1.Text := Reply;
  Http.Free;
end;
0

olesio, Wielkie dzieki za wyczerpujacego posta. Jesli nie znajde sposobu na to indy to pewnie skorzystam z kodu ktory podales. Tylko powiedz.. Jak to jest z szybkoscia tego synapse? bo kod ktory podales nie wyglada na superszybki. A w moim programie ten kod bede musial wykonac ok. 150 razy, wiec zalezy mi troche na czasie.

Sprawdzilem twoj kod. niestety ale tylko czysci mi memo. Poczatkowo jest tam Memo1 a jak wykonam kod to nic nie ma w memo. Nie wiesz o co chodzi olesio?

Ok. Juz mam. W twoim kodzie powinno byc READ zamiast WRITE. jak to jest to pobiera kod:)

Po sprawdzeniu kodu pobranego przez synapse stwierdzam ze nie jest to to o co mi chodzilo. Program pobral kilka obszernych skryptow JS googli i nic poza tym. praktycznie zadnego html'a

Okey, znalazlem rozwiazanie. UserAgent sie nie zgadzal. U mnie potrzebny jest taki:
const
Opera_UserAgent = 'Opera/7.11 (Windows NT 5.1; U) [pl]';

Teraz problemem sa przekierowania. pobiera mi zrodlo strony i poza podstawowymi znacznikami jest tam tylko napis: "The document has been moved". W indy bylo cos takiego jak HandleRedirects. Jak sie to ustawilo na TRUE to wszystko gralo. Ale tutaj na razie nie wiem jak sobie poradzic. Ktos, cos?

Ok znalazlem taki oto kod Miskad do tych przekierowac. Moze komus sie przyda:

    with http do
    BEGIN
    if httpMethod('POST', 'http://www.google.pl/search?q='+models[0,a]+'&hl=pl&client=opera&rls=pl&prmd=i&source=lnt&tbs=lr:lang_1pl&lr=lang_pl&sa=X&ei=ny7dTN3LFMuHhQflm4y_DQ&ved=0CAYQpwU') then
    begin
      while ResultCode = 302 do
      begin
        for i := 0 to Headers.Count - 1 do
        begin
          redirPos := Pos('Location: ', Headers[i]);
          if redirPos > 0 then
          begin
            redirUrl := Copy(Headers[i], redirPos + Length('Location: '), MaxInt);
            Headers.Clear;
            if not HTTPMethod('GET', redirUrl) then
            begin

              Exit;
            end;

            Break;
          end;
        end;
      end;
  end;
  END;
 

Jak go zastosowalem to dostalem kod googli, gdzie pelno bylo wstawek typu: "ERR" i nic konkretnego. 2 linie kodu html

0

lolert1221: musisz myśleć co robisz. Kod który wkleiłeś później jest też
pewnie z moich postów, ale zobacz jaki masz na początku parametr dla
HttpMethod. Masz tam 'POST', a nie 'GET' stąd pewnie te błędy. Jeżeli
do jakiejś strony chcesz podesłać jakieś dane POSTem - to musisz mieć
je zapisane w zmiennej Document. Dodatkowo zmienna MimeType, dla
większości stron przy wysyłaniu POSTem powinna wyglądać choćby tak:

  Http.MimeType := 'application/x-www-form-urlencoded';

Dalej upieram się, że podajesz bardzo starą Operę. Dla google śmiało w
UserAgent powinieneś podać najnowszą wersję. Także zmień to: 'POST'
na 'GET' i powinno zadziałać. Co do szybkości Synapse to śmiem nawet
stwierdzić, że jest ciutke szybsze od Indy, ale dokładnych testow jakoś
nie robiłem. Wiem, że korzysta z WinSocka, a nie jak jakieś tam twory
w stylu UrlDownloadToFile z silnika IE, także jest niezależna od IE albo
innych przeglądarek. Nie obsluguje JavaScriptu, ale wiadomo Indy też.
A i teraz wiem dlaczego kod jeszcze może nie działać. Powinno być nie
Write ale Read, bo odczytujemy zmienną do MemotyStreama. Bo Write
używane jest właśnie przy POST kiedy chcemy do Document - szybko
zapisać zmienną typu sttring. Widzisz, myślałem, że uważniej patrzysz
na kod, a nie bezmyślnie wklejasz - mi też się mogą zdażyć pomyłki ;/
A i dla tak szybkiej strony jak google, na łaczu UPC 25 Megabitów ten
kod jak sprawdziłem wykonuje się tak srednio 390 milisekund, uważam
że jest to bardzo szybko. Zauważalnie to szybciej się chyba nie da :)

//...
uses
  httpsend;

procedure TForm1.Button1Click(Sender : TObject);
const
  Opera_UserAgent = 'Opera/9.80 (Windows NT 5.1; U; pl) Presto/2.6.30 Version/10.63';
var
  Http : THttpSend;
  I, redirPos : integer;
  Stop, Start : Cardinal;
  Reply, RedirUrl : string;
begin
  Start := GetTickCount;
  Http := THttpSend.Create;
  try
    Http.UserAgent := Opera_UserAgent;
    Http.HTTPMethod('GET', 'http://www.google.pl/search?q=DW0504&hl=pl&client=opera&rls=pl&prmd=i&source=lnt&tbs=lr:lang_1pl&lr=lang_pl&sa=X&ei=ny7dTN3LFMuHhQflm4y_DQ&ved=0CAYQpwU');
    SetLength(Reply, Http.Document.Size);
    with Http do
    begin
      while (ResultCode = 301) or (ResultCode = 302) do
      begin
        for i := 0 to Headers.Count - 1 do
        begin
          redirPos := Pos('Location: ', Headers[i]);
          if RedirPos > 0 then
          begin
            RedirUrl := Copy(Headers[i], RedirPos + Length('Location: '), MaxInt);
            Headers.Clear;
            HTTPMethod('GET', RedirUrl);
            Break;
          end;
        end;
      end;
      SetLength(Reply, Document.Size);
      Document.Read(Pointer(Reply)^, Length(Reply));
      Memo1.Text := Reply;
    end;
  finally
    Http.Free;
  end;
  Stop := GetTickCOunt;
  ShowMessage('Operacja trwałą (ms): ' + IntToStr(Stop - Start));
end;
0

No dzieki olesio. Sprobuje z tym kodem co teraz podales. ale nie oskarzaj mnie ze bezmyslnie wklejam kod. przeciez te poprawki ktore mi wymieniles napisalem w edicie mojego posta. Jest tam napisane o bledzie z write, o useragent i o wszystkim innym

0

No ok, ale POST'a nie zauwżyłeś. Chyba, że chcesz jakieś dane słać POSTem,
jednak wtedy musisz dane do wysłania zapisac w zmiennej Document. A kod,
ktory wkleiłem powyżej, po poprawkach na pewno działa, bo go sprawdziłem.

0

Okey. Program zwraca juz zrodlo googli, tylko ze w strasznym formacie. jest to chyba 8 linii kodu tak cholernie dlugich ze szkoda gadac. da sie to jakos zmienic? bo mam specjalna funkcje napisana, ktora z tego kodu wyciaga wszystkie linki jakie znalazlo, a jak caly kod to 8 linii to wszystko sie posypalo...

0

Czy na forum jest ktoś kto potrafilby podac kod do pobierania zrodla strony wyszukiwania w google w normalnej postaci (czyli takiej jak jest po kliknieciu na prawym przycisku na stronie i wybraniu "Źródło strony..."? Prosze o pomoc bo juz nie wiem co robic..

0

Po pierwsze nie musisz spamować mi Prywatnych wiadomości, ja to forum dosyc
regularnie czytam - wiadomości prywatne można na tym forum łatwo przeoczyć.
Po drugie, to po co double post. Przecież prędzej czy później odpiszę Tobie, bo
w dziale Delphi czytam zawsze wszystkie posty i jak umiem i moge to pomagam
jak sam widzisz. Wszystko co masz zrobić masz opisane poniżej. Chociaż raczej
widze, że cały program piszę za Ciebie, a w ten sposób to nic się nie nauczysz,
bo nic nie szukasz. Format zwracanej strony jest taki jak widać, bo to chyba od
serwera zależy albo tak jest strona zakodowana. Co do wyciągnięcia linków, to
co z tego że tekst nie jest w linijkach? Przecież do sparsowania tekstu, takiego
jak ten kod html i wyciągnięcia linków używa się Wyrażen Regularnych. Ja sam
kiedyś robiłem ten błąd i jakimiś funkcjami ExtractValue wyciągałem z kodu od
jakiś stron, korzystając z gotowca znalezionego na forum Experts Exchange ;/
Jednak później naprowadzil mnie jeden user z forum U1. Ale nawet jak nie, to
przecież temat Wyrażen Regularnych - był tutaj jak i w Internecie bardzo dużo
razy wałkowany. Z: http://www.mediafire.com/file/czhw3mmzjyn/regexpr.rar
pobierzesz sobie potrzebny moduł. Resztę załatwi poniższy kod. Tylko zbytnio
nie wiem dlaczego przy wywołaniu strony takiej jak podałeś za drugim razem,
jak kliknie w button mam nieco inne wyniki, ale może tak działa serwer, bo to
na pewno nie wina kodu ani Synapse. Synapse nie ma cache'u jakiegoś, lecz
nawet jakby miala tak jak komponenty korzystające z IE - to na pewno, przy
konstruktorze wywołanym na nowo nie ma wcale takich danych ustawionych.

//...
uses
  httpsend, regexpr;

function KombinujCokolwiekSamodzielnie(AInputString : string) : string;
var
  R : TRegExpr;
begin
  Result := '';
  R := TRegExpr.Create;
  try
    R.Expression := 'class="r"><a href="(.+?)" class=l>';
    if R.Exec(AInputString) = True then
    begin
      repeat
        Result := Result + R.Match[1] + #13#10;
      until R.ExecNext = False;
    end;
    Delete(Result, Length(Result) - 1, 2);
  finally
    R.Free;
  end;
end;

procedure TForm1.Button1Click(Sender : TObject);
const
  Default_MimeType = 'application/x-www-form-urlencoded';
  Opera_UserAgent = 'Opera/9.80 (Windows NT 5.1; U; pl) Presto/2.6.30 Version/10.63';
var
  Http : THttpSend;
  I, redirPos : integer;
  Reply, RedirUrl : string;
begin
  Http := THttpSend.Create;
  try
    with Http do
    begin
      KeepAlive := True;
      Protocol := '1.1';
      MimeType := Default_MimeType;
      UserAgent := Opera_UserAgent;
      HTTPMethod('GET', 'http://www.google.pl/search?q=DW0504&hl=pl&client=opera&rls=pl&prmd=i&source=lnt&tbs=lr:lang_1pl&lr=lang_pl');
      while (ResultCode = 301) or (ResultCode = 302) do
      begin
        ShowMessage('aaa');
        for i := 0 to Headers.Count - 1 do
        begin
          redirPos := Pos('Location: ', Headers[i]);
          if RedirPos > 0 then
          begin
            RedirUrl := Copy(Headers[i], RedirPos + Length('Location: '), MaxInt);
            Headers.Clear;
            HTTPMethod('GET', RedirUrl);
            Break;
          end;
        end;
      end;
      SetLength(Reply, Document.Size);
      Document.Read(Pointer(Reply)^, Length(Reply));
    end;
  finally
    Http.Free;
  end;
  Memo1.Text := KombinujCokolwiekSamodzielnie(Reply);
end;

1 użytkowników online, w tym zalogowanych: 0, gości: 1