如何在第三人的网站上以编程方式提交某些 ID 的表格

Posted

技术标签:

【中文标题】如何在第三人的网站上以编程方式提交某些 ID 的表格【英文标题】:How to programatically submit form of certain ID on 3rd person's website 【发布时间】:2014-12-15 13:27:20 【问题描述】:

在网站上:http://www.e-korepetycje.net/ 有用于登录的表单:

<form method="post" action="http://www.e-korepetycje.net/zaloguj" id="login-box">
   <fieldset>
      <ul>
         <li><input type="text" name="login" placeholder="Login or email"></li>
         <li><input type="password" name="passwd" placeholder="Password"></li>
         <li><input type="submit" value="Log in"></li>
      </ul>
   </fieldset>
</form>

我想填写输入字段loginpasswd,然后通过C# 以编程方式提交此表单。

我见过THIS TOPIC,但最受好评的答案只是一些没有引用相关 html 的代码,并且没有响应引用的 HTML,因此很难理解


更新

我使用了 Adriano Repetti 的答案。我在这里遇到异常var inputField = Descendants(form).First(x =&gt; x.GetAttribute("name") == "login"); 序列不包含指定元素 (InvalidOperationException)。

使用系统; 使用 System.Collections.Generic; 使用 System.ComponentModel; 使用 System.Data; 使用 System.Drawing; 使用 System.Linq; 使用 System.Text; 使用 System.Threading.Tasks; 使用 System.Windows.Forms;

命名空间 WindowsFormsApplication1 公共部分类Form1:Form 公共表格1() 初始化组件(); WebBrowser wb = new System.Windows.Forms.WebBrowser(); wb.DocumentCompleted += wb_DocumentCompleted; wb.Navigate("http://www.e-korepetycje.net/"); Console.WriteLine("导航后"); 公共静态 IEnumerable 后代(HtmlElement 根) foreach(root.Children 中的 HtmlElement 子项) 产生返回子;

            if (!child.CanHaveChildren)
                continue;

            foreach (var subChild in Descendants(child))
                yield return child;
        
    

    static void wb_DocumentCompleted(object sender, WebBrowserDocumentCompletedEventArgs e) 

        WebBrowser wb = ((WebBrowser)sender);
        if (e.Url.AbsolutePath == (sender as WebBrowser).Url.AbsolutePath) 
            Console.WriteLine("COMPLETED");
            //HtmlElementCollection elems = wb.Document.GetElementsByTagName("HTML");
            //Console.WriteLine(elems[0].OuterHtml);
            var form = wb.Document.GetElementById("login-box");
            Console.WriteLine(Descendants(form).Count());


            var inputField = Descendants(form).First(x => x.GetAttribute("name") == "login");
            inputField.SetAttribute("value", "login");

            inputField = Descendants(form).First(x => x.GetAttribute("name") == "passwd");
            inputField.SetAttribute("value", "passwd");

            var submitButton = Descendants(form).First(x => x.TagName == "input" && x.GetAttribute("type") == "submit");
            submitButton.RaiseEvent("click");
        


    


输出

After navigate
'WindowsFormsApplication1.vshost.exe' (CLR v4.0.30319: WindowsFormsApplication1.vshost.exe): Loaded 'C:\Windows\assembly\GAC\Microsoft.mshtml\7.0.3300.0__b03f5f7f11d50a3a\Microsoft.mshtml.dll'. Module was built without symbols.
COMPLETED
'WindowsFormsApplication1.vshost.exe' (CLR v4.0.30319: WindowsFormsApplication1.vshost.exe): Loaded 'C:\Windows\Microsoft.Net\assembly\GAC_MSIL\System.Core.resources\v4.0_4.0.0.0_pl_b77a5c561934e089\System.Core.resources.dll'. Module was built without symbols.
A first chance exception of type 'System.InvalidOperationException' occurred in System.Core.dll
12
'WindowsFormsApplication1.vshost.exe' (CLR v4.0.30319: WindowsFormsApplication1.vshost.exe): Loaded 'C:\Windows\Microsoft.Net\assembly\GAC_MSIL\System.Configuration\v4.0_4.0.0.0__b03f5f7f11d50a3a\System.Configuration.dll'. Skipped loading symbols. Module is optimized and the debugger option 'Just My Code' is enabled.

更新 2

我也试过了:

var inputField =  wb.Document.GetElementsByTagName("text")["login"];

但它返回null

【问题讨论】:

@DeeMac 两者都不是,它是控制台应用程序。该网站不是我的,我想填写此表格:e-korepetycje.net 并通过代码提交。 好的,我明白了。这个问题具有很大的误导性——起初,我假设您想使用 C# 来执行通常由 JS 处理的某种客户端功能。我会认为这是通过传入相关凭据向服务器发出 Web 请求的情况,在这种情况下 - 这不正是该答案所暗示的吗? @DeeMac 答案(在其他主题中)没有从action="http://www.e-korepetycje.net/zaloguj" 表格中说明在哪里使用action 也没有说明这些String strPost = "username="+username+"&amp;password="+password+"&amp;firstname="+firstname+"&amp;lastname="+lastname; 是表格中输入字段的名称等.问题是答案的作者没有发布他的代码引用的HTML,所以它不是自我解释的代码。 相信阿德里亚诺已经给你一个彻底的答案了。我可以问(纯粹出于好奇)你在做什么/为什么要这样做? @Yoda 文档为空,因为下载和 DOM 解析未完成。在 DocumentCompleted 事件中添加您的代码(用于搜索和填写表格)(更新答案以使其清晰)。 【参考方案1】:

以编程方式与网站交互(来自 C# 应用程序)IMO 的最简单方法是使用 WebBrowser 控件:

WebBrowser wb = new System.Windows.Forms.WebBrowser();
wb.Navigate(" http://www.e-korepetycje.net/");

现在该网站已加载到嵌入式 Web 浏览器(基于 IE)中。您可以注入一些 javascript 代码来执行此任务,但来自 C# 的代码也很容易。文档下载和 DOM 解析完成后,您可以找到表单(使用其 ID)。将所有后续代码放入wb.Document.DocumentCompleted 事件处理程序中(如果您愿意,也可以等待wb.Document.DocumentStatus 属性)。

var form = wb.Document.GetElementById("login-box");

然后在里面找到提交按钮:

var submitButton = form
    .Descendants()
    .First(x => x.TagName == "input" && x.GetAttribute("type") == "submit");

然后模拟一次点击:

submitButton.RaiseEvent("click");

我使用了一个小辅助函数来遍历 HtmlElement 的所有子代:

public static IEnumerable<HtmlElement> Descendants(this HtmlElement root)

    foreach (HtmlElement child in root.Children)
    
        yield return child;

        if (!child.CanHaveChildren)
            continue;

        foreach (var subChild in Descendants(child))
            yield return child;
    

顺便说一句,如果你想注入 JavaScript 代码,它必须是这样的(当然,你需要更多的代码来使用 Document.CreateElement() 创建脚本函数并使用 Document.InvokeScript() 调用它):

document.forms["login-box"].submit();

请注意,同样的技术也可以用于填写表格:

var inputField = form
    .Descendants()
    .First(x => x.GetAttribute("name") == "login");

inputField.SetAttribute("value", "login name to post");

当然,所有这些代码都可以泛化到足以被重用...

【讨论】:

@yoda 这是一种自定义扩展方法(我包含了代码)。要以这种方式使用它,您必须将它放在另一个静态类中,否则只需重构以删除“this”。 谢谢你能看看 OP 的更新吗?文件完成后,我询问该表格的后代并打印它们的数量,其中有 0 个。这是wb_DocumentCompleted的第三行。【参考方案2】:

你可以创建一个windows窗体,添加WebBrowser控件,然后设置url到网站。将 url 加载到浏览器控件后,您可以访问 Document 属性以使用 InvokeScript(script) 方法调用脚本(填充用户 ID 和密码并提交表单)。

【讨论】:

以上是关于如何在第三人的网站上以编程方式提交某些 ID 的表格的主要内容,如果未能解决你的问题,请参考以下文章

如何在 iOS 上以编程方式将视频上传到 Vine?

如何在 iOS 上以编程方式将视频上传到 Vine?

无法在 iOS 上以编程方式调整 UITableView 的大小

在 android 上以编程方式安装 APK

在编辑表单上以编程方式选择自动完成设置值 ngModel

在 android 4.0 上以编程方式设置 *** 连接