CefSharp——无所不能的数据抓取利器

前言:如果你想在网站指定地方注入自己的JS,然后通过JS和C#函数互调,那么这篇文章对你很有用

 优势:相比WebKit.NET,CefSharp的谷歌浏览器内核比较新,不会出现H5特性不支持导致的网站无法载入空白的情况,非常不建议大家去使用WebKit.NET,因为内核实在太低。

思路: 使用ChromiumWebBrowser载入浏览器,在FrameLoadEnd事件之后注入自定义的JS,通过TitleChanged事件接受前端通知。

环境: 最低要求 .NET Framework 4.5.2、VS2013

部署: 去下载包cef.redist.x64、cef.redist.x86、cefsharp.common、cefsharp.winforms(我采用的是winforms开发)

https://packages.nuget.org/packages/cef.redist.x64/

手册:https://www.cnblogs.com/yanpeng19940119/archive/2019/10/24/11722377.html

初始化浏览器: 

wb = new ChromiumWebBrowser("http://*****");

浏览器加载完成注入ajax函数:

wb.FrameLoadEnd += wb_FrameLoadEnd;

void wb_FrameLoadEnd(object sender, FrameLoadEndEventArgs e)
        {
            //注册ajax方法
            StringBuilder sb = new StringBuilder();
            sb.AppendLine("function _ajax(type,url,params,contentType,fun) {");
            sb.AppendLine(@"$.ajax({
				url:url,
				type: type, 
				async: true, 
				data: params,
				dataType: 'json',
                contentType: contentType,
				success: function(data) {
                    fun(JSON.stringify(data));
				},
				error: function(xhr, textStatus) {
                    fun(xhr.responseText);
				}
			})");
            sb.AppendLine("};");
            var task01 = wb.GetBrowser().GetFrame(wb.GetBrowser().GetFrameNames()[0]).EvaluateScriptAsync(sb.ToString());
        }

 

TitleChanged事件

 这里我需要一点点技巧,我们为浏览器添加一个TitleChanged事件,当ajax请求完毕后我们更改wb.Title就会触发此事件

wb.TitleChanged += wb_TitleChanged;

void wb_TitleChanged(object sender, TitleChangedEventArgs e)
        {
            try
            {
                string title = e.Title;
                if (!string.IsNullOrEmpty(title))
                {
                    #region 获取到任务
                    if (title == "getTasks")
                    {

                    }
                    #endregion

                    #region 获取联系人
                    if (title=="contacts")
                    { 
                        
                    }
                    #endregion
                }
            }
            catch (Exception ex)
            {
                Print("✖ 系统异常:"+ex.Message);
                Lib.Log(ex.ToString());
            }
        }

 

调用ajax并将返回数据提交给C#后端

private void getTask()
        {
            string key = "getTasks";
            string data = "{}";
            string js = "_ajax('post','https://***','" + data + "','application/json',function(res){ jsEvent.setData('" + key + "',res,''); setTimeout(function(){document.title='" + key + "'},5000); });";
            wb.GetBrowser().GetFrame(wb.GetBrowser().GetFrameNames()[0]).EvaluateScriptAsync(js);

            Print("→ 获取任务条数...");
        }

代码中有一个jsEvent对方,这个对象其实是我们C#后端的CefAsyncJS对象,在前端注入进去后取名jsEvent。

前端jsEvent对象注入

这个对象的注入非常关键,因为有了它我们才能使用前端JS调用后端C#函数,我现在使用它来存/取ajax返回的内容,而这些内容都将以*.txt的形式保存在本地。

首先我们要实现CefAsyncJS对象

public class CefAsyncJS
    {
        /// <summary>
        /// 将存储的数据读出来
        /// </summary>
        public string getData(string key,string custId)
        {
            string path = System.AppDomain.CurrentDomain.BaseDirectory + "data/"+key;
            string fileName = key + (string.IsNullOrEmpty(custId) ? "" : ("-" + custId)) + ".txt";
            string fullName = path + "/" + fileName;
            while (!System.IO.File.Exists(fullName))
            {
                System.Threading.Thread.Sleep(500);
            }
            return Lib.readFile(fullName);//读取文件
        }

        /// <summary>
        /// 将前台传递的数据存起来
        /// </summary>
        public void setData(string key, string value, string custId)
        {
            string path = "data/" + key;
            string fileName = key + (string.IsNullOrEmpty(custId) ? "" : ("-" + custId)) + ".txt";
            Lib.Log(value, path, fileName,true);//保存文件
        }
    }

现在我们在前端注入

//注册js事件
                CefSharpSettings.LegacyJavascriptBindingEnabled = true;
                CefSharpSettings.WcfEnabled = true;
                wb.JavascriptObjectRepository.Register("jsEvent", jsEvent, isAsync: true, options: new CefSharp.BindingOptions() { CamelCaseJavascriptNames = false });
                i++;
                StringBuilder sb = new StringBuilder();
                sb.AppendLine(@"CefSharp.BindObjectAsync('jsEvent').then(function(result)
                {
                         alert('✔函数 jsEvent 注册完成');          
                });");
                wb.GetBrowser().GetFrame(wb.GetBrowser().GetFrameNames()[0]).EvaluateScriptAsync(sb.ToString());

 

 

 总结:首先在网站添加自己的JS方法,然后再把C#对象注册到JS中,最后通过网站Title的更改通知C#读取内容。

如有技术问题,欢迎联系我邮箱咨询:norton.yang@foxmail.com

相关推荐
©️2020 CSDN 皮肤主题: 大白 设计师:CSDN官方博客 返回首页