| |
|
开发:
C++知识库
Java知识库
JavaScript
Python
PHP知识库
人工智能
区块链
大数据
移动开发
嵌入式
开发工具
数据结构与算法
开发测试
游戏开发
网络协议
系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程 数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁 |
-> 开发工具 -> git-history:一款用于分析保存在Git和SQLite中的网页抓取数据的工具 -> 正文阅读 |
|
[开发工具]git-history:一款用于分析保存在Git和SQLite中的网页抓取数据的工具 |
大多数人都知道Git scraping,这是一种网页抓取工具编程技术,你可以定期将数据源快照抓取到Git存储库来跟踪数据源随时间的变化。 如何分析这些收集到的数据是个公认的难题。git-history正是我为解决这个难题而设计的工具。 Git scraping技术回顾 抓取数据到Git存储库的一大优势在于,抓取工具本身非常简单。 这里有一个具体的例子:加州林业与消防局(Cal Fire)在fire.ca.gov/incidents网站上维护了一张火灾地图,地图展示了该州近期的大型火灾情况。 我找到了网站的底层数据: curl https://www.fire.ca.gov/umbraco/Api/IncidentApi/GetIncidents 然后我搭建了一个简单的抓取工具,每20分钟抓取一份网站数据并提交至Git。到现在,这个工具已经运行了14个月,收集了1559个提交版本。 Git scraping最让我兴奋的是,它可以创建真正独一无二的数据集。很多组织都不会对数据变更内容和位置做详细归档,所以通过抓取他们的网站数据并保存到Git存储库,你会发现自己比他们更了解他们的数据变更历史。 然而,一个巨大的挑战是,如何最有效地分析这些收集到的数据?面对成千上万个版本、大量的JSON和CSV文档,如果只靠肉眼观察不同之处,想必很难挖掘出数据背后的价值。 git-history git-history就是我提出的新解决方案,它是一个命令行工具。它可以读取一个文件的全部历史版本,并生成一个SQLite数据库,记录文件随时间的变化。然后可以用Datasette分析挖掘这些数据。 下面是我用ca-fires-history存储库运行git-history所生成的一个数据库示例。我在存储库目录中运行以下命令创建了一个SQLite数据库:
在这个例子中,我们抓取的是incidents.json这个文档的历史版本。 我们通过UniqueId列来识别随时间变化的记录和新增记录。 新建数据库表的默认名称是item和item_version,我们通过--namespace incident将表名指定为incident和incident_version。 工具中还内嵌了一段Python代码,可以将提交历史中存储的每个版本转换成与工具相兼容的对象列表。 让数据库来帮我们回答一些关于过去14个月美国加州火灾的问题吧。 incident表包含每场火灾的最新记录。通过这张表,我们可以得到一张关于所有火灾的地图: 这里用到了datasette-cluster-map插件,它把表中给出有效经度和纬度值的所有行都标注在了地图上。 真正有趣的是incident_version这张表。这张表记录了每场火灾历次抓取版本间的数据更新情况。 250场火灾有2060个记录版本。如果按照_item进行分面,我们可以看到哪些火灾记录的版本最多。前十名依次是:
版本数越多,大火持续的时间越长。维基百科上甚至有Dixie Fire的词条! 点击Dixie Fire,在弹出页面上可以看到按版本号排列的所有抓取到的“版本”。 git-history在这张表中只写入了与前一版本相比发生变化的值。因此一眼扫过去你就能看到哪些信息随时间变化了: 经常变化的是ConditionStatement列,这一列是文字描述,另外两个有意思的列是AcresBurned和PercentContained。 _commit是commits表的外键,该表记录了工具已提交的版本,所以当你再次运行工具的时候,工具能定位上次提交到哪个版本。 连接commits表即可查看每个版本的创建日期。也可以用incident_version_detail视图执行连接操作。 通过该视图,我们可以筛选_item值为174、AcresBurned值不为空的所有行,借助datasette-vega插件,将_commit_at列(日期类型)和AcresBurned列(数值类型)比对形成一张图表,直观显示Dixie Fire火灾随时间蔓延的过程。 总结一下:我们先用GitHub Actions创建一个定时工作流,每20分钟抓取JSON API端点的最新副本。现在,借助git-history、Datasette和datasette-vega,我们成功用一幅图表展示了过去14个月中加州持续最久的一次森林火灾的蔓延情况。 关于表结构设计 git-history的设计过程中,最难的是为历次版本变更信息的存储设计一种合适的表结构。 我的最终设计如下(为清晰起见作了适当编辑):
如前所述,item_version表记录了不同时间点的网站快照,但为了节省数据库空间和提供简洁的版本浏览界面,这里只记录与前一版本相比发生变化的列。没变化的列都写入null。 然而这个设计有个隐患,即如果某场火灾某一列的值更新为了null,我们该怎么办?我们如何分辨是更新还是没变化? 为解决这个问题,我新增了一个多对多表item_changed,用整数对记录item_version表中具体哪些列更新了内容。用整数对的目的是尽可能少地占用空间。 item_version_detail视图将多对多表中的列以JSON的方式呈现出来,我筛选了部分数据放在下图中,可以看出哪些火灾的哪些列在哪些版本中有更新: 通过下面这个SQL查询,我们能知道加州火灾哪些数据更新最频繁:
查询结果如下:
直升机听起来很刺激!我们来筛选出第一个版本之后直升机数量有过至少一次更新的火灾。可以使用如下嵌套的SQL查询:
查询结果显示,有19场火灾出动直升机扑救,我们标注在下面的地图上: --convert选项的高级用法 过去8个月中,Drew Breunig用Git抓取工具持续从511.org网站抓取数据并保存到dbreunig/511-events-history存储库。该网站记录旧金山湾区的交通事故。我将他的数据加载到了sf-bay-511数据库。 以sf-bay-511这个数据库作为示例有助于我们深入了解git-history与--convert选项叠加的用法。 git-history要求抓取的数据呈如下特定格式:一个由JSON对象组成的JSON列表,每个对象有一列可以作为唯一标识列用于追踪数据随时间的变化。 理想的JSON文件是这样的:
但抓取的数据通常不是这种理想格式。 我找到了511.org网站的JSON Feed。这里面有非常复杂的嵌套对象,数据庞杂,其中一些对整体分析没有帮助,比如即使没有数据更新也会随版本变化的updated时间戳,还有包含大量重复数据的深度嵌套对象“extension”。 我编写了一段Python代码,把每一个网站快照转换为一个较简单的结构,再把这段代码传递到脚本的--convert选项:
传递到--convert的这个单引号字符串被编译成一个Python函数,并在每个Git版本上依次运行。代码在Events嵌套列表中循环运行,修改每条记录,然后使用yield按照可迭代的序列输出。 有些历史记录显示服务器500错误,代码也能够识别并跳过这些记录。 使用git-history的时候,我发现自己大部分时间都用在了迭代转换脚本上。把Python代码字符串传递到git-history之类的工具是个挺有趣的模式,今年早些时候我还尝试在sqlite-utils工具中叠加转换。 动手试一试 如果你想尝试一下git-history工具,扩展文档README里提供了更多选项,示例用到的脚本都保存在了demos文件夹中。 GitHub上git-scraping话题下面,很多人创建了存储库,目前已有200多个。那里有丰富的抓取数据等着你去探索! |
|
|
上一篇文章 下一篇文章 查看所有文章 |
|
开发:
C++知识库
Java知识库
JavaScript
Python
PHP知识库
人工智能
区块链
大数据
移动开发
嵌入式
开发工具
数据结构与算法
开发测试
游戏开发
网络协议
系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程 数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁 |
360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 | -2024/11/15 14:56:49- |
|
网站联系: qq:121756557 email:121756557@qq.com IT数码 |