Jak odczytywać dane ze stron internetowych, gdy mam adres XPath kontrolki

2

Chciałbym zasymulować w delphi klawiaturę i myszkę na stronie internetowej w Mozilla Firefox, tj. przeczytanie pól formularza i kilknięcie przycisku/linka kierującego mnie do następnej strony. Link mam wyciągnięty jako XPath, dane formularza też. Kiedyś to robiłem w AutoIt3, teraz chcę przejść na Delphi i szukam komponentów.

0

To powodzenia w szukaniu.
hint: wpisz w google "hook na mysz delphi"

0

Przejrzyj moje ostatnie odpowiedzi w tym dziale. Nie raz już tutaj postowałem kody pokazujące zarówno zakładanie hooka na klawiaturę jak i symulowanie naciskania klawiszy własną procedurą KeyDownUp. Również ostatnio. Google i forumowa wyszukiwarka, mimo iż niedoskonała wcale nie gryzą :-) A i w kodzie wielokrotnie dołączanego tutaj mojego modułu w pliku useful_winapi.pas jest też kod symulujący pracę myszki.

0

Dzięki, ale nie chodzi mi o to, żeby zasymulować, że myszka się przesunęła na link i następnie został wciśnięty lewy przycisk myszy. Chodzi mi o komponent mający metodę np. LinkClick(link,typ) np. LinkClick('logout','id') - zamiast najeżdżać myszką na link chcę go po prostu uruchomić. W AutoIt pobrałem XPath linka (np. /html/body/div/div[4]/div[2]/ul[4]/li[2]/a) i wywołałem procedurę _FFClick(sciezkaXPath) - chcę to zrobić w Delphi, czy jest możliwy pierwszy lub drugi wariant?
I czy można jakoś łatwo pobrać dane ze strony? Mam daną ścieżkę i chciałbym móc zrobić coś takiego: $napis = _FFXpath("/html/body/form/div[2]/div[4]/div[2]/span") - czyta mi ze strony internetowej napis z kontrolki o danej ścieżce.

0

Sorry za niezrozumienie, czasami trudno mi wyjaśnić o co właściwie mi chodzi :)
TWebBrowser jest dobrym pomysłem i właśnie próbuję go rozgryźć, wadą jest silnik w oparciu o Internet Explorer a sporo danych uzyskuję podając ścieżkę XPATH. I niestety XPath w IE nie działa :( A to jest naprawdę super przydatne, gdy chcę przeczytać jakiś komunikat (nie formularz, po prostu tekst wyświetlony na stronie). Podaję jego XPATH i już, czy może ktoś wie, jak odczytać to bez XPATH? Np. strona główna www.4programmers.net - jak odczytać z prawej strony tytuły wątków z działu "Ostatnie zmiany w tekstach" ? Gdyby można było się jakoś dostać do strony firefox'a, to sprawa byłaby prosta,

i:=1;
repeat
   tablWatkow[i]:=wezZawartoscXPath('/html/body/div/div[3]/div[2]/div[3]/ul/li['+intToStr(i)+'/a'); 
until tablWatkow[i]='';

oczywiście trzeba jeszcze mieć funkcję, która pobiera zawartość strony z zadanej ścieżki i nad tym się głowię.

dodanie znacznika <code class="delphi"> - fp

1

Document Object Model (DOM) lub wyrażenia regularne używając DOM może to wydawać się trochę skomplikowane np:

uses MSHTML;

procedure TForm1.Button1Click(Sender: TObject);
var
  Doc: IHTMLDocument3;
  Elements: IHTMLElementCollection;
  Element, Element2: IHTMLElement;
  //Link: IHTMLLinkElement;
  i, j: Integer;
  List: THTMLElements;
begin
  WEBBrowser1.Navigate('www.4programmers.net');
  while WEBBrowser1.ReadyState <> READYSTATE_COMPLETE do
    Application.ProcessMessages;
  Doc:= WEBBrowser1.Document as IHTMLDocument3;
  Elements:= Doc.getElementsByTagName('div');
  for i:=0 to Elements.length - 1 do
  begin
    Element:= Elements.item(i, EmptyParam) as IHTMLElement;
    if AnsiSameText(Element.className, 'box-feed') then
      break;
  end;
  Elements:= Element.children as IHTMLElementCollection;
  for i:=0 to Elements.length -1 do
  begin
    Element:= Elements.item(i, EmptyParam) as IHTMLElement;
    if AnsiSameText(Element.tagName, 'ul') then
      break;
  end;
  Elements:= Element.children as IHTMLElementCollection;
  for i:=0 to Elements.length -1 do
  begin
    Element:= Elements.item(i, EmptyParam) as IHTMLElement;
    if AnsiSameText(Element.tagName, 'li') then
    begin
      for j:= 0 to IHTMLElementCollection(Element.children).length -1 do
      begin
        Element2:= IHTMLElementCollection(Element.children).item(j, EmptyParam) as IHTMLElement;
        if AnsiSameText(Element2.tagName, 'a') then
          Memo1.Lines.Add(Format('%0:d %1:s %2:s', [i, Element2.innerHTML, Element2.getAttribute('href', 0)]));
      end;
    end;
  end;
end;

oczywiście można ten kod uprościć pisząc sobie odpowiednią procedurę:

uses MSHTML;

type
  THTMLElements = array of IHTMLElement;

procedure GetChildrenByTagName(const AElement: IHTMLElement; const ATagName: string;
  var AHTMLElements: THTMLElements);
var
  i: Integer;
  Elements: IHTMLElementCollection;
  Element: IHTMLElement;
begin
  Elements:= AElement.children as IHTMLElementCollection;
  for i:=0 to Elements.length -1 do
  begin
    Element:= Elements.item(i, EmptyParam) as IHTMLElement;
    if AnsiSameText(Element.tagName, ATagName) then
    begin
      SetLength(AHTMLElements, Length(AHTMLElements) + 1);
      AHTMLElements[Length(AHTMLElements) - 1]:= Element;
    end;
    GetChildrenByTagName(Element, ATagName, AHTMLElements);
  end;
end;

procedure TForm1.Button1Click(Sender: TObject);
var
  Doc: IHTMLDocument3;
  Elements: IHTMLElementCollection;
  Element: IHTMLElement;
  i: Integer;
  List: THTMLElements;
begin
  WEBBrowser1.Navigate('www.4programmers.net');
  while WEBBrowser1.ReadyState <> READYSTATE_COMPLETE do
    Application.ProcessMessages;
  Doc:= WEBBrowser1.Document as IHTMLDocument3;
  Elements:= Doc.getElementsByTagName('div');
  for i:=0 to Elements.length - 1 do
  begin
    Element:= Elements.item(i, EmptyParam) as IHTMLElement;
    if AnsiSameText(Element.className, 'box-feed') then
    begin
      GetChildrenByTagName(Element, 'a', List);
      break;
    end;
  end;
  for i:=Low(List) to High(List) do
    Memo1.Lines.Add(Format('%0:d %1:s %2:s', [i, List[i].innerHTML, List[i].getAttribute('href', 0)]));
end;

W tym przykładzie zysku za bardzo nie widać ale gdyby w programie często zachodziła potrzeba pobierania takich danych była by ona użyteczna i znacznie skracała kod. A wyrażenia regularne to to chyba wiesz co to i zwykle z ich pomocą wychodzi zdecydowanie mniej kodu :)

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