Problem z zapisaniem żródła strony w Delphi

0

Witam. Piszę program w Delphi który będzie wspólpracował z innym programem. Zadaniem mojego jest zapisanie żródła strony do pliku .txt. Mam już wszystko, tylko pojawia się pewien problem a mianowicie chodzi o to, że gdy źródło zapisuje się do notatnika większość zostaje wyrównana do lewej strony. Tak być niestety nie może, do pliku .txt żródło musi trafić w oryginalnej postaci (tak jakby zrobić to ręcznie). Mam screany do zobrazowania mojego problemu: tak mi wychodzi - http://zapodaj.net/a132a07f39fa.jpg.html, a powinno być tak - http://zapodaj.net/ed28798c80e7.jpg.html.

Źródło pobieram i zapisuje jednym buttonem, mam taki kod:

procedure TForm1.Button3Click(Sender: TObject);
var
  TF : TextFile;
begin
  AssignFile(TF, 'C:\dane.txt');
    try
      Append(TF);
      Writeln(TF, WebBrowser1.OleObject.Document.documentElement.innerHTML);

    finally
      CloseFile(TF);

end;

Próbowałem też na dwa buttony, czyli pierwszy odczytywał żródło i zapisywał w memo a drugi czytał z memo i zapisywał do notatnika. Z Write zamist Writeln to samo. Zawijanie wierszy w notatniku nie ma wpływu. Kombinowałem na różne sposoby i zawsze z tym samym rezultatem. Szukałem podobnego problemu ale niestety nic nie znalazłem.
Może jak się wyśpię to mi coś do głowy wpadnie, ale póki co dobre rady mile widziane. Z góry dzięki za pomoc :)

0

use streams luck

0

Mógłbyś to troszeczke rozwinąć? Próbowałem na strumieniach ale zapisywało mi wszystko w jednym ciągu.
Wzorowałem sie chyba na tym kodzie:

procedure TMainForm.btnSaveClick(Sender: TObject);
var
  S : TFileStream;
begin
{ zapisz plik }
  S := TFileStream.Create('dane', fmCreate);
  S.WriteComponent(edtValue); // zapisz dane
  S.Free;
end;

ale pewny nie jestem bo ciągle coś zmieniam, próbuje na różne sposoby i nadal nic :/

Dodam, że już sporo czasu minęło od mojego ostatniego programu. Kilka lat do tyłu to miałem tego dość w lic, ale teraz mnie to zafascynowało :)
Niestety praktycznie musze sobie wszystko przypominać od początku, praktycznie nic mi w głowie z tego nie zostało... dlatego prosiłbym o odpowiadanie pełnymi zdaniami tak żebym zrozumiał o co biega ;)

0

ale jeśli kod strony jest zwracany ciągiem to inaczej go nie zapiszesz

0

No na strumieniach wychodziło ciągiem, ale tym pierwszym sposobem było dość blisko. Około 10% źródła zapisywało prawidłowo a później tak jakby zjadało wszystkie wcięcia akapitów i wyrównywało do lewej strony... Najgorsze jest to, że bardzo mi zależy aby źródło zapisywało sie w oryginalnej formie. Jeśli mi to nie wyjdzie to lipa :/

0

a z innej beczki dlaczego przez webbrowser a nie pobierając źródło przez indy, synapse, ics czy co tam masz? WB generalnie źródło strony traktuje po swojemu

BTW tu masz jakieś kody dla WB
http://delphi.about.com/od/twebbrowser/a/save-as-mht.htm
http://www.delphidabbler.com/articles?article=14&part=1

0

No kurde nie wychodzi mi. Jutro przestudiuje dobrze Indy, bo dzisiaj tak na szybko patrzyłem i mi jakieś błędy wyskakiwały jak próbowałem zapisać źródło, choć program sam z siebie startował. Widocznie musiałem czegoś nie napisać w kodzie...
Chyba, że ktoś ma chęci i wie jak zrobić żeby zapisywało źródło strony na której sie w danym momencie znajduje to może mi pomóc, naprowadzić bo mi się już miesza wszystko...

Ewentualnie napisze inny program, ktory bedzie obslugiwal tak zapisane źródło jak mi to wychodziło na początku z wykorzystaniem WB. Tylko prosiłbym o wytłumaczenie jak mam przechwytywać dane z notatnika które mnie interesuja czyli pomiędzy wszystkimi <TR> a </TR> ale tylko z kilku wybranych <TD>|</TD>.
Na csreanie widać o co chodzi.
Na dziś mam już dość, jutro będzie następny dzień walki ;)

0

Ja jak Misiekd polecam źródło strony wczytywać przy użyciu Indy lub Synapse. I nie wiem jak jest w Indy, bo bardzo rzadko używam, ale jeżeli nie masz ustawionego konkretnego UserAgenta to nawet dane tekstowe z FaceBooka są odczytywane bez wcięć i znaków nowej linii. Jak ustawiłem na Operę to wszystko wygląda po zapisie do własności Document (w Synapse i THttpSend Document jest typu TMemoryStream) tak jak należy. A pod poniższym linkiem jest wątek gdzie kAzek jakiemuś leniowi podaje przykład pobrania źródła strony do zmiennej typu string: Wysyłanie zapytań WWW

0

Ok, czesciowo udalo mi sie to dzieki Synapse. Dlaczego czesciowo? otoz problem pojawia sie gdy chce pobrac zrodlo strony do ktorej dostep uzyskuje sie po zalogowaniu. Wtedy pobiera mi sie zrodlo strony logowania. A wiec aby to obejsc musze zrobic jakies autologowanie?
Teraz probowalem zrobic tak, ze wchodze na strone ktora mnie interesuje (wymaga logowania) i zrodlo ma sie pobrac ze strony na ktorej sie obecnie znajduje. Niestety pobiera sie ze strony logowania tak jakby nie uzyskiwalo dostepu...
Moze pokaze kod i zobaczycie co tam namodzilem ;)

procedure TForm1.Button2Click(Sender: TObject);

 const
  Opera_UserAgent = 'Opera/9.80 (Windows NT 6.1; U; pl) Presto/2.7.62 Version/11.01';
var
  Reply : string;
  Http : THttpSend;
begin
  Http := THttpSend.Create;
  Http.UserAgent := Opera_UserAgent;
  Http.HTTPMethod('GET', WebBrowser1.LocationURL);
  SetLength(Reply, Http.Document.Size);
  Http.Document.Read(Pointer(Reply)^, Length(Reply));
  Memo1.Text := reply;
  Http.Free;
end;

I chyba też to sie pobiera w ciagu, ale czytalem gdzies jak to zrobic to moze mi sie uda :)
Wazne w tej chwili zebym mogl jakos dobrac sie do strony ktora mnie interesuje ;)

0

Logowanie do stron przeprowadza się na ogół przy użyciu metody POST. Jakie dane wysyłane są tą metodą do serwera można podejrzeć jeżeli połączenie nie jest szyfrowane pod snifferami, ja polecam dość prosty WireShark (jak go używać pokazują tutoriale na YT). Poniżej przykład jak logować się na naszą klasę. Funkcja HttpAction przerobiona na podstawie kodu, który kiedyś zasugerował mi Misiekd. Funkcja SimpleParse jest również jego autorstwa i wyciąga z kodu strony pewne dane. Oczywiście logowanie na wiele stron jest indywidualne, najlepiej WireSharkiem wcześniej trzeba prześledzić co jest i pod jaki adres wysyłane. Jeżeli po wysyłaniu metodą POST w zmiennej Document nic nie ma (ma ona rozmiar 0) to znaczy że są jeszcze jakieś dodatkowe przekierowania, które trzeba obsłuzyć. Czasami, jak w przypadku FaceBooka, aby się zalogowac trzeba odwiedzić wcześnej metodą GET stronę główną aby uzyskać odpowiednie ciasteczka. Większośc zmiennych użytych tutajk jak FPage czy FUrl są oczywiście typu string i zadeklarowano je w sekcji public formatki głownej, jak i wspomniane funkcje. Natomiast SynHttp to obiekt typu THttpSend z modułu httpsend, który jest oczywiście kiedy trzeba tworzony, a kiedy już niepotrzebny zwalniany. Mam nadzieję, że kod poniższy coś Tobie podpowie. Często logowanie do wielu serwisów to tylko kwestia odpowiedniego wysłania metodą POST danych podstawionych w zmiennej typu string. Nie trzeba do tego tworzyć osobnej funkcji jak tutaj, ale czasami jak schemat się powtarza do kilku zadan to można tak sobie ułatwić. Czasami taka funkcja nie przydaje się, bo trzeba zrobić na przykład po POST, kolejny POST na inną stronę. A i jakbyś stwierdzil, że masz w zwróconym kodzie informacje o BAD REQUEST albo coś w tym stylu, to na ogół pomaga na to czyszczenie nagłowków przez Headers.Clear, tak jak widać w poniższym kodzie, bo inaczej nie chce działać. Oczywiście poniższy kod to tylko pewien fragment pewnego programu. Podaje w celach edukacyjncyh żeby Ciebie naprowadzić jak można się logować na stronę.

//...
type
  THttpAction = (acGet, acPost);
//...
const
  Redir_C = 'Location: ';
  Referer_C = 'Referer: ';
  Base_Url = 'http://nk.pl/';
  Default_MimeType = 'application/x-www-form-urlencoded';
  Opera_UserAgent = 'Opera/9.80 (Windows NT 5.1; U; pl) Presto/2.7.62 Version/11.01';
//...
function SimpleParse(StrBegin, StrEnd, Str : string) : string;
var
  B, E : integer;
begin
  Result := '';
  if StrBegin = '' then
  begin
    B := 1;
  end
  else
  begin
    B := Pos(StrBegin, Str);
  end;
  if B > 0 then
  begin
    Str := Copy(Str, B + Length(StrBegin), MaxInt);
    if StrEnd = '' then
    begin
      E := Length(Str) + 1;
    end
    else
    begin
      E := Pos(StrEnd, Str);
    end;
    if E > 0 then
    begin
      Result := Copy(Str, 1, E - 1);
    end;
  end;
end;
//...
procedure TMainForm.HttpAction(WhatAction : THttpAction; Encode, InsertHeader : boolean);
var
  I, RedirPos : integer;
  Action, RedirUrl : string;
begin
  case WhatAction of
    acGet : Action := 'GET';
    acPost : Action := 'POST';
  end;
  with SynHttp do
  begin
    Headers.Clear;
    Document.Clear;
    KeepAlive := True;
    Protocol := '1.1';
    if InsertHeader = True then
    begin
      Headers.Insert(0, Referer_C + FRefererUrl);
    end;
    MimeType := Default_MimeType;
    UserAgent := Opera_UserAgent;
    Document.Write(PChar(FStrData)^, Length(FStrData));
    if HTTPMethod(Action, FUrl) = True then
    begin
      while (ResultCode = 301) or (ResultCode = 302) do
      begin
        for I := 0 to Headers.Count - 1 do
        begin
          RedirPos := Pos(Redir_C, Headers[I]);
          if RedirPos > 0 then
          begin
            RedirUrl := Copy(Headers[I], RedirPos + Length(Redir_C), MaxInt);
            if Pos('http://', RedirUrl) <> 1 then
            begin
              RedirUrl := Base_Url + RedirUrl;
            end;
            Headers.Clear;
            if HTTPMethod(Action, RedirUrl) = False then
            begin
              Exit;
            end;
            Break;
          end;
        end;
      end;
      SetLength(FPage, Document.Size);
      Document.Read(PChar(FPage)^, Document.Size);
      if Encode = True then
      begin
        FPage := UTF8ToAnsi(FPage);
      end;
    end;
  end;
end;
//...
function TMainForm.LogonToNK(Login, Password : string) : boolean;
const
  ErrorText1 = 'Nieprawidłowa nazwa użytkownika lub hasło.';
begin
  Result := False;
  Screen.Cursor := crHourGlass;
  SynHttp.Cookies.Clear;
  FUrl := Base_Url + 'login';
  FStrData := 'login=' + Login + '&password=' + Password + '&manual=1';
  HttpAction(acPost, True, False);
  if Pos(ErrorText1, FPage) > 0 then
  begin
    AlreadyLogged := Result;
    SetFocusToEditFields;
    MessageBox(Application.Handle, PChar(ErrorText1),
      PChar(Application.Title), MB_ICONERROR + MB_OK);
    Exit;
  end;
  if SynHttp.ResultCode = 503 then
  begin
    AlreadyLogged := Result;
    SetFocusToEditFields;
    MessageBox(Application.Handle, PChar('Serwer niedostępny! ' +
      'Spróbuj odwiedzić stronę: ' + Copy(Base_Url, 1, Length(Base_Url) - 1) +
      ',' + #13#10 + 'w celu sprawdzenia, jaka jest przyczyna wystąpenia błędu.'),
      PChar(Application.Title), MB_ICONERROR + MB_OK);
    Exit;
  end;
  FOwnID := SimpleParse('"watched_uid":', ',"', FPage);
  FAuthID := SimpleParse('basic_auth=', #13#10, SynHttp.Cookies.Text);
  Screen.Cursor := crDefault;
  Result := True;
end;
//...

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