造个系统做金融 027 数据采集器的进化:自动化的起点

();

陈帆把手机塞回裤兜,没回短信,也没再看第二眼。他转身走进街角的公用电话亭,投币拨通了市科委实验室的线路。电话响了四声,自动答录机启动,他听见自己三天前录下的测试语音:“服务器运行正常,数据采集器待命。”他挂了电话,抬脚往老城区方向走。

天快黑了,风从巷口斜穿过来,吹得他衣角贴在腿上。他走得不快,脑子里还在过刚才那条短信的措辞。不是深圳那边问你——是“**深圳那边问你**”。七个字,没称呼,没落款,却像一道指令落下来。他没去想背后是谁,只清楚一件事:系统现在必须更快、更独立,不能再依赖任何人的接口,也不能再卡在人工录入的瓶颈上。

三轮车停在教学楼后门,他把背包和一台二手扫描仪搬下来,锁好车,直奔三楼307教室。

门一推开,灰尘在斜照进来的路灯下浮着。他没开大灯,只拧亮桌边的台灯,屏幕映出他刚进门时的脸。服务器风扇转着,绿色指示灯稳定闪烁,数据库日志显示最后一次更新在二十分钟前,是他离开证券公司前设定的自动同步任务。他插上U盘,把今天带出的核心参数导入本地环境,然后打开一个命名为“DataCapture”的文件夹。

里面是过去三个月他亲手抄录的《中国证券报》剪报电子版,共八十七张表格,每一行数字都来自凌晨四点的逐字核对。他盯着这些数据看了一会儿,双击运行新写的OCR识别程序。

界面弹出来,灰底黑字,没有图形按钮,只有一行提示:“加载模板库中……”

几秒后,弹出进度条。第一张报纸扫描图被载入,系统开始逐行扫描表格区域。边缘增强算法启动,图像变清晰了些。识别进程跳到30%时,程序卡住,内存溢出提示跳出。他关掉窗口,调低分辨率,重新运行。

第三次尝试,识别完成。结果对比显示,印刷体数字准确率92.1%,但手写批注区错误频发,尤其是“—”和“0”混淆,“6”被认成“8”。他记下错误类型,打开代码编辑器,手动添加规则:当字符高度低于阈值且笔画闭合不全时,优先匹配负号;连续两个相似误判则触发人工复核标记。

他保存更新版本,重命名程序为“DataHarvester_v0.2”,然后放进后台定时任务,每小时自动处理一张新扫描图。屏幕右下角时间跳到晚上八点二十三分,第一轮测试结束,六张报纸数据成功转入Access数据库,仅三处需人工干预。

他正准备记录日志,门外传来脚步声。

林悦推门进来,手里提着饭盒,发梢沾了点雨气。她把饭放在桌上,没说话,先看了眼显示器。“又通宵?”

“还没开始。”他说,顺手点了点鼠标唤醒屏幕,进度条正跳向第七张。

她走近看:“这东西真能认字?”

“现在能认九成。”他靠在椅背上,声音有点哑,“剩下的,得人来补。”

“哪九成?”她问。

“印的。手写的不行。”

她拉开椅子坐下,接过鼠标:“那我就补手写的。”

他没拦她。她打开另一台终端,调出原始扫描图与识别结果对照界面,一边核对一边标注修正项。两人没再说话,只有键盘敲击声和偶尔的提示音。窗外天色彻底暗下来,远处高架桥上的车灯拉出细长的光带。

到夜里十一点,三十二张报纸数据完成迁移。林悦揉了揉眼睛,指着其中一条记录:“这个‘涨幅’后面的手写数字,你看是‘5.3’还是‘6.3’?”

他凑过去看,放大图像。纸面有折痕,墨迹晕开了一角。他拖动对比工具,调出同一位置的前日报纸字体样本,比对笔锋走向。

“是5。”他说,“收笔没有上挑。”

她点头,输入修正值,提交入库。

静了几秒,她忽然说:“你说机器是为了省时间,不是替人。可你现在做的,是不是让机器慢慢学会替你做决定?”

他摇头:“它只是读字。怎么用这些字,还是人在定。”

她没再问,合上笔记本,起身收拾饭盒。走到门口时,她停下,从包里抽出一张便签纸,写下一行字,贴在显示器边框上:“别忘了睡觉。系统重要,人更重要。”

门关上后,教室只剩他一个人。

他盯着那张便签看了两秒,转头看向服务器状态面板。网络连接正常,硬盘读写频率稳定。他打开另一个项目目录,双击进入“WebCrawler_Test”文件夹。

这是他昨天就开始写的网页抓取脚本。基于VBScript,调用WinInet API模拟请求,目标是“新浪财经”首页的早盘快讯栏。他知道1998年的网站大多不用动态加载,内容直接嵌在HTML里,只要找到规律,就能批量提取。

他启动程序。

命令行窗口闪出几行返回码,接着输出一段HTML源码。标题抓到了,发布时间也解析出来,但正文链接全部为空。他检查网页结构,发现部分条目用了JavaScript跳转,而他的脚本无法执行脚本代码。

他改用最笨的办法:手动分析URL规则。发现某些栏目页面的路径遵循“year/month/day_news_编号.html”格式。他根据当天日期生成一组预测链接,逐个发起请求。

第四个链接成功返回内容。是一条关于央行票据发行的消息,共三百二十七字。他让程序将文本清洗后存入数据库,并标记来源和时间戳。

效率很低。每请求一次,拨号网络要等待十五到四十秒,断线两次后自动重拨。他设定循环间隔为六分钟,预计每小时最多抓取十条有效信息。

凌晨一点十七分,爬虫完成首轮二十四小时周期测试。共获取八十三条新闻记录,其中完整正文五十九条。他导出数据,与当日《中国证券报》进行交叉比对,重复率64%,新增信息源来自地方股评栏目和交易所公告摘要。

他靠在椅背上,闭眼三分钟,脑子却还在跑流程。OCR识别已经半自动化,每天能消化三十张报纸;网络爬虫虽然慢,但只要不断线,就能持续填充数据库。这两条数据流一旦并行运转,系统的更新频率就能从“每日手动推送”变成“准实时滚动”。

他睁开眼,打开数据库管理界面,新建一个名为“DataSource_Merge”的视图,将OCR录入表与爬虫抓取表按时间戳合并。刷新后,屏幕上出现一条连续的时间轴,最早是早上六点零三分,一条关于外汇牌价调整的简讯,来自网页抓取;最新一条是七点四十八分,某钢铁厂产能扩张的报道,来自昨日报纸扫描。

中间没有断层。

他手指停在回车键上,又按了一次刷新。数据流缓缓推进,像一条开始流动的河。

他打开记事本,写下一行部署计划:

- 明早八点,扫描剩余报纸;

- 上午优化OCR误判规则;

- 下午重构爬虫逻辑,加入断点续传和失败重试机制;

- 晚上测试双源数据自动校验功能。

写完,他**一张空白CD-R,将整个“DataHarvester_v0.2”项目打包刻录。光驱读写完毕,他取出光盘,在标签上写下日期和版本号,放进抽屉。

抬头看墙上的挂钟,指针指向两点零五分。

他没动,也没起身关机。服务器风扇依旧低鸣,屏幕上的数据流仍在缓慢更新。他盯着最新一条入库记录的发布时间,轻声说:“开始了。”

就在这时,电话响了。