开发手册 欢迎您!
软件开发者资料库

.NET(C#) CefSharp 下载获取页面中指定的文件图片视频等内容(.jpg、.js等)

CefSharp访问和操纵页面上的内容,可以以编程方式执行 JavaScript 并将其嵌入到页面中,并在触发JavaScript事件时接收回调。您可以使用CefSharp显示使用HTML5构建的嵌入式UI,或显示远程Web内容和Web应用程序。Google Chrome浏览器可以使用很多命令行(CommandLine)配置,有些更改功能的行为,而另一些则用于调试或试验。本文主要介绍.NET(C#)中, 使用CefSharp时,下载获取网页中地址的文件图片视频等内容(.jpg、.js等)的方法,以及实现的示例代码。

1、下载获取一般文件内容实现思路

1) 首先需要对ChromiumWebBrowser IRequestHandlerRequestHandler进行实现。
2) 需要对IRequestHandlerIResponseFilterIRequestHandler.GetResourceResponseFilter 方法进行重写。
3) 需要写一个类实现 IResponseFilter 接口。
4) 然后就可用在IResponseFilterFilterStatus Filter(Stream dataIn, out long dataInRead, Stream dataOut, out long dataOutWritten) 方法中,读取指定内容的Stream。

2、下载文件示例代码

由于很多文件无法获取到完整内容,再者具体文件内容在Filter里面进行了控制,而Fileter的内容依赖于IRequestHandler所以,外部只能操作Handler得到数据。 所以需要在,Filter和Hanlder类中,使用事件来传递具体的内容。代码如下。 Filter类如下:

public class TestImageFilter : IResponseFilter      {          public event Action NotifyData;          private int contentLength = 0;          private List dataAll = new List();          public void SetContentLength(int contentLength)          {              this.contentLength = contentLength;          }          public FilterStatus Filter(System.IO.Stream dataIn, out long dataInRead, System.IO.Stream dataOut, out long dataOutWritten)          {              try              {                  if (dataIn == null)                  {                      dataInRead = 0;                      dataOutWritten = 0;                      return FilterStatus.Done;                  }                  dataInRead = dataIn.Length;                  dataOutWritten = Math.Min(dataInRead, dataOut.Length);                  dataIn.CopyTo(dataOut);                  dataIn.Seek(0, SeekOrigin.Begin);                  byte[] bs = new byte[dataIn.Length];                  dataIn.Read(bs, 0, bs.Length);                  dataAll.AddRange(bs);                  if (dataAll.Count == this.contentLength)                  {                      // 通过这里进行通知                      NotifyData(dataAll.ToArray());                      return FilterStatus.Done;                  }                  else if (dataAll.Count < this.contentLength)                  {                      dataInRead = dataIn.Length;                      dataOutWritten = dataIn.Length;                      return FilterStatus.NeedMoreData;                  }                  else                  {                      return FilterStatus.Error;                  }              }              catch (Exception ex)              {                  dataInRead = dataIn.Length;                  dataOutWritten = dataIn.Length;                  return FilterStatus.Done;              }          }          public bool InitFilter()          {              return true;          }      }  
bool IRequestHandler.OnResourceResponse(IWebBrowser browserControl, IBrowser browser, IFrame frame, IRequest request, IResponse response)          {              //NOTE: You cannot modify the response, only the request              // You can now access the headers              //var headers = response.ResponseHeaders;              try              {                  var content_length = int.Parse(response.ResponseHeaders["Content-Length"]);                  if (this.filter != null)                  {                      this.filter.SetContentLength(content_length);                  }              }              catch { }              return false;          }          private TestImageFilter filter = null;          public event Action NotifyData;          IResponseFilter IRequestHandler.GetResourceResponseFilter(IWebBrowser browserControl, IBrowser browser, IFrame frame, IRequest request, IResponse response)          {              var url = new Uri(request.Url);              if (url.AbsoluteUri.Contains("http://test.test.com/somehead?"))              {                  this.filter = new TestImageFilter();                  filter.NotifyData += filter_NotifyData;                  return filter;              }              return null;          }          void filter_NotifyData(byte[] data)          {              if (NotifyData != null)              {                  NotifyData(data);              }          } 

此方法位IRequestHandler的一部分实现,通过实现函数:IRequestHandler.GetResourceResponseFilter得到资源文件的长度,然后长度传入Filter,在Filter中控制从而得到整个数据的真正长度。

3、下载分片分段数据文件数据

部分站点,返回数据是分片了的,不能通过Content-Length的长度来判断,程序的Stream是否完成。

所以需要其他方式处理,单个http请求完成的时候,会调用Complete方法,所以可以在此方法中处理。示例代码如下,

public class FilterManager    {        private static Dictionary dataList = new Dictionary();        public static IResponseFilter CreateFilter(string guid)        {            lock (dataList)            {                var filter = new TestImageFilter();                dataList.Add(guid, filter);                return filter;            }        }        public static IResponseFilter GetFileter(string guid)        {            lock (dataList)            {                return dataList[guid];            }        }    }//对Stream进行合并public class TestImageFilter : IResponseFilter    {        public List dataAll = new List();        public FilterStatus Filter(System.IO.Stream dataIn, out long dataInRead, System.IO.Stream dataOut, out long dataOutWritten)        {            try            {                if (dataIn == null || dataIn.Length == 0)                {                    dataInRead = 0;                    dataOutWritten = 0;                    return FilterStatus.Done;                }                dataInRead = dataIn.Length;                dataOutWritten = Math.Min(dataInRead, dataOut.Length);                dataIn.CopyTo(dataOut);                dataIn.Seek(0, SeekOrigin.Begin);                byte[] bs = new byte[dataIn.Length];                dataIn.Read(bs, 0, bs.Length);                dataAll.AddRange(bs);                dataInRead = dataIn.Length;                dataOutWritten = dataIn.Length;                return FilterStatus.NeedMoreData;            }            catch (Exception ex)            {                dataInRead = dataIn.Length;                dataOutWritten = dataIn.Length;                return FilterStatus.Done;            }        }        public bool InitFilter()        {            return true;        }    }//IRequestHandler实现代码public class RequestHandler : IRequestHandler    {        // 略去代码 ...        public event Action NotifyMsg;        IResponseFilter IRequestHandler.GetResourceResponseFilter(IWebBrowser browserControl, IBrowser browser, IFrame frame, IRequest request, IResponse response)        {            var url = new Uri(request.Url);            if (url.AbsoluteUri.Contains("https://res.wx.qq.com/zh_CN/htmledition/v2/css/base/base2e4e03.css"))            {                var filter = FilterManager.CreateFilter(request.Identifier.ToString());                return filter;            }            return null;        }        void filter_NotifyData(byte[] data)        {            if (NotifyMsg != null)            {                NotifyMsg(data);            }        }        void IRequestHandler.OnResourceLoadComplete(IWebBrowser browserControl, IBrowser browser, IFrame frame, IRequest request, IResponse response, UrlRequestStatus status, long receivedContentLength)        {            if (request.Url.Contains("https://res.wx.qq.com/zh_CN/htmledition/v2/css/base/base2e4e03.css"))            {                var filter = FilterManager.GetFileter(request.Identifier.ToString()) as TestImageFilter;                filter_NotifyData(filter.dataAll.ToArray());            }        }    }

相关文档:

https://github.com/cefsharp/CefSharp/wiki/Quick-Start

.Net(C#) cefsharp Chrome 浏览器控件后台执行Iframe中的Js代码的方法

.NET(C#) cefsharp 设置浏览器默认语言和userAgent及示例代码

.NET(C#) CefSharp CommandLine开关参数配置和读取网页源代码方法及示例代码