从网站上显示的图表获取数据
我被要求画一个像这样的图
使用Latex(更准确地说,是tikz和/或pgf)。如果我有数据,这根本不成问题,但我没有。 我只有一个网站,可以显示图表,但我不知道怎么从那里获取数据。
今天我花了一整天试图获取这些数据,包括给谷歌写信和使用一种可以追踪线条并推测图表点的软件,比如Datathief和DigitizeIt,但都没有成功。我觉得后者没有用是因为图表中的线条太细,而且有多种蓝色的阴影。当然,我尝试用Paint和Gimp改善图片质量,但还是没能成功。
我还尝试使用eps2pgf,这是一个可以将eps图形转换为pgf代码的Java脚本,但即使这样也无法处理我用Image Capture(mac)和Print Screen(Windows)保存的图表。老实说,这也是我最后的选择,因为这是一种“粗暴的方法”,生成的代码很丑,根本无法改进。
经过这一切,我决定开始学习Python,因为我的主管,也就是要求我用tikz画这个图的人,说有Python代码可以从这样的网页获取数据。现在我甚至不确定Python是否能完成这个工作(不过我很高兴有借口去学它),当然,学习一门新语言并做这样的事情需要时间,所以我想知道是否真的有办法从那个网站获取数据,最好是用Python,如果不行,也希望有其他方法。
1 个回答
如果谷歌能提供一个API来获取这些数据,那就太好了!不过,你仍然可以从网站上抓取一些数据。下面是具体的操作步骤……
安装Firebug
我个人比较喜欢用Firebug这个工具在Firefox上,但Chrome的开发者工具也可以用。
调查一下
首先,我们访问一下这个网址,然后用Firebug看看发生了什么。按F12键打开Firebug,或者去工具菜单选择Firebug,然后打开它。先点击“网络”标签,然后刷新页面。这样可以看到所有的请求,这能帮助你了解网站是怎么运作的。通常,Flash插件会从外部加载数据,而不是把数据嵌入到插件里。如果你查看请求,会看到一个标记为POST service
的请求。把鼠标悬停在上面,Firebug会显示完整的URL,你会看到页面向http://www.google.com/transparencyreport/traffic/service
发出了请求。你可以点击这个请求,查看发送的头信息、POST数据、响应和用于请求的cookies。
查看响应时,你会发现看起来像是格式不正确的JSON。从我能看出的,这里面似乎包含了标准化的流量数据点。其实你可以直接从Firebug中复制响应内容,但因为这是一个关于Python的问题,我们可以稍微努力一下。
把数据导入Python
为了成功发送POST请求,我们需要做几乎所有浏览器所做的事情。我们可以稍微“作弊”一下,直接从Firebug中复制请求头和POST数据,以伪装成一个真实的请求。
请求头和POST数据
使用三重引号可以把多行字符串粘贴到命令行中。复制请求头并粘贴进去。

>>> headers = """ <paste headers> """
接下来,把它转换成一个字典格式,以便使用httplib2。我会用列表推导式(这会根据换行符分割字符串,然后在第一个冒号处分割这一行,并去掉末尾的空格,这样就得到了一个包含两个元素列表的列表,dict
可以把它转换成字典),但你可以用任何你喜欢的方式来做。你也可以手动创建字典,我只是觉得这样更快。
>>> headers = dict([[s.strip() for s in line.split(':', 1)]
for line in headers.strip().split('\n')])
然后复制POST数据。

>>> body = """ <paste post data> """
发送请求
我将使用httplib2,但还有其他一些HTTP客户端和一些很好的网页抓取工具,比如mechanize和scrapy。我们将使用API的URL、复制的请求头和从Firebug复制的POST数据来发送POST请求。请求会返回一个包含响应头和内容的元组。
>>> import httplib2
>>> h = httplib2.Http()
>>> url = 'http://www.google.com/transparencyreport/traffic/service'
>>> resp, content = h.request(url, 'POST', body=body, headers=headers)
处理数据
原始格式看起来很奇怪,只有顶部的部分似乎包含数据点,所以我会把其他部分丢掉。
>>> cleaned = content.split("'")[0][4:-1] + ']'
现在它是有效的JSON格式,我们可以把它转换成Python的原生数据类型。
>>> import json
>>> data = json.loads(cleaned)
我感兴趣的所有数据点都是浮点数,所以我会根据这个进行筛选。
>>> data = [x for x in data if type(x) == float]
处理/保存数据
现在我们有了数据,可以检查一下,进行额外的处理等等……
>>> data[:5]
<<<
[44.73874282836914,
45.4061279296875,
47.5350456237793,
44.56114196777344,
46.08817672729492]
……或者直接保存它。
>>> with open('data.json', 'w') as f:
...: f.write(json.dumps(data))
我们还可以使用pyplot来自matplotlib(或者其他一些绘图/图表库)来绘制这些数据。
>>> import matplotlib.pyplot as plt
>>> plt.plot(data)
总结
如果你只对一些特定的内容感兴趣,可以调整图表来显示你想要的内容,然后使用正确请求的请求头和POST数据,去访问http://www.google.com/transparencyreport/traffic/service
。你可能想更仔细地检查一下实际的响应,我只是丢掉了那些我看不懂的部分。希望他们能为这些数据提供一个公开的API。