起因
工作需要,为了简化一些数据的处理流程,于是乎我决定用VBA来做,没办法,谁让那些处理数据的模板都是xlsm呢!
原来的流程
- 登录某个内网网站,其实就是个网盘,目录很多
- 一级一级展开,找到要下载的数据文件
- 更改模板文件名字与数据文件同名
- 打开模板,执行处理相关宏
- 检查处理结果
现在的流程
- 打开模板文件,点击绑定宏的按钮,等待完成,目视检查即可。
简化关键点
- 自动下载文件
- 下载文件后自动执行处理数据的宏
相关库
- 为了现代化一点,登录网站和下载选择了WinHttpRequest
- 返回数据是字典形式的,选用了VBA-JSON/JsonConverter
- 写入文件选择的是Adodb.Stream这个库,写入的内容是IWinHttpRequest::ResponseBody
注意点
- WinHttpRequest默认保持cookie,不需要操心。一开始因为犯了一个小错误(以为登录失败,实际上登陆成功),我还一直在找原因,以为是要手动处理cookie,然后就把IWinHttpRequest.Option(WinHttpRequestOption_EnableRedirects) = False了,最后发现不是,算是踩了坑。
- 通过Open写入二进制数据(ResponseBody),文件的开头始终会多一些数据,没有找到原因,最后使用Adodb.Stream搞定。
- Function如果返回的是Object,那么形式应该是这样的,即赋值的时候要用Set,调用的地方也要用Set,如果是常规的类型则两个地方都不用Set,用了反而会错:
Function BeCallFunc(Param1 As String) As Object
Dim res As Object
' ...
Set BeCallFunc = res
End Function
Sub MainSub()
Dim MainRes As Object
Dim MainParam1 As Object
Set MainRes = BeCallFunc(MainParam1)
End Sub
- As的大小写机制没有搞明白,似乎是在同一个函数里面同是一个模式,即都是As或都是as即可。
- 代码放到VBA是编辑器里面后,相关的代码大小写会自动调整,中文粘贴进去会正常,但是从VBA里复制出来会乱码,暂时没有查怎么避免。
- 有些函数的库需要提前在工具-引用里面选上,同系列(不同版本)的库只能用一个。
- base64的转换用的是Microsoft XML 3.0,这个网上一搜就能找到。
- 最好不要再VBA的编辑器里面敲代码,因为这是真的不好写,虽然有些代码提示是有帮助的。令人难受的点有什么呢,比如你回车选择它的提示,然后会给你多个换行出来,我也不知道这是怎么想的,可能需要系统性学习下才知道怎么操作可以避免这个。另外比如你选中剪切了一部分代码,会直接报错,说你代码格式/参数什么的不对,我知道不对呀!我这不是在改吗。。
- 运行时报错你找不到在哪里,它就是说你错了,貌似只有明显的语法错误才会标红,其他的BUG个人经验是先运行到指定的光标位置,然后F8逐语句比较好定位。
- 如果预先通过Dim定义了类型,那么赋值时,值会被转换到被赋值变量的类型。
- 如果想执行宏,但文件又不能是xlsm,那么请通过Open的方式,激活要操作的文件,然后跑VBA代码。
碎碎念
- Mid函数用于截取字符串,值得注意的是,截取开始位置是1,而非编程中常常使用0作为开始,也许这是为了方便非编程人员吧,不过我是很难受。。
- Shell command可以执行command命令,注意这里的command可以是其他exe,执行cmd的话一般就是 Shell "cmd /c ...",没错这里是一个字符串。
- VBA中如果你要输出一个引号("),那么请把它写成两个即可,即两个引号代表一个引号,例如"""0"""实际上是
"0"
。 - 连接字符串可以用+也可以用&。
- Object对象的函数传递参数,根据我目前的经验,如果要返回值,那么用res = obj.callfunc(param1, param2),不需要的话就是obj.callfunc param1, param2,否则报错是语法错误,没错就是这么神奇。。
- WinHttpRequest要把请求头删掉的话SetRequestHeader传入header的值和NULL即可,不过由于抓包失败,没有验证到底是Null,还是”null“,还是"",网上也没搜到例子。。
- 调试的时候,看变量相关属性和值,是在本地窗口,立即窗口是console,Debug.Print之类的输出会在这里显示,不过本地窗口的信息量有限。
- 代码提示很渣。。
其他的想起来再补充。
有些数据方面的爬虫倒是可以基于Excel来做,就是写成VB代码不太方便。