打开网络浏览器,自动完成表单组件并提交。

13

我们目前正在调查一种创建WPF/winforms应用程序的方法,使我们可以在内部设置它来:

  1. 自动打开一个新的浏览器实例到预定义的URL
  2. 自动填写所需的字段与预定义的数据
  3. 自动提交表单并等待下一页加载
  4. 自动完成所需的字段与预定义的数据 (第2页)
  5. 自动提交表单并等待下一页加载 (等等)

经过多次调查,我们唯一发现的是通过以下方式打开Web浏览器:

object o = null;

SHDocVw.InternetExplorer ie = new SHDocVw.InternetExplorer();
IWebBrowserApp wb = (IWebBrowserApp)ie;
wb.Visible = true;
wb.Navigate(url, ref o, ref o, ref o, ref o);

希望您能就如何完成该过程提供建议/阅读推荐,谢谢。

3个回答

25

我为在HTML页面中填写元素编写了一个示例。你必须像这样做:

Winform


Winform

public Form1()
        {
            InitializeComponent();
            //navigate to you destination 
            webBrowser1.Navigate("https://www.certiport.com/portal/SSL/Login.aspx");
        }
        bool is_sec_page = false;
        private void webBrowser1_DocumentCompleted(object sender, WebBrowserDocumentCompletedEventArgs e)
        {
            if (!is_sec_page)
            {
                //get page element with id
                webBrowser1.Document.GetElementById("c_Username").InnerText = "username";
                webBrowser1.Document.GetElementById("c_Password").InnerText = "pass";
                //login in to account(fire a login button promagatelly)
                webBrowser1.Document.GetElementById("c_LoginBtn_c_CommandBtn").InvokeMember("click");
                is_sec_page = true;
            }
            //secound page(if correctly aotanticate
            else
            {
                //intract with sec page elements with theire ids and so on
            }

        }

Wpf

public MainWindow()
        {
            InitializeComponent();
     webBrowser1.Navigate(new Uri("https://www.certiport.com/portal/SSL/Login.aspx"));
            }
            bool is_sec_page = false;
            mshtml.HTMLDocument htmldoc;
            private void webBrowser1_LoadCompleted(object sender, NavigationEventArgs e)
            {
                htmldoc = webBrowser1.Document as mshtml.HTMLDocument;
                if (!is_sec_page)
                {
                    //get page element with id
                    htmldoc.getElementById("c_Username").innerText = "username";
                    //or
                    //htmldoc.getElementById("c_Username")..SetAttribute("value", "username");
                    htmldoc.getElementById("c_Password").innerText = "pass";
                    //login in to account(fire a login button promagatelly)
                    htmldoc.getElementById("c_LoginBtn_c_CommandBtn").InvokeMember("click");
                    is_sec_page = true;
                }
                //secound page(if correctly aotanticate
                else
                {
                    //intract with sec page elements with theire ids and so on
                }
            }

只需导航至特定的URL并填写页面元素即可。


谢谢您的快速回复。然而,这使用了winform上内置的浏览器控件,而不是打开一个新的浏览器实例。这是唯一的方法吗(推荐的方式?) - Simon
@user2009091:你在使用WPF吗? - KF2
啊,是的,这就是我们一直在寻找的东西...然后实现 while (gmailurl.Busy) { System.Threading.Thread.Sleep(100); } 以允许页面完成后再输入其他数据。您推荐任何额外的阅读材料来补充吗? - Simon
@user2009091:我认为这个dll没有包含任何关于页面加载的事件,相反你可以使用一个计时器并检查表单中的一个元素是否存在,如果存在则表示页面已经完全加载(如果我的描述有帮助,请标记为答案:D)。 - KF2
嘿@KF2,我喜欢这个答案,是否有一种类似的方法,可以使用登录令牌来处理? - Rafael
显示剩余4条评论

7
如果我理解正确,您想在Web浏览器中打开某个URL,然后像普通用户一样与该网站进行交互。对于这样的任务,我可以建议您查看Selenium。虽然它通常用作回归测试自动化工具,但没有人能阻止您将其用作浏览器自动化工具。
Selenium拥有详细的文档和庞大的社区。最可能您会想要使用Selenium WebDriver,它可以通过nuget获得。
下面是一个典型的Selenium“脚本”示例(直接摘自文档):
// Create a new instance of the Firefox driver.

// Notice that the remainder of the code relies on the interface, 
// not the implementation.

// Further note that other drivers (InternetExplorerDriver,
// ChromeDriver, etc.) will require further configuration 
// before this example will work. See the wiki pages for the
// individual drivers at http://code.google.com/p/selenium/wiki
// for further information.
IWebDriver driver = new FirefoxDriver();

//Notice navigation is slightly different than the Java version
//This is because 'get' is a keyword in C#
driver.Navigate().GoToUrl("http://www.google.com/");

// Find the text input element by its name
IWebElement query = driver.FindElement(By.Name("q"));

// Enter something to search for
query.SendKeys("Cheese");

// Now submit the form. WebDriver will find the form for us from the element
query.Submit();

// Google's search is rendered dynamically with JavaScript.
// Wait for the page to load, timeout after 10 seconds
WebDriverWait wait = new WebDriverWait(driver, TimeSpan.FromSeconds(10));
wait.Until((d) => { return d.Title.ToLower().StartsWith("cheese"); });

// Should see: "Cheese - Google Search"
System.Console.WriteLine("Page title is: " + driver.Title);

//Close the browser
driver.Quit();

个人建议将脚本按照用户操作(注册、登录、填写表单、在网格中选择某些内容、筛选网格等)进行思考和组织。这样可以使脚本具有良好的结构和可读性,而不是杂乱无章的硬编码代码块。在这种情况下,脚本可能类似于以下内容:
// Fill username and password
// Click on button "login"
// Wait until page got loaded
LoginAs("johndoe@domain.com", "johndoepasswd"); 

// Follow link in navigation menu
GotoPage(Pages.Reports); 

// Fill inputs to reflect year-to-date filter
// Click on filter button
// Wait until page refreshes
ReportsView.FilterBy(ReportsView.Filters.YTD(2012)); 

// Output value of Total row from grid
Console.WriteLine(ReportsView.Grid.Total);

太棒了!我已经寻找这种解决方案好几天了。 - B.K.
非常好的答案!谢谢! - Yang Zhang

2
if (webBrowser1.Document != null)
{
  HtmlElementCollection elems = webBrowser1.Document.GetElementsByTagName("input");
  foreach (HtmlElement elem in elems)
  {
    String nameStr = elem.GetAttribute("name");

    if (nameStr == "email")
    {
      webBrowser1.Document.GetElementById(nameStr).SetAttribute("value", "test_email@mail.com");
    }
  }
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接