- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我正在尝试使用 TChromium 迭代 DOM,因为我使用 Delphi 2007,所以我无法使用匿名方法,所以我创建了一个继承 TCEFDomVisitorOwn 的类。我的代码如下,但由于某种原因,“访问”过程从未被调用,所以什么也没有发生。
unit udomprinc;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, ceflib, cefvcl;
type
TForm1 = class(TForm)
Chromium1: TChromium;
procedure FormCreate(Sender: TObject);
procedure Chromium1LoadEnd(Sender: TObject; const browser: ICefBrowser; const frame: ICefFrame;
httpStatusCode: Integer);
private
{ Private declarations }
public
{ Public declarations }
end;
type
TElementVisitor = class(TCefDomVisitorOwn)
private
FTagName, FHtml: string;
protected
procedure visit(const document: ICefDomDocument); override;
public
constructor Create(const par1, par2: string); reintroduce;
end;
var
Form1: TForm1;
implementation
constructor TElementVisitor.Create(const par1, par2: string);
begin
inherited create;
FTagName := par1;
FHtml := par2;
end;
procedure TElementVisitor.visit(const document: ICefDomDocument);
procedure ProcessNode(ANode: ICefDomNode);
var
Node: ICefDomNode;
tagname, name, html, value : string;
begin
if Assigned(ANode) then
begin
Node := ANode.FirstChild;
while Assigned(Node) do
begin
name := Node.GetElementAttribute('name');
tagname := Node.GetElementAttribute('tagname');
html := Node.GetElementAttribute('outerhtml');
value := Node.GetElementAttribute('value');
ProcessNode(Node);
Node := Node.NextSibling;
end;
end;
end;
begin
// this never happens
ProcessNode(document.Body);
end;
{$R *.dfm}
procedure TForm1.Chromium1LoadEnd(Sender: TObject; const browser: ICefBrowser; const frame: ICefFrame;
httpStatusCode: Integer);
var visitor : TElementVisitor;
begin
visitor := TElementVisitor.Create('input','test');
chromium1.Browser.MainFrame.VisitDom(visitor);
end;
procedure TForm1.FormCreate(Sender: TObject);
begin
chromium1.load('www.google.com');
end;
end.
最佳答案
这都是关于来回发送消息的。您的代码缺少 RenderProcessHandler,这允许渲染器接收消息。
在您的 DPR 中,您应该有这样的代码
if not CefLoadLibDefault then
Exit;
在你的 pas 文件中
type
TNotifyVisitor = procedure(aNode: ICefDomNode; var aLevel: integer);// of object;
TAttributeType = (atNodeName, atName, atId, atClass, atLevel);
TElementNameVisitor = class(TCefDomVisitorOwn)
private
FName: string;
FAttributeName: string;
FOnFound: TNotifyVisitor;
FOnVisited: TNotifyVisitor;
function getAttributeName: string;
protected
procedure visit(const document: ICefDomDocument); override;
public
constructor Create(const AName: string); reintroduce;
property OnFound: TNotifyVisitor read FOnFound write FOnFound;
property OnVisited: TNotifyVisitor read FOnVisited write FOnVisited;
property AttributeName: string read getAttributeName write FAttributeName;
end;
TCustomRenderProcessHandler = class(TCefRenderProcessHandlerOwn)
protected
function OnProcessMessageReceived(const browser: ICefBrowser;
sourceProcess: TCefProcessId; const message: ICefProcessMessage): Boolean; override;
end;
implementation
var
_Browser: ICefBrowser;
{ TElementNameVisitor }
constructor TElementNameVisitor.Create(const AName: string);
begin
inherited Create;
FName := AName;
end;
function TElementNameVisitor.getAttributeName: string;
begin
if FAttributeName = '' then
Result := 'name'
else
Result := FAttributeName;
end;
procedure TElementNameVisitor.visit(const document: ICefDomDocument);
var
a_Level: integer;
a_message: iCefProcessMessage;
procedure ProcessNode(aNode: ICefDomNode; var aLevel: integer);
var
a_Node: ICefDomNode;
a_Name: string;
begin
if Assigned(aNode) then
begin
inc(aLevel);
a_Node := aNode.FirstChild;
while Assigned(a_Node) do
begin
if Assigned(FOnVisited) then
FOnVisited(a_Node, aLevel);
if Assigned(FOnFound) then
begin
a_Name := a_Node.GetElementAttribute(AttributeName);
if SameText(a_Name, FName) then
begin
// do what you need with the Node here
if Assigned(FOnFound) then
FOnFound(a_Node, aLevel);
end;
end;
ProcessNode(a_Node, aLevel);
a_Node := a_Node.NextSibling;
end;
end;
end;
begin
a_Level := 0;
ProcessNode(document.Body, a_Level);
a_message := TCefProcessMessageRef.New(cdomdataFin);
_Browser.SendProcessMessage(PID_BROWSER, a_message);
end;
您需要创建一个 RenderProcessHandler:
initialization
CefRenderProcessHandler := TCustomRenderProcessHandler.Create;
要使用它...您可以像这样向渲染器发送消息
function TformBrowser.HasBrowser: boolean;
begin
Result := Assigned(Chromium1.browser);
end;
procedure TformBrowser.Button1Click(Sender: TObject);
var
a_message: ICefProcessMessage;
a_list: ICefListValue;
a_How: string;
begin
if HasBrowser and FLoaded then
begin
FLoaded := False;
Case rgFindDomNodeBy.ItemIndex of
0: a_How := 'ByName';
1: a_How := 'ById';
2: a_How := 'ByClass';
3: a_How := 'ByAll';
end;
lbFrames.Items.Clear;
a_message := TCefProcessMessageRef.New(a_How);
a_list := a_message.ArgumentList;
a_list.SetString(0, edtAttribute.Text);
Chromium1.browser.SendProcessMessage(PID_RENDERER,a_message);
end;
end;
RenderProcessHandler 将收到消息:
{ TCustomRenderProcessHandler }
procedure _ElementCB(aNode: ICefDomNode; var aLevel: integer);
var
a_message: ICefProcessMessage;
begin
a_message := TCefProcessMessageRef.New('domdata');
a_message.ArgumentList.SetString(Ord(atNodeName), aNode.Name);
a_message.ArgumentList.SetString(Ord(atName), aNode.GetElementAttribute('name'));
a_message.ArgumentList.SetString(Ord(atId), aNode.GetElementAttribute('id'));
a_message.ArgumentList.SetString(Ord(atClass), aNode.GetElementAttribute('class'));
a_message.ArgumentList.SetInt(Ord(atLevel), aLevel);
_Browser.SendProcessMessage(PID_BROWSER, a_message);
end;
function TCustomRenderProcessHandler.OnProcessMessageReceived(
const browser: ICefBrowser; sourceProcess: TCefProcessId;
const message: ICefProcessMessage): Boolean;
var
a_list: ICefListValue;
begin
_Browser := browser;
Result := False;
if SameText(message.Name, 'ByAll') then
begin
_ProcessElements(browser.MainFrame, _ElementCB);
Result := True;
end else
if SameText(message.Name, 'ByName') then
begin
a_list := message.ArgumentList;
_ProcessElementsByAttribute(browser.MainFrame, a_list.GetString(0),'name', _ElementCB);
Result := True;
end else
if SameText(message.Name, 'ById') then
begin
a_list := message.ArgumentList;
_ProcessElementsByAttribute(browser.MainFrame, a_list.GetString(0), 'id', _ElementCB);
Result := True;
end else
if SameText(message.Name, 'ByClass') then
begin
a_list := message.ArgumentList;
_ProcessElementsByAttribute(browser.MainFrame, a_list.GetString(0), 'class', _ElementCB);
Result := True;
end;
end;
RenderProcessHandler 创建 Visitor(TElementNameVisitor)
procedure _ProcessElementsByAttribute(const aFrame: ICefFrame; aName, aAttributeName: string; aVisitor: TNotifyVisitor);
var
a_Visitor: TElementNameVisitor;
begin
if Assigned(aFrame) then
begin
a_Visitor := TElementNameVisitor.Create(aName);
a_Visitor.AttributeName := aAttributeName;
a_Visitor.OnFound := aVisitor;
aFrame.VisitDom(a_Visitor);
end;
end;
procedure _ProcessElements(const aFrame: ICefFrame; aVisitor: TNotifyVisitor);
var
a_Visitor: TElementNameVisitor;
begin
if Assigned(aFrame) then
begin
a_Visitor := TElementNameVisitor.Create('');
a_Visitor.OnVisited := aVisitor;
aFrame.VisitDom(a_Visitor);
end;
end;
然后,访问者 (TElementNameVisitor) 将一条消息发送回 TChromium,您可以将其绑定(bind)到其中,如下所示:
procedure TformBrowser.Chromium1ProcessMessageReceived(Sender: TObject;
const browser: ICefBrowser; sourceProcess: TCefProcessId;
const message: ICefProcessMessage; out Result: Boolean);
var
a_List: ICefListValue;
begin
if SameText(message.Name, 'domdata') then
begin
a_List := message.ArgumentList;
lbFrames.Items.Add(a_List.GetString(Ord(atNodeName)));
lbFrames.Items.Add('Name: ' + a_List.GetString(Ord(atName)));
lbFrames.Items.Add('Id: ' + a_List.GetString(Ord(atId)));
lbFrames.Items.Add('Class: ' + a_List.GetString(Ord(atClass)));
lbFrames.Items.Add('Level: ' + IntToStr(a_List.GetInt(Ord(atLevel))));
lbFrames.Items.Add('------------------');
Result := True;
end else
if SameText(message.Name, cdomdataFin) then
begin
FLoaded := True;
end else
begin
lbFrames.Items.Add('Unhandled message: ' + message.Name);
inherited;
end;
end;
------------编辑-------------
查看此代码后...它可以改进...更加线程友好
删除这个
var
_Browser: ICefBrowser;
改变这个
TNotifyVisitor = procedure(aBrowser: ICefBrowser; aNode: ICefDomNode; var aLevel: integer);// of object;
将其添加到 TElementNameVisitor
property Browser: ICefBrowser read getBrowser write FBrowser;
将 TElementNameVisitor 中的引用更改为浏览器也会添加此
function TElementNameVisitor.getBrowser: ICefBrowser;
begin
if not Assigned(FBrowser) then
Raise Exception.Create('Need to set the Browser property when creating TElementNameVisitor.');
Result := FBrowser;
end;
更改这些
procedure _ProcessElementsByAttribute(const aBrowser: ICefBrowser; aName, aAttributeName: string; aVisitor: TNotifyVisitor);
var
a_Visitor: TElementNameVisitor;
begin
if Assigned(aBrowser) and Assigned(aBrowser.MainFrame) then
begin
a_Visitor := TElementNameVisitor.Create(aName);
a_Visitor.Browser := aBrowser;
a_Visitor.AttributeName := aAttributeName;
a_Visitor.OnFound := aVisitor;
aBrowser.MainFrame.VisitDom(a_Visitor);
end;
end;
procedure _ProcessElements(const aBrowser: ICefBrowser; aVisitor: TNotifyVisitor);
var
a_Visitor: TElementNameVisitor;
begin
if Assigned(aBrowser) and Assigned(aBrowser.MainFrame) then
begin
a_Visitor := TElementNameVisitor.Create('');
a_Visitor.Browser := aBrowser;
a_Visitor.OnVisited := aVisitor;
aBrowser.MainFrame.VisitDom(a_Visitor);
end;
end;
同时更改这些
procedure _ElementCB(aBrowser: ICefBrowser; aNode: ICefDomNode; var aLevel: integer);
var
a_message: ICefProcessMessage;
begin
a_message := TCefProcessMessageRef.New(cdomdata);
a_message.ArgumentList.SetString(Ord(atNodeName), aNode.Name);
a_message.ArgumentList.SetString(Ord(atName), aNode.GetElementAttribute('name'));
a_message.ArgumentList.SetString(Ord(atId), aNode.GetElementAttribute('id'));
a_message.ArgumentList.SetString(Ord(atClass), aNode.GetElementAttribute('class'));
a_message.ArgumentList.SetInt(Ord(atLevel), aLevel);
aBrowser.SendProcessMessage(PID_BROWSER, a_message);
end;
function TCustomRenderProcessHandler.OnProcessMessageReceived(
const browser: ICefBrowser; sourceProcess: TCefProcessId;
const message: ICefProcessMessage): Boolean;
var
a_list: ICefListValue;
begin
Result := False;
if SameText(message.Name, 'ByAll') then
begin
_ProcessElements(browser, _ElementCB);
Result := True;
end else
if SameText(message.Name, 'ByName') then
begin
a_list := message.ArgumentList;
_ProcessElementsByAttribute(browser, a_list.GetString(0),'name', _ElementCB);
Result := True;
end else
if SameText(message.Name, 'ById') then
begin
a_list := message.ArgumentList;
_ProcessElementsByAttribute(browser, a_list.GetString(0), 'id', _ElementCB);
Result := True;
end else
if SameText(message.Name, 'ByClass') then
begin
a_list := message.ArgumentList;
_ProcessElementsByAttribute(browser, a_list.GetString(0), 'class', _ElementCB);
Result := True;
end;
end;
关于Delphi Chromium - 迭代 DOM,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34655862/
如果您有超过 1 个具有相同类名的(动态)文本框,并使用 jquery 循环遍历每个所述文本框,您是否可以假设每次选择文本框的顺序都是相同的? 示例: 文本框 1 值 = 1文本框 2 值 = 2文本
有人知道为什么这段代码无法顺利运行吗?它似乎不喜欢使用yield关键字进行迭代:我正在尝试从任何级别的列表或字典中挖掘所有数字(对列表特别感兴趣)。在第二次迭代中,它找到 [2,3] 但无法依次打印
我关于从 mysql 数据库导出数据并将其保存到 Excel 文件(多表)的创建脚本。我需要让细胞动态基因化。该脚本正确地显示了标题,但数据集为空。当我“回显”$value 变量时,我检查了数据是否存
我正在尝试在 Python 中运行模拟,由此我绘制了一个数组的随机游走图,给定了两个变量参数的设定水平。 但是,我遇到了一个问题,我不确定如何迭代以便生成 250 个不同的随机数以插入公式。例如我已经
我是学习 jquery 的新手,所以如果这是一个相对简单的问题,我深表歉意。我有一个 ID 为 ChartstoDisplay 的 asp.net 复选框列表。我正在尝试创建 jquery 来根据是否
我正在尝试根据在任意数量的部分中所做的选择找出生成有效案例列表的最佳方法。也许它不是真正的算法,而只是关于如何有效迭代的建议,但对我来说这似乎是一个算法问题。如果我错了,请纠正我。实现实际上是在 Ja
如果我使用 sr1 为 www.google.com 发送 DNSQR,我会收到几个 DNSRR(s) 作为回复,例如(使用 ans[DNSRR].show() 完成): ###[ DNS Resou
假设有这样一个实体类 @Entity public class User { ... public Collection followers; ... } 假设用户有成千上万的用户关注者。我想分页..
这个问题已经有答案了: 已关闭11 年前。 Possible Duplicate: Nested jQuery.each() - continue/break 这是我的代码: var steps =
我刚从 F# 开始,我想遍历字典,获取键和值。 所以在 C# 中,我会说: IDictionary resultSet = test.GetResults; foreach (DictionaryEn
我知道已经有很多关于如何迭代 ifstream 的答案,但没有一个真正帮助我找到解决方案。 我的问题是:我有一个包含多行数据的txt文件。 txt 文件的第一行告诉我其余数据是如何组成的。例如这是我的
我有 12 个情态动词。我想将每个模态的 .modal__content 高度与 viewport 高度 进行比较,并且如果特定模态 .modal__content 高度 vh addClass("c
在此JSFiddle (问题代码被注释掉)第一次单击空单元格会在隐藏输入中设置一个值,并将单元格的背景颜色设置为绿色。单击第二个空表格单元格会设置另一个隐藏输入的值,并将第二个单元格的背景颜色更改为红
这是一个非常具体的问题,我似乎找不到任何特别有帮助的内容。我有一个单链表(不是一个实现的链表,这是我能找到的全部),其中节点存储一个 Student 对象。每个 Student 对象都有变量,尽管我在
有没有办法迭代 IHTMLElementCollection? 比如 var e : IHTMLLinkElement; elementCollection:IHTMLElementCollect
我正在尝试用 Java 取得高分。基本上我想要一个 HashMap 来保存 double 值(因此索引从最高的 double 值开始,这样我更容易对高分进行排序),然后第二个值将是客户端对象,如下所示
我想在宏函数中运行 while/until 循环,并限制其最大迭代次数。我找到了如何在“通常”sas 中执行此操作: data dataset; do i=1 to 10 until(con
Iterator iterator = plugin.inreview.keySet().iterator(); while (iterator.hasNext()) { Player key
晚上好我有一个简单的问题,我警告你我是序言的新手。假设有三个相同大小的列表,每个列表仅包含 1、0 或 -1。我想验证对于所有 i,在三个列表的第 i 个元素中,只有一个非零。 此代码针对固定的 i
我在 scheme 中构建了一个递归函数,它将在某些输入上重复给定函数 f, n 次。 (define (recursive-repeated f n) (cond ((zero? n) iden
我是一名优秀的程序员,十分优秀!