C#在指定时间自动填写网页表单 从零开始_c#网页填表-程序员宅基地

不积跬步,无以至千里;不积小流,无以成江海。
————————————————————————————————————————————————————

最近因为某些原因笔者需要频繁的填写表单,在多次错过时间被点名批评后终于决定借助技术的力量拜托重复劳动。笔者之前从未接触过HTML和Javascript,是真正的从零开始,等做完以后发现还是挺简单的。这篇文章记录了我在这个过程中踩过的坑,希望能给大家提供一个参考。

网页分析和程序设计

首先,这是我们实验用的WPS网页表单:
实验用到的表单
在当前网页上,单击鼠标右键——审查元素(或者“查看代码”/“开发人员工具”,浏览器不同选项不同),得到如下页面:
审查元素界面
下方即为本页面的HTML代码。每一个选项和输入框,都对应其中一行,找到相应的代码对我们使用程序自动填表至关重要。在相应元素上点击“审查元素”,即可跳到对应代码上。
下面开始编程。我使用的是VS2017,编程语言为.net4.7.1下的C#。
新建项目,创建windows窗体,在窗体中拖拽一个webbrowser控件,默认命名为“webBrowser1”。这个控件用于模拟浏览器访问网页。
输入网址,跳转:webBrowser1.Navigate("https://f.wps.cn/form-write/KKPn2wCj/");
也可以直接赋值:webBrowser1.Url =new Uri("https://f.wps.cn/form-write/KKPn2wCj/") ;
接下来需要等待网页加载完毕。如果网页没有加载完,代码是读取不到页面内的元素的。C#提供了一些方式用于判断加载状态,比如

  1. webBrowser控件的ReadyState属性,我们可以在循环语句中使用:
    while (webBrowser1.ReadyState==WebBrowserReadyState.Loading) ;
  2. webBrowser控件的webBrowser1_DocumentCompleted()事件,在加载完毕后自动触发。将之后的代码写在事件内就可以。
    但这个网页在加载时会触发多次事件,以上两种方式都无法使用。我简单粗暴的使用了一个定时器,延时几秒后判断是否找得到页面的元素,如果能找的到就说明页面加载完毕了,否则就再等几秒再判断一次。给窗口拖入一个timer控件。
	timer1.Enabled = true;
    timer1.Interval = 1000;

然后在触发中断函数中继续写代码,开始填表。
首先对这个网页进行分析。从网页代码中可以看到,问题1的标签是input,id为“input_0”:
问题1
C#提供了两种方式用于找到你想要的网页元素:GetElementById()和GetElementsByTagName()。既然有id号,那用id是最方便的:

	HtmlDocument doc = webBrowser1.Document;
	doc.GetElementById("input_0").Focus();//姓名
    SendKeys.SendWait("峡谷柔情");//使用模拟按键的方式

这里之所以不用直接修改value的方式doc.GetElementById("input_0").SetAttribute("value", “峡谷柔情”);可能是因为这个网页的问题,点击其他地方后刚修改的值马上会为空。因此笔者通过模拟键盘输入的方式进行填写。
问题2/3/4,网页代码如下:
问题2
对于这种单选框,我们模拟鼠标的点击来完成操作:doc.GetElementById("select_label_wrap_1_1").InvokeMember("click");//单位
问题5比较复杂,笔者作为初学者花了不少时间。点击这一项后会弹出一个日期框,选择日期后自动给value赋值。
日期选择
它的代码如下:
日期选择代码
从代码中可以看到,这是一个picker类:“class=ant-calendar-picker”,它的组成比较复杂,有很多子元素,儿通过id的访问只能到某一个父元素。c#提供了一些访问子元素的方式,如Children[],FirstChildren等。具体问题具体分析,经过我的尝试,第一次模拟点击的代码如下:

 //打开日期选择
    doc.GetElementById("date-common-4").Children[1].Children[0].Children[0].InvokeMember("click");

点击之后会弹出一个日历选择框,在网页代码的后半段也会出现对应的变化:
日历框
找到“今天”按钮对应的代码,我们可以看到这是一个超链接式的按钮:role=“button”。c#对于此类按钮没有相应的方法,但我们知道它的tagname为a,我们可以曲线救国:

//选择今天
	doc.GetElementsByTagName("a")[doc.GetElementsByTagName("a").Count-1].InvokeMember("click");

因为是弹出窗口,所以在相同的标签中,它一定是数组中的最后一个元素。模拟鼠标点击即可。
对于问题6,我们需要结合系统时间做出选择:

	int hour = System.DateTime.Now.Hour;//填写时间
    if (hour >= 6 && hour <= 8)
         doc.GetElementById("select_label_wrap_5_0").InvokeMember("click");
    else if (hour >= 10 && hour <= 12)
         doc.GetElementById("select_label_wrap_5_1").InvokeMember("click");
    else if (hour >= 18 && hour <= 20)
         doc.GetElementById("select_label_wrap_5_2").InvokeMember("click");

之后找到提交按钮对应的代码,模拟点击后,对于弹出的确认窗口用相同手法处理。
对于一张WPS表单,所有可能的问题都在这里了,下面贴上源码:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace FormFillingAssistant
{
    
    public partial class MainForm : Form
    {
    
        public MainForm()
        {
    
            InitializeComponent();
        }
        
        private void MainForm_Load(object sender, EventArgs e)
        {
    
            webBrowser1.Navigate("https://f.wps.cn/form-write/KKPn2wCj/");//加载表单界面
            Timer timer1 = new Timer();
            timer1.Enabled = true;
            timer1.Interval = 1000;
        }

        private void timer1_Tick(object sender, EventArgs e)
        {
    
            HtmlDocument doc = webBrowser1.Document;
            try
            {
    
                doc.GetElementById("input_0").Focus();//姓名
                SendKeys.SendWait("峡谷柔情");//使用模拟按键的方式,直接修改value会无法录入

                //建议使用执行单击事件的方式来设置单选框,而不是修改属性
                doc.GetElementById("select_label_wrap_1_1").InvokeMember("click");//单位
                doc.GetElementById("select_label_wrap_2_0").InvokeMember("click");//居住地
                doc.GetElementById("select_label_wrap_3_0").InvokeMember("click");//共居人员

                int hour = System.DateTime.Now.Hour;//填写时间
                if (hour >= 6 && hour <= 8)
                    doc.GetElementById("select_label_wrap_5_0").InvokeMember("click");
                else if (hour >= 10 && hour <= 12)
                    doc.GetElementById("select_label_wrap_5_1").InvokeMember("click");
                else if (hour >= 18 && hour <= 20)
                    doc.GetElementById("select_label_wrap_5_2").InvokeMember("click");

                doc.GetElementById("input_6").Focus();//体温
                SendKeys.SendWait("36.6");
                
                doc.GetElementById("select_label_wrap_7_0").InvokeMember("click");//本人情况
                doc.GetElementById("select_label_wrap_8_0").InvokeMember("click");//活动轨迹
                doc.GetElementById("select_label_wrap_9_0").InvokeMember("click");//同居者状况
                doc.GetElementById("select_label_wrap_10_1").InvokeMember("click");//居住地情况
                doc.GetElementById("select_label_wrap_11_0").InvokeMember("click");//近十四天
                doc.GetElementById("select_label_wrap_12_0").InvokeMember("click");//其他事

                //打开日期选择
                doc.GetElementById("date-common-4").Children[1].Children[0].Children[0].InvokeMember("click");
                //选择今天
                doc.GetElementsByTagName("a")[doc.GetElementsByTagName("a").Count-1].InvokeMember("click");

                //doc.GetElementById("submit_button").InvokeMember("click"); //提交

                timer1.Enabled = false;//如果网页成功加载则关闭定时器1
                timer2.Enabled = true;//开启定时器2
            }
            catch
            {
    

            }
            

        }
        
            
        private void timer2_Tick(object sender, EventArgs e)
        {
    //在页面上停留一定时间,确认无误后自动提交,并点击确认按钮
            timer2.Enabled = false;
            webBrowser1.Document.GetElementById("submit_button").InvokeMember("click"); //提交
            webBrowser1.Document.GetElementById("bind_phone_modal_confirm_button").InvokeMember("click"); //确认提交
        }
    }
}

计划任务

在“我的电脑”上右击,选择“管理”——“任务计划程序”,“创建基本任务”,设置好调用小工具的时间即可。傻瓜操作,不再赘述。
计划任务

感谢 @卢喵猫 同学的文章https://blog.csdn.net/JCFY1055176872/article/details/104267639?from=timeline,给了我很大的启发。他是用python实现的,经过我的对照,两种编程语言各有优劣,收益颇丰。

萌新写手,烦请各位大佬多多指教。

附上C#中WebBrowser常用的方法和属性汇总:

https://www.cnblogs.com/vaevvaev/p/6980318.html

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/qq_34239846/article/details/104274309

智能推荐

openssl-3.0.0-alpha9编译_all lines in c:/openssl-3.0.9/openssl-3.0.9/extern-程序员宅基地

文章浏览阅读3.5k次。这个通讯传输加密工具,非常厉害。configure 如下之后make和make install就可以了。多谢,亲爱的美美。_all lines in c:/openssl-3.0.9/openssl-3.0.9/external/perl/modules.txt must b

python 写入csv文件固定列_python对csv文件追加写入列的方法-程序员宅基地

文章浏览阅读3.4k次。python对csv文件追加写入列,具体内容如下所示:原始数据[外链图片转存失败(img-zQSQWAyQ-1563597916666)(C:UsersinnduceAppDataRoamingTyporatypora-user-images1557663419920.png)]import pandas as pdimport numpy as npdata = pd.read_csv(r'平均..._numpy写入csv文件一列

2018年世界计算机超算大赛,在世界大学生超级计算机竞赛(ASC18)总决赛中 青海大学超算团队成功获得ASC竞赛全球一等奖...-程序员宅基地

文章浏览阅读216次。5月9日晚,2018ASC世界大学生超级计算机竞赛(ASC18)总决赛在南昌大学落下帷幕,清华大学成功卫冕总冠军,上海科技大学揽获亚军和e Prize计算挑战奖两项大奖,台湾清华大学获得最高计算性能奖。青海大学在此次比赛中取得了突破性的成绩,HPL基准测试性能仅次于台湾清华大学,HPCG性能仅次于清华大学,最终获全球一等奖,展现出优秀的超算系统与应用理解能力以及出色的性能优化能力。ASC18由亚洲..._青海大学超级计算机

asp webForm 三层框架的简单实例(一)未完待续--_asp net web form应用 三层架构部署-程序员宅基地

文章浏览阅读1.1w次,点赞8次,收藏23次。本文通过一个简单的登录实例,介绍了基本的WebForm开发方式的MVC三层框架方式。本文,是个人作为一个初学者,对webform三层框架的总结,配有相应的源代码,希望对同样迷惑的你有所帮助,如果有不对之处敬请批评指导。_asp net web form应用 三层架构部署

人脸比对(1:N)_1:n人脸检索 学术-程序员宅基地

文章浏览阅读2.9w次,点赞12次,收藏81次。第1章 前言设计出人脸1:N,随着N的增大准确率降低最小的解决方案具有很强的现实意义。人脸1:N的框架大致分为:人脸检测、人脸对齐、人脸映射与人脸识别LOSS的设计,结构如下图所示:图1:人脸1:N的主要框架人脸1:N在学术界有着广泛的研究,对于人脸检测与人脸对齐(MTCNN、TCDCN等)在业界已经有较好的效果,目前的主要性能提升有:DeepFace、DeepID,框架为CNN ..._1:n人脸检索 学术

java语言当中的标识符_java语言的标识符-程序员宅基地

文章浏览阅读458次。关于java语言当中的标识符1、什么是标识符?- 在java源程序当中凡是程序员有权利自己命名的单词都是标识符-标识符可以表示什么元素?*类名*方法名*变量名*接口名*常量名......2、标识符命名规则?【不按照这个规则来,编译器会报错,这是语法】*只能由“数字、字母、下划线_、美元符号$”组成,不能含有其他符号*不能数字开头*严格区分大小写*关键字无长度限制,但是最好不要太长3、标识符命名规范?【只是一种规范,不属于语法,不遵守规范编译器不会报_java语言的标识符

随便推点

直接插入排序——华农oj 8638_数组插入排序 oj-程序员宅基地

文章浏览阅读1.1k次。8638 直接插入排序时间限制:1000MS 代码长度限制:10KB提交次数:2050 通过次数:1393题型: 编程题 语言: G++;GCCDescription用函数实现直接插入排序,并输出每趟排序的结果.输入格式第一行:键盘输入待排序关键的个数n第二行:输入n个待排序关键字,用空格分隔数据输出格式每行输出一趟排序结果,数据之间用一个空格分隔输入样例105 4..._数组插入排序 oj

vue element-ui 表格的分页功能_elementui table 分页-程序员宅基地

文章浏览阅读3.5k次,点赞3次,收藏7次。vue element-ui 表格的分页功能_elementui table 分页

用OpenInventor实现的NeHe OpenGL教程-第三十课-程序员宅基地

文章浏览阅读65次。用OpenInventor实现的NeHe OpenGL教程-第三十课 NeHe教程在这节课介绍了碰撞检测。碰撞检测是一种比较复杂的技术。NeHe教程只是检测平面、球体、圆柱体等这些规则物体之间的碰撞检测。OpenInventor提供了任意形状物体之间的碰撞检测,当然这样的碰撞检测需要更多的计算时间。碰撞检测的算法在NeHe的教程中已经做了详尽的解释,我们就不再赘述了。程序的..._openinventor 火焰效果

视频播放加密功能的演示_视频分段加密播放实现-程序员宅基地

文章浏览阅读1.3k次。视频播放密码/设定观看密码功能,对视频文件设置观看权限,划分学员和游客,学员输入正确的密码即可观看视频。_视频分段加密播放实现

vue中用computed简单实现数据的双向绑定(getter 和 setter)_vue computed绑定表单值-程序员宅基地

文章浏览阅读6.2k次,点赞3次,收藏9次。vue是号称实现了数据双向绑定的框架,但事实上在日常开发中我们用的最多的就是 v-model 将data(vue实例中)里面的是数据和view 相关联,实现 data 更新,view自动刷新的效果。但是,在移动成都上来说,这种数据双向绑定的效果并不是特别的明显。今天,我用输入框和 computed 配置来实现一个比较明显的数据双向绑定的效果:先来看一下最终的效果:主要实现的效果:..._vue computed绑定表单值

联想微型计算机C470拆装,联想C470一体机一键U盘重装系统教程图解-程序员宅基地

文章浏览阅读3.7k次。联想C470一体机造型小巧,外观唯美时尚,易于摆放并能脱离冗杂线缆的束缚。该机是一款非常时尚的家用一体电脑,采用21.5英寸触控屏幕,全高清显示相当精细。无论是学习办公,还是家庭娱乐都能够满足用户的需求。下面给大家介绍联想C470一体机一键U盘重装系统教程图解,教大家一体机怎么装系统。相关推荐:联想C470一体机怎么进入bios设置u盘启动准备一个u盘,再下载U盘装机大师启动盘制作工具,把其做成U..._联想c470一体机拆机图解

推荐文章

热门文章

相关标签