CefSharp使用教程二

1.讀取網頁源代碼

在頁面加載完成後處理, 依賴最低環境 4.5.2

async void browser_FrameLoadEnd(object sender, FrameLoadEndEventArgs e)  
{  
    Log.WriteLog("browser_FrameLoadEnd:" + e.Url);  

    var result = await browser.GetSourceAsync();  
} 

如果想在4.0下環境操作需要使用。

 var task = browser.GetSourceAsync();  
 task.Wait();  
 string content = task.Result;  

2.獲取頁面中的指定文件內容(.jpg,.js等)

A.首先需要對ChromiumWebBrowser 的 IRequestHandler RequestHandler進行實現。
B.需要對 IRequestHandler 的IResponseFilter IRequestHandler.GetResourceResponseFilter 方法進行重寫。
C.需要寫一個類實現 IResponseFilter 接口。
D.然後就可用在IResponseFilter 的
FilterStatus Filter(Stream dataIn, out long dataInRead, Stream dataOut, out long dataOutWritten) 方法中,讀取指定內容的流了。

3.過濾某些頁面內容,例如圖片或某些文字

具體實現,參考 2 ,在最後的Filter方法中,對返回的dataOut不進行賦值或者,取到值,然後replace處理,返回其他數據,即可。

4.文件進一步獲取,獲取完整內容

說明:由於很多文件無法獲取到完整內容,再者具體文件內容在Filter裏面進行了控制,而Fileter的內容依賴於IRequestHandler所以,外部只能操作Handler得到數據。 所以需要在,Filter和Hanlder類中,使用事件來傳遞具體的內容。代碼如下。 Filter類如下:

public class TestImageFilter : IResponseFilter  
    {  
        public event Action<byte[]> NotifyData;  
        private int contentLength = 0;  
        private List<byte> dataAll = new List<byte>();  

        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;  
        }  
    }  

Filter類有了,那我們如何知道數據流的具體長度呢?這就需要在Handler的實現的其他方法裏面尋找了。

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<byte[]> 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中控制從而得到整個數據的真正長度。

5.文件進一步獲取,獲取完整內容(優化,Content-Length不一致)

由於,部分站點,返回數據是分片了的,即:不能通過,Content-Length的長度來判斷,程序的流是否完成。
所以需要其他方式處理,即:單個http請求完成的時候,會調用Complete方法,所以可以在這裏處理。
下面是測試代碼: Filter管理類

public class FilterManager
    {
        private static Dictionary<string, IResponseFilter> dataList = new Dictionary<string, IResponseFilter>();

        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];
            }
        }
    }

TestFilter類,對流進行合併

public class TestImageFilter : IResponseFilter
    {
        public List<byte> dataAll = new List<byte>();

        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<byte[]> 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());
            }
        }
    }
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章