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.
To powodzenia w szukaniu.
hint: wpisz w google "hook na mysz delphi"
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.
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.
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
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 :)