浏览器自动化的一些体会3 webBrowser控件之零碎问题

Posted badnumber

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了浏览器自动化的一些体会3 webBrowser控件之零碎问题相关的知识,希望对你有一定的参考价值。

1. 一般需要执行这一句:webBrowser1.ScriptErrorsSuppressed = true;

主要目的是禁止跳出javascript错误的对话框,否则会导致程序无法正确地跑下去。缺点显然是某些真正的javascript错误被掩盖了。但是实践中觉得多数情况下,这一句是有必要的。

2. 解析dom

webBrowser控件提供了一些解析dom的方法,如webBrowser1.Document.GetElementById()。这些方法在处理某些结构较为复杂的dom时会显得不太方便,这时我一般喜欢用htmlAgilityPack这个库来解析dom。

HtmlAgilityPack很强大,但有一个很大问题是,webBrowser里的方法找到所需元素后,可以执行Click等操作,而HtmlAgilityPack不行(因为它不能执行javascript)。所以在需要Click等操作时,我一般用webBrower控件提供的方法,或者干脆换用selenium的webdriver(以后讨论)。

3. 保存图片

主要有两种方法(如果把本贴里第5条的“另存为”也算上,可说有3种方法),一种是先解析dom,获取图片url,然后发httprequest/用webclient下载图片:

https://social.msdn.microsoft.com/Forums/en-US/3cce6004-2b04-46f4-ac2e-b16a9852d62d/how-to-save-imagepicture-from-webbrowser-control?forum=ieextensiondevelopment

主要问题是某些网站需要cookie或其他header时,这种方法就较为麻烦。

另外一种是利用剪贴板:

https://stackoverflow.com/questions/3833718/webbrowser-copy-image-to-clipboard/3833846#3833846

实践中碰到的主要问题是难以保留图片的格式,比如图片本来是png格式,保存后,不管

Bitmap bmp = (Bitmap) Clipboard.GetDataObject().GetData(DataFormats.Bitmap)中的DataFormat设成什么,都无法存成png格式(将保存后文件的大小和直接从网页中“另存为”保存的文件大小对比可看出)。这个问题不知道如何解决。高明教我。

4. session问题

在winform中如果用多个tabpage里的webBrowser控件同时打开同一个url,如果该网站用了session,那么,这几个tabpage里的webBrowser控件将“共享”同一个session。这个有点坑爹。下面用代码来说明:

winform里的代码:

private void winWeb_Load(object sender, EventArgs e)
{//winWeb是个winform,放在一个tabpage里,包含了一个webBrowser控件,这里在load事件中Navigate
            string url = "http://abc.com?a=test";
            int count = Util.GetCount();//Util类里记录当前最大的count值
            count++;//每调用一次(也就是新开一个tabpage)加1
            url += "&count=" + count.ToString();//传给网页,用于区分不同tabpage的session
            webBrowser1.Navigate(url); 
}

网页(asp.net webform)里的代码:

protected void Page_Load(object sender, EventArgs e)
{
                    string count = Request.QueryString["count"];
                    if (String.IsNullOrEmpty(count))
                    {
                        count = "1";
                    }
                    ViewState["Count"] = count;//保存在ViewState里,因为网页其他部分也要用
                    int pID = Convert.ToInt32(Request.QueryString["pid"]);
                    Session[ViewState["Count"].ToString() + "SelectedOID"] = pID;//创建session,用count值来实现不同tabpage打开的网页有不同的session,否则就“共享” session了                  
                   
}

 

5. “另存为”

如何用代码来实现浏览器里右击鼠标,然后点“另存图片为”的行为?如果用的是webBrowser控件,似乎没有太好的办法,只能估算屏幕坐标,然后模拟鼠标行为,这里贴一段虽然work(针对程序中所处理的网页而言,如果用在别的网页中,显然要做一点修改),但显然很笨拙的代码:

private void webBrowser1_DocumentCompleted(object sender, WebBrowserDocumentCompletedEventArgs e)
{
                timer1.Stop();
                timer1.Start();
}

        private void timer1_Tick(object sender, EventArgs e)
        {
            timer1.Stop();
            Point controlLoc = this.PointToScreen(webBrowser1.Location);
            controlLoc.X = controlLoc.X + webBrowser1.Document.GetElementById("memu6").OffsetRectangle.Left + 200;//找到鼠标右击的位置
            controlLoc.Y = controlLoc.Y + webBrowser1.Document.GetElementById("memu6").OffsetRectangle.Top + 150;
            Cursor.Position = controlLoc;
            MouseAndKeySimulator.ClickRightMouseButton();//MouseAndKeySimulator顾名思义是一个模拟鼠标和键盘时间的第三方类
            timer2.Stop();//因为是模拟点击,需要有一定的延时,这里用timer实现
            timer2.Start();
        }

        private void timer2_Tick(object sender, EventArgs e)
        {
            timer2.Stop();
            var newX = Cursor.Position.X + 10;
            Point newPoint = new Point();
            newPoint.X = newX;
            newPoint.Y = Cursor.Position.Y;
            Cursor.Position = newPoint;
            MouseAndKeySimulator.PressKey(Keys.G, true);
            MouseAndKeySimulator.PressKey(Keys.G, false);//模拟键盘操作,下移到“图片”菜单项
            for (int i = 0; i < 3; i++)
            {//模拟键盘操作,下移到“另存图片为”菜单项
                MouseAndKeySimulator.PressKey(Keys.Up, true);
                MouseAndKeySimulator.PressKey(Keys.Up, false);
            }
            MouseAndKeySimulator.PressKey(Keys.Enter, true);//打开“保存图片”对话框
            MouseAndKeySimulator.PressKey(Keys.Enter, false);
            timer3.Stop();//打开对话框也需要延时
            timer3.Start();
        }

        private void timer3_Tick(object sender, EventArgs e)
        {
            timer3.Stop();
            MouseAndKeySimulator.PressKey(Keys.Enter, true);//用缺省的文件名保存图片,如果要换名保存,这里还得模拟键盘输入文件名
            MouseAndKeySimulator.PressKey(Keys.Enter, false);
            timer4.Stop();//这个是为了处理下一个图片的,代码这里从略
            timer4.Start();
        }

以后再讨论selenium的webdriver时,可能还会提到类似功能,就会发现实现起来容易多了。在模拟鼠标和键盘行为方面,webBrowser控件没有提供什么支持,实现起来比较费劲。

以上是关于浏览器自动化的一些体会3 webBrowser控件之零碎问题的主要内容,如果未能解决你的问题,请参考以下文章

浏览器自动化的一些体会4 webBrowser控件之零碎问题2

怎样让webbrowser执行JS脚本正常显示网页

具有自动代理登录的 WebBrowser 控件

WinForm WebBrowser 控件背景颜色

.Net 中的缓存和 WebBrowser 控件

外部 WebBrowser 控件浏览?