Перечисление узлов DOM в TChromium

Я пытаюсь перечислить узлы DOM, используя следующий код (в XE2).

Я позаимствовал большую часть этого из ответов, данных здесь, в SO, но по какой-то причине это ничего не делает.

IOW, ProcessDOM() никогда не вызывается.

И я в своем уме.

Может ли кто-нибудь показать мне, что я делаю неправильно здесь.

Заранее спасибо.

procedure ProcessNode(ANode: ICefDomNode);
var
  Node1: ICefDomNode;
begin
  if Assigned(ANode) then begin
    Node1 := ANode.FirstChild;
    while Assigned(Node1) do begin
      {Do stuff with node}
      ProcessNode(Node1);
      Node1 := Node1.NextSibling;
    end;
  end;
end;

procedure ProcessDOM(const ADocument: ICefDomDocument);
begin
  ProcessNode(ADocument.Body);
end;

procedure TMainForm.Chrome1LoadEnd(Sender: TObject; const ABrowser: ICefABrowser; const AFrame: ICefAFrame; AStatus: Integer);
begin
  if Assigned(AFrame) then AFrame.VisitDomProc(ProcessDOM);
end;

person Adem    schedule 22.01.2013    source источник
comment
Насколько я помню, была версия Chromium, где посещение DOM вообще не работало. Какую версию ты используешь ?   -  person TLama    schedule 23.01.2013
comment
Я использую последнюю версию SVN Delphi Chromium Embedded 3. Вы знаете, какая версия работает?   -  person Adem    schedule 24.01.2013
comment
Хм, кажется, это не работает в текущем снимке Chromium 3 (конечно, я исправил опечатки ICefABrowser и ICefAFrame отсюда). Ваш код ИМХО должен работать, но не работает. Посещение DOM отлично работало в некоторых старых версиях старого Chromium (не v3), и, насколько я помню, в новом снимке старого Chromium это тоже не работает. Я бы предложил сообщить об ошибке (если ее нет) или связаться с автором. Боюсь, я больше ничем не могу вам помочь.   -  person TLama    schedule 24.01.2013
comment
Я сообщу об этом, чтобы увидеть, если он улучшится. И... вы правы, 'ICefABrowser' и 'ICefAFrame' должны были быть 'ICefBrowser' и 'ICefFrame' -- результат редактирования в последнюю минуту (хотя и неаккуратного) с моей стороны перед публикацией здесь.   -  person Adem    schedule 24.01.2013
comment
Без проблем. Это случается со всеми время от времени. Я надеюсь, что Генри скоро это исправит, так как это кажется давней проблемой. Спасибо!   -  person TLama    schedule 24.01.2013
comment
@TLama Можно ли передать указатель на TCefProcessMessageRef? Я хотел бы пройти запись.   -  person user3060326    schedule 19.05.2014
comment
@user3060326 user3060326, если вы имеете в виду, как передать указатель на ArgumentList, то возможно, но на самом деле возможно, методом SetBinary. Но я никогда этого не пробовал. Извините, я давно не уходил из CEF...   -  person TLama    schedule 19.05.2014


Ответы (3)


У меня была та же проблема, и я использовал демо-программу, которая поставляется с dcef3. Со следующим работает.

type TCustomRenderProcessHandler = class(TCefRenderProcessHandlerOwn)
  protected
    function OnProcessMessageReceived(const browser: ICefBrowser; sourceProcess: TCefProcessId; const message: ICefProcessMessage): Boolean; override;
end;

Chromium1.browser.SendProcessMessage(PID_RENDERER, TCefProcessMessageRef.New('visitdom')); 

function TCustomRenderProcessHandler.OnProcessMessageReceived(browser: ICefBrowser; sourceProcess: TCefProcessId; message: ICefProcessMessage): Boolean;
begin 
  if (message.Name = 'visitdom') then begin
    browser.MainFrame.VisitDomProc(
        procedure(const doc: ICefDomDocument) 
        begin
          ProcessNode(Doc.Body);
        end);
    Result := True;
  end; 
end;

initialization
  CefRenderProcessHandler := TCustomRenderProcessHandler.Create;
person Dimitris    schedule 09.03.2013

Вам нужно добавить процедуру в обработчик. процедура ProcessNode(ANode: ICefDomNode);

Прочтите это: 1

person Epiphanyx    schedule 14.04.2013
comment
Этот ответ не имеет смысла. Это связано с этим вопросом, и зачем нужна дополнительная процедура? Можете ли вы объяснить больше, пожалуйста? - person David; 07.03.2016

Как отмечается в этом блоге, основная трудность при Доступ к DOM визуализированной страницы заключается в том, что вы можете сделать это только в том же процессе, что и связанный модуль визуализации для этой страницы.

Вы не можете получить доступ к dom из потока браузера, вы должны сделать это в потоке рендерера.

Во-первых, перенаправьте сообщение (например, visitdom) из процесса браузера в процесс рендеринга.

procedure TMainForm.crmLoadEnd(Sender: TObject; const browser: ICefBrowser;
  const frame: ICefFrame; httpStatusCode: Integer);
var
  msg : ICefProcessMessage;
begin
  if IsMain(browser, frame) then
    FLoading := False;

  msg := TCefProcessMessageRef.New('visitdom');
  browser.SendProcessMessage(PID_RENDERER, msg);
end;

Во-вторых, создайте TCustomRenderProcessHandler для обработки сообщения и отправьте результат обратно процессам браузера.

function TCustomRenderProcessHandler.OnProcessMessageReceived(
  const browser: ICefBrowser; sourceProcess: TCefProcessId;
  const message: ICefProcessMessage): Boolean;
begin
  Result := False;
  if (message.Name = 'visitdom') then
  begin
      browser.MainFrame.VisitDomProc(
        procedure(const doc: ICefDomDocument)
          function ProcessNode(ANode: ICefDomNode) : String;
          var
            Node: ICefDomNode;
          begin
            Result := 'Not Found';
            if Assigned(ANode) then
            begin
              Node := ANode.FirstChild;
              while Assigned(Node) do
              begin
                if Node.ElementTagName='DIV' then
                begin
                  if Node.GetElementAttribute('class')='tv-panels' then
                  begin
                    Result := 'Found';
                    Exit;
                  end;
                end;
                ProcessNode(Node);
                Node := Node.NextSibling;
              end;
            end;
          end;
        var msg : ICefProcessMessage;
        begin
          msg := TCefProcessMessageRef.New('visitdom');
          msg.ArgumentList.SetString(0, processNode(doc.Body));
          browser.SendProcessMessage(PID_BROWSER, msg);
        end);
      Result := True;
  end;
end;

В-третьих, в процессе браузера создайте обработчик для обработки сообщения, отправленного обратно из процесса рендеринга.

procedure TMainForm.crmProcessMessageReceived(Sender: TObject;
  const browser: ICefBrowser; sourceProcess: TCefProcessId;
  const message: ICefProcessMessage; out Result: Boolean);
begin
  Result := False;
  if (message.Name = 'visitdom') then
  begin
    StatusBar.SimpleText := message.ArgumentList.GetString(0);
    Result := True;
  end;
end;

Будьте осторожны, во время отладки установка точки останова в процессе рендеринга никогда не работает. Он никогда не достигнет там.

person Yongyuth Rootwararit    schedule 12.05.2016