如何使用VBA查询Microsoft Dynamics CRM 2011或ASPX中的数据?
听你说的情况,用网页抓取CRM 2011的页面确实会踩很多坑——毕竟CRM的ASPX页面是动态渲染的,还有身份验证、视图状态这些机制拦着,直接扒HTML肯定行不通。其实微软给CRM 2011提供了官方的API接口,用这个来查询数据才是靠谱的方案,下面给你分两种情况说明:
首选方案:使用CRM 2011官方Organization Service API
CRM 2011的Organization Service是基于SOAP的官方接口,专门用来和系统交互数据,完全不需要碰前端页面,直接通过主键查询项目详情才是正确姿势。
步骤说明:
- 第一步:准备身份验证
如果你的CRM是内部AD部署,直接用Windows集成身份验证就行;如果是IFD(公网部署),需要处理ADFS的身份验证逻辑。下面的示例用内部AD场景。 - 第二步:编写VBA代码调用SOAP接口
先在VBA编辑器里引用Microsoft XML, v6.0(工具→引用),然后用以下代码查询指定主键的项目实体(假设实体逻辑名是new_project,主键字段是new_projectid,需要返回的字段比如new_projectname、new_description):
Sub QueryCRMProject() Dim xmlHttp As MSXML2.XMLHTTP60 Dim soapRequest As String Dim crmUrl As String Dim projectId As String Dim responseXml As MSXML2.DOMDocument60 Dim node As MSXML2.IXMLDOMNode ' CRM Organization Service地址(替换成你的CRM地址) crmUrl = "http://your-crm-server/XRMServices/2011/Organization.svc" ' 要查询的项目主键(替换成实际ID) projectId = "XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX" ' 构造SOAP请求 soapRequest = "<s:Envelope xmlns:s=""http://schemas.xmlsoap.org/soap/envelope/"">" & _ "<s:Body>" & _ "<Retrieve xmlns=""http://schemas.microsoft.com/xrm/2011/Contracts/Services"" xmlns:i=""http://www.w3.org/2001/XMLSchema-instance"">" & _ "<entityName>new_project</entityName>" & _ "<id>" & projectId & "</id>" & _ "<columnSet xmlns:a=""http://schemas.microsoft.com/xrm/2011/Contracts"">" & _ "<a:AllColumns>false</a:AllColumns>" & _ "<a:Columns xmlns:b=""http://schemas.microsoft.com/2003/10/Serialization/Arrays"">" & _ "<b:string>new_projectname</b:string>" & _ "<b:string>new_description</b:string>" & _ "</a:Columns>" & _ "</columnSet>" & _ "</Retrieve>" & _ "</s:Body>" & _ "</s:Envelope>" Set xmlHttp = New MSXML2.XMLHTTP60 With xmlHttp .Open "POST", crmUrl, False .setRequestHeader "Content-Type", "text/xml; charset=utf-8" .setRequestHeader "SOAPAction", "http://schemas.microsoft.com/xrm/2011/Contracts/Services/IOrganizationService/Retrieve" ' Windows集成身份验证 .setRequestHeader "Authorization", "Negotiate " .send soapRequest ' 解析返回的XML Set responseXml = New MSXML2.DOMDocument60 responseXml.LoadXML .responseText ' 提取项目名称和描述 Set node = responseXml.SelectSingleNode("//*[local-name()='new_projectname']") If Not node Is Nothing Then Debug.Print "项目名称: " & node.Text End If Set node = responseXml.SelectSingleNode("//*[local-name()='new_description']") If Not node Is Nothing Then Debug.Print "项目描述: " & node.Text End If End With Set xmlHttp = Nothing Set responseXml = Nothing End Sub
注意事项:
- 替换代码中的
crmUrl为你的CRM实际服务地址,实体逻辑名、字段名也要对应你系统中的配置。 - 如果是IFD部署,需要替换身份验证部分,改用ADFS获取令牌后再调用接口。
备选方案:模拟浏览器操作(仅当API不可用时)
如果因为权限或其他原因没法用API,只能走网页抓取的话,得用VBA模拟IE浏览器操作(CRM 2011对IE兼容性更好),等待页面完全加载后再获取内容,而不是直接看浏览器的"查看源代码"(因为动态渲染的内容只有页面加载完成后才会生成)。
示例代码:
Sub ScrapeCRMProject() Dim ie As Object Dim projectId As String Dim searchInput As Object Dim searchButton As Object Dim detailElement As Object Set ie = CreateObject("InternetExplorer.Application") projectId = "你的项目编号" With ie .Visible = True ' 调试时可以设为True,上线后改False .Navigate "http://your-crm-server/main.aspx?etc=10001&pagetype=entitylist" ' 替换成项目列表页地址 ' 等待页面加载完成 Do While .Busy Or .ReadyState <> 4 DoEvents Loop ' 假设搜索框的ID是"new_projectid",搜索按钮ID是"searchButton" Set searchInput = .Document.getElementById("new_projectid") If Not searchInput Is Nothing Then searchInput.Value = projectId ' 模拟点击搜索按钮 Set searchButton = .Document.getElementById("searchButton") If Not searchButton Is Nothing Then searchButton.Click ' 等待搜索结果加载 Do While .Busy Or .ReadyState <> 4 DoEvents Loop ' 提取详情,假设项目名称在class为"project-name"的元素里 Set detailElement = .Document.querySelector(".project-name") If Not detailElement Is Nothing Then Debug.Print "项目名称: " & detailElement.innerText End If End If End If ' 关闭浏览器(可选) .Quit End With Set ie = Nothing Set searchInput = Nothing Set searchButton = Nothing Set detailElement = Nothing End Sub
注意事项:
- 这个方案非常脆弱,CRM页面的元素ID、类名一旦修改,代码就会失效。
- 要处理登录逻辑,如果CRM需要手动登录,得在代码里模拟输入用户名密码点击登录按钮。
- 页面加载等待的逻辑要写完善,避免因为加载未完成导致找不到元素。
内容的提问来源于stack exchange,提问作者confusedDude
相关产品推荐
相关产品推荐

