作为一个数据控,爱好各种实时数据,比如中央气象台的气象雷达数据。最近在进行的一个HTML5项目,就是利用Canvas和WebGL,把外观土鳖的官方数据,变成洋气+实用的交互式地图。由于HTML5 Canvas CORS的限制,在没有服务器配合的情况下,无法跨域载入图片,然后getImageData
,因此就做了一个爬虫。
经过一番试验,发现国外的免费云服务只有GAE能够访问nmc.gov.cn,确定爬虫在GAE上安家了。大致计算了下数据量,全国167个雷达站,平均10分钟更新1帧,每帧是一幅约35KB的GIF图像,一天下来就至少800+M的数据,放GAE上不现实。同时前端也需要.json
文件,描述雷达站信息以及数据帧列表,所以还需要数据库存储,而GAE坑爹的datastore quota,一天只能5w次读写,爬虫大概跑3圈就爆了。在这样一些约束下,最后脑洞大开的结合GitHub API,把数据全存到一个GitHub repository里,然后再把git tree拖回来当数据库用,解决问题。
目前在GAE上部署了两个实例,分时运行,因为bandwidth quota大概只能支撑半天,然后每天删除repository重建一次,避免超过GitHub的quota。
除了爬图片,地图叠加层的对其需要知道雷达站的坐标,以及数据的范围(即图片上的“数据范围:xxx km”),前者通过之前人肉爬到的一个包含全国雷达站坐标的xml文件解决问题。
至于数据范围没有找到官方的数据,最后写了一个简单的OCR算法直接从图片上识别。
附记:用GitHub API创建commit流程
GitHub提供了Content API,可以方便的对单个文件进行CRUD操作,每次操作产生1个commit。
如果需要一次commit多个文件(比如这个爬虫每次cron会新增数百文件),这样显然不实际。
更好的做法是通过Git Data API,模拟git创建一次commit的过程。
之前做git私有传输协议的经验立即发挥作,轻车熟路的解决,流程如下:
- 用Blob API为每个文件创建一个blob
- 用Tree API为每个子文件夹创建一个tree,并添加其中文件对应的blob
- 用Commit API读出要commit分支最新的commit,以及commit对应的tree
- 创建root tree,未改变的文件/文件夹需要原封不动的在tree里面保留,插入/替换新增的blob/tree
- 创建commit,tree指向新的root tree,parent指向分支最新commit
- 用Reference API更新分支的ref,指向新创建的commit
如果操作中断或重复操作,blob/tree都不会导致多余的数据产生(纯浪费上传带宽而已)。
因为git用SHA1 Digest作为所有git object的文件名,同内容的blob/tree不会重复。
需要注意一个例外,commit由于包含了时间戳,会重复创建。
当然最好封装好的library,会省不少事。
比如我在这个项目里用到的python library是PyGitHub,几个月前给这个项目发过pull request增加了些功能,比较熟悉用起来顺手。
链接
- 源码: radar-bot
- 爬到的数据:data
- OCR工具:Frame Range OCR