既然“数据”之于数据新闻、可视化如此重要,那么该如何搜集数据呢?本书将搜集数据的一般途径归纳为三种:①搜索与查询,包括使用搜索引擎查询数据和查询开放数据集、数据分享站点;②采访、调查与众包,包括通过采访他人或向他人询问索取数据,通过问卷调查获取一手数据,以及通过众包的形式搜集数据;③程序抓取,即通过计算机程序(通常被称为“网络爬虫”或“网络蜘蛛”)抓取网页数据。本书重点讨论通过计算机程序抓取网页数据的方法。
在无法预判从哪里可以获得数据时,最直接的反应是使用搜索引擎来检索。搜索引擎的基本用法很简单,在搜索框中输入关键词后,单击【搜索】按钮或按Enter键(回车键),就可以获得与关键词有关的资源链接列表。接下来,查询者需要对资源进行筛选,寻找匹配需求的数据或可能存在此类数据的站点、平台。然而,这种简单的方式有时并不一定能快速定位所需的资源,特别是如果关键词、检索条件设置得有问题,则很可能会为后续的筛选增加很多工作量。因此,使用搜索引擎时,可以结合一些搜索技巧,如通过“and”“or”“not”等逻辑运算符或“+”“−”符号来细化检索词和检索条件,通过设置检索限定条件来细化搜索需求或限制检索范围等 [46] 。关于这些搜索技巧,网络上有许多教程资源,读者可自行查阅,这里不再赘述。不过,值得注意的是,有些技巧只在某些搜索引擎中适用,在另一些搜索引擎中则不适用。所以,最好使用多个搜索引擎来查询数据。
“开放数据”是指政府或其他组织机构将一些数据开放给社会公众。这些数据可以被自由获取和再次发布,而不会受到著作权、专利权及其他管理机制的限制 [1 、2] 。近年来,世界各国都在积极致力于推进本国的“开放数据”进程。美国和英国等是开放数据运动的领先者。我国近几年来在开放数据方面也取得了不少成绩。2012年6月,上海启动政府数据资源向社会开放试点工作,上海政府数据服务网成为全国首个政府数据服务网站 [47] 。同年10月,北京市政务数据资源网开始试运行 [48] 。2013年,国务院发布了《关于促进信息消费扩大内需的若干意见》,要求促进公共信息资源共享和开发利用 [49] 。2014年8月,在北京国家会议中心召开的“开放数据中心2014峰会”上,开放数据中心委员会(Open Data Center Committee,ODCC)正式宣布成立 [50] 。2019年的《中国地方政府数据开放平台报告》显示,截至2019年上半年,有多达82个省级、副省级和地级政府上线了数据开放平台 [51] 。除了“开放数据”进程的推进外,在大数据时代,国内商业化的数据分享站点也日益丰富,其中包括许多数据交易平台,如数据堂(网址:www.datatang.com)、京东万象(网址:wx.jdcloud.com)、聚合数据(网址:www.juhe.cn)等。
采访和调查都是比较传统的数据搜集途径,而众包是在社交网络、大数据技术发展成熟的前提下发展起来的搜集方法。不过,它们的共同特点是,都需要借助第三方的力量。
当难以通过查询开放数据集、数据分享站点的方式来搜集某些数据时,还可以通过采访等方式来搜集这些数据。正如《数据新闻概论:操作理念与案例解析》一书中说到的,“像做调查性报道一样去找到有关消息人士,并通过对这些人的采访而追根溯源、层层深入,逐步收集报道需要的数据。” [52] 大多数新闻从业者对这种方法都比较熟悉,这里不做过多介绍。需要了解这种数据搜集途径的读者,可查阅《数据新闻概论:操作理念与案例解析》 [52] 一书。
问卷调查作为一种经典的社会研究方法,在传统新闻报道的实践过程中就有运用。鉴于多数新闻从业者对此类方法都有较丰富的经验,本书也不再赘述。
“众包”(Crowdsourcing)是美国《连线》(Wired)杂志特约编辑杰夫·豪(Jeff Howe)提出的一个概念 [53 、54] 。2006年6月,杰夫·豪在自己的博客上较正式地给出了“众包”的定义 [54] 。关于这一概念,他倾向于两种解释 [54] :一种解释认为“众包是一种将原本由指定代理人(通常是一个雇员)承担的工作通过公开招募外包给非特定人员(一般是一大群人)的行为”;另一种解释认为“众包是软件以外的领域对开源(Open Source)原则的应用”。目前,众包模式已经被广泛应用于各行业,出现了设计众包、数据众包等类型的众包平台。数据众包按照具体的服务内容可以分为通过众包搜集数据、通过众包处理分析数据等类型,有的数据众包平台专门提供一种服务,也有许多平台同时提供多种服务。国内的数据众包平台有百度数据众包(网址:zhongbao.baidu.com)、数据堂“数加加众包”平台(网址:crowd.shujiajia.com)等。在数据新闻实践中,媒体也并不仅仅是将众包模式用在数据搜集上,例如,英国《卫报》在调查国会议员开销的项目中,面对45万个文件,就采用众包的方式,向读者开放项目,让其参与进来,帮忙整理数据 [11] 。
该搜集方法是指借助计算机程序自动搜集和抓取所需的网页数据,而为此开发的计算机程序通常被称为“网络爬虫”或“网络蜘蛛”(Web Scraper/Web Spider/Web Crawler)。由于不同的数据新闻主题一般都有不同的数据需求,因此计算机程序通常也不是一成不变的,而要根据数据需求去定制或进行参数的配置。随着大数据技术和互联网的发展,借助计算机程序来自动搜集、抓取数据的情况越来越多见,也就意味着“程序抓取”这种方法对于新闻从业者来说越来越重要。本节向读者介绍根据自己的数据需求通过程序自动搜集、抓取数据的方法。同时,从这一节开始,会接触到一些编程的内容。如前所述,我们介绍编程方法的主要目的是让读者熟悉编程的语境和思路,为理解后面章节介绍的可视化工具及其实践中涉及的编程做准备。虽有一定技术深度,但考虑到本书主要面向新闻从业者,所以会尽可能地使用不那么专业的简单语言来解释编程过程。
总的来说,通过程序抓取网页数据通常有三种方式:一是通过数据来源站点提供的应用程序接口(Application Programming Interface,API)来搜集和获取数据;二是使用现成的网络爬虫工具(如八爪鱼采集器 、GooSeeker集搜客网络爬虫软件 、后羿采集器 等)来搜集和获取数据;三是直接用Python等编程语言进行网络爬虫程序的开发。接下来,对这三种方式分别进行介绍,重点介绍第一种方式,将通过一个实例来说明其基本原理和实现过程。
前面提到,API是“应用程序接口”的英文缩写。所谓接口,就是设置在复杂系统之上,为屏蔽其操作细节以便简化某些任务 [55] 而设置的“窗口”。生活中有许多接口,如电源接口。你不需要知道内部的线路如何部署,当需要用电时,只要将电源插头插到电源接口上就可以了。应用程序接口也是这样一种接口。但设置这种接口的初衷不仅仅是为了屏蔽其复杂的内部机制,还出于对数据来源站点上数据的保护。但不管怎样,站点设置了API以后,就能让第三方开发者对站点上的数据加以利用,从而也为站点提供许多创新的功能。早在2008年,MySpace就已经开放了20多个API,开发者也因此能够开发像音乐播放器、电子贺卡等一类应用程序嵌入MySpace网站 [56] 。Facebook和Google也提供了大量的网络应用程序接口(Web API),集结大众的力量,创新许多有用的应用程序 [56] 。
随着社交媒体的发展,Twitter、Facebook和新浪微博等一类社交媒体积蓄了越来越多有价值的信息和数据,成为新闻数据的一个重要来源。如前所述,通过对它们提供的API进行操作可以获得数据,并在此基础上开发出许多第三方应用程序。下面就以新浪微博API为例,对使用API搜集和获取数据的原理和过程进行简单介绍。
新浪微博提供的是REST(Representational State Transfer,表述性状态转移)API接口,通过标准的HTTP请求和响应来访问资源,得到JSON格式的返回数据 [57] 。对于JSON格式,将在2.3.3节专门介绍,这里只需知道它是返回数据的一种格式即可。
一般情况下,API可以通过在线调试或基于程序开发进行操作。前者需要平台为用户提供这类功能支持,否则就只能基于程序开发进行操作。在新浪微博开放平台(网址:open.weibo.com)上申请成为开发者以后,首先要在该平台上创建应用,获得对应的App Key和App Secret。然后,下载对应语言的软件开发工具包(Software Development Kit,SDK)。新浪微博开放平台提供了多种版本的SDK,开发者可根据自己准备使用的开发语言选择相应的SDK进行下载。使用不同语言对应的SDK,在后续开发过程的操作细节上可能会有所不同,这里以Java语言为例,对后续操作过程进行说明。若用Java语言进行后续开发,就需要下载与Java语言对应的SDK。接着,基于所下载的Java SDK,使用Java开发平台(也称为“集成开发环境”,如MyEclipse 、Eclipse 等)创建Java工程,并打开文档config.properties,根据App Key和App Secret等信息对该文档做若干修改并保存,以便后续完成打开新浪微博认证页、经用户认证并获得其授权的过程(所涉及的访问授权机制后文再做详细说明)。最后,根据自己的数据需求选择Java SDK中与所需调用的微博API对应的Java文件,在其基础上进行开发。上述使用Java基于程序开发来操作新浪微博API的过程可用图2-1来描述。
图2-1 使用Java基于程序开发来操作新浪微博API的过程
上文提到访问授权机制,该技术所采用的访问授权机制是需要重点理解的内容。具体来说,在提供API的站点中,开发者获取数据之前,通常都要先经过该站点用户的授权,所采用的授权方式被称为“OAuth授权”。不同于传统的客户端—服务器认证模型中需要资源所有者向第三方应用提供自己的凭证(通常是用户名和密码),才能访问其存储在资源服务器上的资源,“OAuth授权”的优势在于资源所有者可以在不告诉第三方应用用户名和密码的前提下进行授权,使第三方应用获得另一种凭证(称为“访问令牌”,Access Token),并据此访问和获取资源所有者在资源服务器上的数据。整个认证过程涉及资源所有者(Resource Owner)、资源服务器(Resource Server)、认证服务器(Authorization Server)和客户端(Client,通常是第三方应用)。资源服务器和认证服务器可以是同一个服务器,也可以不同 [58] 。具体到新浪微博上,资源服务器和认证服务器都来自新浪微博,资源所有者即新浪微博上的用户,第三方应用即开发者开发的应用程序,在数据新闻实践中则通常是媒体为了获得数据而开发的程序(网络爬虫),以及建立在所获数据基础上的新闻应用程序。用户在不告知第三方应用自己的新浪微博用户名和密码的前提下对其进行授权;经过授权,新浪微博的认证服务器就会向第三方应用发放Access Token;最后,第三方应用通过向新浪微博出示Access Token来访问用户的微博数据,并据此向用户提供某项服务。
接下来,通过一个实例实践基于程序开发来操作新浪微博API,从而搜集和获取数据的过程。本例的主要目的是让读者加深对这一操作过程及对“OAuth授权”的理解。
目标:获得新浪微博上某个授权用户最新发布的前三条微博的创建时间和内容。由于开发者的第三方应用只有经过新浪微博的官方审核并上线后,才能获得除开发者及个别测试用户以外的其他授权用户的微博数据。本例只是一个如何操作新浪微博API的小例子,不进行应用上线,故在介绍过程中将会以开发者自己的微博账号作为授权用户账号,所使用的开发语言为Java语言。
过程:结合前文所述的操作过程及“OAuth授权”原理,本例需要说明三个关键环节:第一,申请成为开发者;第二,创建应用;第三,基于数据需求的开发,包括下载SDK,获取Access Token,开发、测试和使用。关于“如何申请成为开发者”和“如何创建应用”,新浪微博开放平台的新手指南页中已有介绍 [59] ,为保持实例过程介绍的完整性,下面还是对其进行描述,操作细节会结合实例进行若干调整。下面就是这三个关键环节的具体实现过程 。
1)申请成为开发者
申请成为开发者的具体步骤如下 。
第1步:登录新浪微博开放平台,做法是在浏览器中打开新浪微博开放平台的官网(网址:open.weibo.com),单击【登录】按钮,在弹出的对话框中根据操作提示完成登录。
第2步:完善开发者信息并进行验证。
第2.1步:单击【我的应用】菜单,跳转到【开发者信息】页面。
第2.2步:在【开发者信息】页面上单击【现在就去完善】按钮,跳转到【基本信息】页面。在该页面填写开发者资料,经过若干验证流程,就可成为新浪微博认证的开发者。
2)创建应用
创建应用的步骤可在“申请成为开发者”以后马上进行或选择之后的任何时间进行。具体步骤如下。
第1步:选择目标应用类型并创建应用。新浪微博开放平台中有【微连接】和【微服务】两个菜单,提供了“微连接”和“微服务”两种目标应用类型。“微连接”下有“移动应用”“网站接入”“无线游戏”“其他”四种子类型。“微服务”下有“轻应用”“微博支付”等子类型。本例选择【微连接】→【其他】菜单,跳转到【创建新应用】页面,在页面中将【应用名称】设置为“用户微博的相关统计”,将【应用分类】设置为“网页应用”,并勾选【我已阅读并接受《微博开发者协议》】,再单击【创建】按钮,即可创建应用并跳转到【应用信息】下的【基本信息】页面。
第2步:在【基本信息】页面中设置应用的基本信息。首先,该页面的【应用基本信息】选项区域会显示该应用的App Key和App Secret,如图2-2所示。这两个信息需记录下来,在后续开发环节中会用到。然后,对【应用基本信息】选项区域的各选项进行设置,尤其是将标识为“必填”的内容补充完整,再单击【保存以上信息】按钮进行保存。
图2-2 新浪微博开放平台【应用信息】下【基本信息】页面的【应用基本信息】选项区域
第3步:添加授权回调页,以便在后面的操作中获取Access Token。做法是在刚刚创建的应用“用户微博的相关统计”的【基本信息】页面选择【应用信息】→【高级信息】菜单 ,跳转到【高级信息】页面,单击【OAuth2.0授权设置】选项区域的【编辑】按钮,然后在【授权回调页】和【取消授权回调页】文本框中分别输入一个授权回调页的URL地址(以下简称“地址”)和一个取消授权回调页地址,并单击【提交】按钮完成设置。一般来说,开发者应填写自己网站的地址。
至此,创建应用的环节完成,即可进入下面的开发环节。
3)基于数据需求的开发
这一环节包含三部分:下载SDK;获取Access Token;开发、测试和使用。
(1)下载SDK
下载SDK的具体步骤如下。
第1步:选择新浪微博开放平台页面的【文档】菜单,跳转到【开发文档】页面的【首页】。
第2步:在该页面中选择【资源下载】→【SDK】菜单,在跳转到的页面中,根据自己后续开发要使用的语言选择对应的SDK版本进行下载。本例需要选择的是与Java语言对应的版本“Java SDK”,即单击【Java SDK】下的【下载地址】,从跳转到的Github页面 中下载压缩包“weibo4j-oauth2- beta3.1.1.zip”。
第3步:将下载的压缩包解压缩。
(2)获取Access Token
打开Java开发平台Eclipse后,通过如下四步操作获取Access Token。Eclipse是一个在本地运行的软件,需要开发者在自己的计算机上安装,也可以选择安装其他的Java开发平台。不过,要注意的是,要开发Java程序,必须先下载和安装Java开发工具包(Java Development ToolKit,JDK),并配置好相应的环境变量后,才能使用Eclipse等Java开发平台。读者可通过网络自行搜索安装JDK和配置环境变量等的相关操作方法,本书不详细介绍。
第1步:新建工程,分为以下三个子步骤。
第1.1步:选择Eclipse应用程序窗口的【File】→【New】→【Java Project】命令,弹出【New Java Project】对话框。
第1.2步:在对话框的【Project name】文本框中为新建的工程设置一个工程名称,本例设置为“beijingtour”,并将【Location】设置为上一步下载的Java SDK(即文件夹“weibo4j-oauth2-beta3.1.1”)里面的文件夹“weibo4j-oauth2”中所有文件所在的位置。方法是,取消勾选【Use default location】,并单击【Location】选项右侧的【Browse】按钮,在弹出的【浏览文件夹】对话框中选择文件夹“weibo4j-oauth2”,再单击【确定】按钮即可。
第1.3步:单击【New Java Project】对话框中的【Finish】按钮,完成新建工程操作,此时下载的Java SDK已经加载到新建的工程中。
第2步:填写相关配置。这时,在第二个环节中记录的App Key和App Secret及填写的授权回调页地址就要派上用场了。填写相关配置的方法如下。
第2.1步:在Eclipse应用程序窗口的【Navigator】面板中选择并打开文件夹“beijingtour”→“bin”→“weibo4j”下的文件config.properties。
第2.2步:填写该文件中client_ID、client_SERCRET和redirect_URI三项,即按照表2-1所示的对应关系将之前记录的相应参数值填入该文件上述三项的“=”之后。
表2-1 填写文件config.properties中的相关配置信息
第2.3步:在Eclipse应用程序窗口选择【File】→【Save】命令,保存修改。
第3步:从授权回调页获取code参数。操作方法如下。
第3.1步:在Eclipse应用程序窗口的【Navigator】面板中选择并打开文件夹“beijingtour”→“examples”→“weibo4j”→“examples”→“oauth2”中的Java程序文件OAuth4Code.java。
第3.2步:在Eclipse应用程序窗口选择【Run】→【Run】命令,运行OAuth4Code.java文件。程序运行后,自动打开浏览器窗口并显示一个新浪微博的页面,页面中会询问用户是否对该应用进行授权。在用户同意授权(输入新浪微博账号、密码进行登录)后,页面跳转到开发者所设置的授权回调页。这时,浏览器地址栏内的网址后增加了一段以“?code=”开头的代码,复制等号后面的参数(为叙述方便,本例将其称为“code参数”) 。
第4步:获得Access Token。分为以下两个子步骤。
第4.1步:回到Eclipse应用程序窗口,在【Console】面板中显示的“Hit enter when it’s done.[Enter]:”提示语后(即图2-3中虚线框框出的区域),输入上一步复制的code参数。
第4.2步:按Enter键(回车键)。这时,程序继续运行。运行后,就能从【Console】面板显示的运行结果中获得Access Token,即图2-4中【Console】面板上所显示的最后一行的“accessToken=”后直到第一个逗号之前的参数值(图中矩形框框出的位置)。将这个参数记下来,后续开发过程会用到,因为前面介绍“OAuth授权”时就提到,有了Access Token以后,开发者所开发的第三方应用才能访问和获取授权用户的微博数据。此外,为了降低理解难度,上述过程简单采用了人工手动操作的方式,而在实际开发相关应用时,上述过程都应考虑由应用程序自动完成。
图2-3 在Eclipse的【Console】面板中“Hit enter when it’s done.[Enter]:”提示语后输入复制的code参数
图2-4 从Eclipse的【Console】面板显示的运行结果中获得Access Token
(3)开发、测试和使用
虽然从新浪微博开放平台下载的SDK为开发者提供了通过调用新浪微博API来获取某些微博数据的程序代码,但不一定能满足开发者的全部需求,这时就需要在现有程序的基础上,根据数据需求来补充或修改必要的代码,以完成开发过程。这正是这种搜集数据的方式有难度的地方,但也是其能满足开发者对数据的个性化定制需求的一种体现。那么,开发者如何面向自己的数据需求来完成开发、测试和使用呢?首先,开发者需要在新浪微博开放平台上查看它提供的API列表,找到符合开发者数据需求或与其需求最接近的API;然后,在本地的开发平台中找到所下载的SDK提供的对应于该API的程序文件,并根据自己的数据需求在该程序文件代码的基础上补充或修改代码,以实现最终目标。因此,概括地说,这一部分的具体实现过程分为三步:第1步,查找API及SDK对应的程序文件;第2步,开发(代码补充或修改);第3步:测试和使用。就本例而言,这三步的实现过程如下。
第1步:查找API及SDK对应的程序文件。分为以下三个子步骤。
第1.1步:在浏览器中打开新浪微博开放平台页面,单击【文档】菜单,跳转到【开发文档】页面的【首页】。
第1.2步:在页面中选择【微博API】→【微博API】菜单,跳转到【开发文档】页面下的【微博API】页面。该页面显示了新浪微博开放平台提供的各种接口(如粉丝服务接口、微博接口、评论接口等),以及各种类下具体的接口名称和功能简介。根据数据需求,在该页面查找可利用的接口。经查找,发现与本例数据需求最相关的接口是“statuses/user_timeline”,其功能是获取某个用户最新发布的微博列表 ,因此选择该接口。
第1.3步:回到Eclipse应用程序窗口,在【Navigator】面板中选择并打开文件夹“beijingtour”→“examples”→“weibo4j”→“examples”→“timeline”下的Java程序文件GetUserTimeline.java,这是与前一步选择的API“statuses/user_timeline”对应的程序文件,后续要在该文件的代码基础上进行开发。
第2步:开发(代码补充或修改)。就本例而言,就是在前一步打开的GetUserTimeline.java文件的代码基础上进行开发,开发过程在Eclipse软件中进行。在补充和修改代码前,先观察一下未做任何编辑之前的GetUserTimeline.java文件,代码如下。
为便于解释,加入行号来标识每行代码,实际编码中应去掉行号。出于同样的目的,在后面的例子中,代码较长的都会加入行号,实际编码时都应忽略,对此后文不再赘述。在上述代码中,第1行是Java的包机制,包是将一些功能相关的类放在一起的一种组织机制。简单来说,第1行代码意味着该源文件中定义的所有类都属于包weibo4j.examples.timeline。类及后文出现的变量、对象、方法等也都是Java语言中常见的概念,对此,本书不展开详细介绍,读者可自行查阅Java的相关学习资料。接下来,第3~6行则用import关键字导入需要使用的其他Java包。第8行到最后一行定义了一个名为“GetUserTimeline”的类,这个类是实现本例目标的关键。
下面在原代码基础上进行代码的补充和修改。在此过程中,应尽量寻找和调用新浪微博Java SDK中提供的类及其方法。整个过程就像“拼积木”,找到实现最终目标所需的“积木”,然后将它们恰当地“组装”起来。开发者要做的主要是添加一些调用某些类的成员方法的代码并设置和传递若干参数,添加所需的衔接性的代码,以及根据数据需求适当地添加、修改其他一些代码(如添加将数据输出的代码等),从而完成“积木”的“组装”。本例进行代码补充和修改的过程如下。
第2.1步:将上述代码第11行,access_token等号后的值修改为本例在“基于数据需求的开发”环节第二部分第4.2步获得的Access Token值,代码修改示例如下。注意,该值要包含在一个英文双引号中。
第2.2步:定义变量i,创建对象createtime和microblogtext,分别用于记录当前正在处理的是第几条微博、它的创建时间及内容,即在原代码第12行的下面增加以下三行代码。
其中,第2行、第3行代码通过new关键字创建了对象。关于这种创建对象的方法,我们不做详细介绍,有兴趣的读者可以自行查阅Java的相关学习资料。Data类是新浪微博Java SDK中已经定义好的,而String类是Java语言中已经定义的字符串类型。至于为何将代码添加到第12行的后面,因为通过观察可以发现第13行以后的代码中有跟获取微博列表有关的代码,而在开始获取微博列表之前,要先将需要使用的变量和创建的对象都准备好。
此外,由于Date类的使用,需要导入另外一个Java包,即在原代码第6行的下面增加如下代码。
第2.3步:获得用户的微博列表。本例通过getStatuses( )方法获取用户的微博列表,并定义一个对象变量microbloglist,将获取的微博列表的引用地址赋值给它(可简单理解为该变量指向了所获取的微博列表),即在原代码第14行的下面添加如下代码。
getStatuses( )方法是新浪微博Java SDK事先定义好的StatusWapper类的成员方法。前面提到,要尽量寻找和调用新浪微博Java SDK中提供的类及其方法,那么,该如何寻找适用的类和方法呢?在Eclipse软件中,当鼠标指针悬停在一个类或方法的名称上时,会显示一个解释对话框,单击对话框中的【Open Declaration】按钮 ,可以打开定义此类或包含了此方法的类所在的Java文件,从而查看关于它们的详细定义。就本例而言,通过查看关于原代码第14行的getUserTimeline( )方法的定义,发现其作用是获取某个用户发表的最新微博列表,返回值是StatusWapper类型。因此,再通过查看定义StatusWapper类的Java程序文件StatusWapper.java,就找到其成员方法getStatuses( )用来获得微博列表,返回值是List<Status>类型,即返回一组Status类型的对象列表。最后,再通过查看定义Status类的Java程序文件Status.java,发现Status类是用来定义一条微博的各项信息和对信息进行若干操作的类。因此,最终确定getStatuses( )方法是为获得用户的微博列表可以使用的方法。可能有读者会问,第14行代码已经有获取某个用户发表的最新微博列表的功能,为何还要使用getStatuses( )方法呢?这是因为通过查看Status类及其方法的定义,会发现其中定义了在后续步骤中要使用的两个方法——getCreateAt( )和getText( ),而StatusWapper类中定义的getStatuses( )方法返回值是一组Status类型的对象列表,换言之,只有通过使用getStatuses( )方法得到了这一返回值,才可能使用Status类中的getCreateAt( )和getText( )方法。不过,这是在完成第2.4步的过程中才最终确定需要使用getStatuses( )方法的。
此外,由于添加的代码中返回值是List<Status>类型,因此,还需要导入两个Java包,即在原代码第6行的下面再增加如下代码。
至于什么时候需要导入额外的Java包及导入什么包,有一个对于初学者来说非常实用的方法,即借助Eclipse软件的错误提示功能。在代码编写的过程中,Eclipse软件对于它无法识别的类型会给出错误提示,在该行代码最左侧用一个带有叉的小灯泡 标识。单击该标识,会显示解决这一问题的建议,只需要从中找到导入包的那一条建议并双击,即可在代码中自动添加导入相关包的代码(若所给建议中有多条关于导入包的建议,就需要开发者自行判断导入哪一条,或一一导入所列的包进行尝试,直到所选择导入的包使得错误提示标识消失为止)。
第2.4步:实现依次读取并在Eclipse软件的控制台(【Console】面板)上显示微博列表中前三条微博的信息(包括创建时间和微博内容)。为此,继续在第2.3步新增代码“List<Status> microbloglist=status.getStatuses();”的下面添加如下代码。
其中,为了遍历microbloglist所指向的微博列表,使用了for循环语句。for循环语句圆括号内的内容可简单理解为每次取出microbloglist所指向的微博列表中的一条微博信息s进行操作。for循环语句的花括号内是循环体,就是对每次取出的微博信息s所进行的具体操作,由一个if-else判断语句构成。if的圆括号内是判断条件,判断变量i是否不超过3,如果是,则执行if后面花括号内的语句,即执行的操作是,首先,用一个System.out.println( )方法将一行文字输出到Eclipse软件的控制台上,提示以下输出的是最新前三条微博中第几条微博的信息(按照发布时间的新旧,最后发布的一条称为“第1条”)。该方法的圆括号中是它传递的参数,即输出到控制台上的具体内容。其中,双引号内的文字是一个字符串,将直接输出到控制台上,而“i”则是输出执行for语句循环体的过程中,变量i当前所代表的值。输出字符串和输出变量的参数之间要用加号相连。System.out.println( )方法传递的参数输出完毕后,会在控制台上自动进行一次换行。其次,用getCreateAt( )方法获得当前正在处理的微博创建的时间,并将其引用地址赋值给createtime;用getText( )方法获得当前正在处理的微博的内容,并将其引用地址赋值给microblogtext。getCreateAt( )和getText( )方法是从新浪微博Java SDK中找到的事先定义好的方法,是Status类的成员方法。寻找合适方法的思路已在第2.3步做了介绍,此处不再赘述。然后,用两个System.out.println( )方法分别将当前正在处理的微博创建的时间和内容输出到控制台上,即输出createtime和microblogtext所指向的值;再用一个System.out.println( )方法在控制台上进行一次换行,以使控制台上所显示的两条不同微博的信息之间有一个空行。最后,用“i++;”将变量i加1,可理解为当前这条微博所需进行的信息处理已完成,将变量i加1,以便做好处理下一条微博信息的准备。当if圆括号内的条件不满足(即变量i的值超过3)时,则执行else下的语句“break;”,表示终止for循环,执行该循环语句后面的语句。
至此,本例进行开发(代码补充和修改)的过程就完成了,在Eclipse应用程序窗口选择【File】→【Save】命令,保存程序文件。本例按以上步骤实现的完整代码可扫描旁边的二维码查看。
第3步:测试和使用。在Eclipse中完成程序开发后,开发者需对程序进行测试。就本例而言,在Eclipse应用程序窗口选择【Run】→【Run】命令,运行上一步开发的程序,结果输出到控制台(【Console】面板)上,如图2-5所示。开发者通过检查输出结果来检验所开发的程序。
图2-5 本例完整代码运行后在Eclipse的控制台(【Console】面板)上显示运行结果
尽可能对程序进行多次测试,以便发现程序逻辑中可能还存在的问题,从而进一步完善代码。例如,本例通过测试发现,如果用户发布的全部微博总数不足3条,则输出到Eclipse软件控制台上的微博信息就会少于3条,这时最好输出一行文字加以提示。为此,可在上一步开发的程序代码的基础上,在for循环语句的下面增加如下代码。
上述代码的作用是判断用户发布的全部微博数是否少于3条,如果是,则输出一行提示文字到控制台上,说明用户发布的全部微博总数是多少条。
测试完成后,开发者需将其在新浪微博开放平台上所创建的应用提交审核。如前所述,应用只有审核通过并上线后,开发者才能正式使用。最后,还要说明的两点是,第一,像新浪微博这类提供API的网站,会出于数据价值和安全性等方面的考虑而限制开发者能够获取的数据量,例如,本例使用的API“statuses/user_timeline”就被限制为最多只能获得最新发布的5条微博。而且,新浪微博所提供的接口中有的还是高级权限接口,需要申请并通过审核后才能使用。第二,新闻从业者用站点提供的API搜集和获取数据,一般都发生在开发新闻应用产品的时候,因为通过该方法搜集数据时是需要获得用户授权的,这种授权通常在用户使用新闻应用产品的过程中完成。新闻应用产品的开发还需要根据具体的应用需求考虑更多工程实现细节,本例对数据的搜集只是其中的一小步。
市场上的网络爬虫工具非常多,如前面提到的八爪鱼采集器、GooSeeker集搜客网络爬虫软件、后羿采集器等。网络爬虫工具的难易程度不一,前面提到的几种工具操作都比较简单。以八爪鱼采集器为例,它提供了简易采集和自定义采集两种模式。简易采集模式通过点击、输入等操作即可完成配置和数据采集,但可扩展性一般,可能无法很好地契合从业者对数据的个性化定制需求。自定义采集模式则需要从业者基于一定的开发逻辑去配置,难度相对大一些,但不需要编程,且可扩展性好,能满足从业者在数据采集上的许多个性化需求。这类工具一般都提供了丰富而翔实的教程文档,从业者通过阅读文档能够很快上手。还有一些网络爬虫工具,它们有较好的扩展性,但也需要从业者进行一定的编程。不过,与通过API获取数据的方式相同的一点是,这些工具都不需要从业者从头开始开发,而可以在其代码、所提供的API等的基础上进行二次开发以满足从业者自己的数据需求。使用网络爬虫工具的一般过程可分为以下三步。
第1步:从网络爬虫工具的官方网站下载并安装该工具,打开工具后新建项目(有的工具还需要注册并登录后才能打开使用)。如果是通过浏览器在线使用的工具,则在其官方网站上登录后再使用。若进行编程,一般还需要从其支持的开发语言中选择一种。
第2步:在浏览器中打开要抓取数据的网页,按F12键打开浏览器自带的开发者工具 ,并借助这一工具分析网页结构,找到要抓取的网页内容所在的HTML元素。最为简单易用的网络爬虫工具也可能不需要进行此步操作,只需要按照工具向导输入要抓取数据的网页地址等信息即可。
第3步:设置参数,进行程序逻辑的设计或写代码,以进行网页数据的抓取。是仅需要设置参数,还是需要设计程序逻辑,甚至写代码(以及代码量),得视具体的网络爬虫工具和数据需求而定。有的可能很简单,有的则可能需要进行比较复杂的开发。
实际上,使用站点提供的API来搜集和获取数据通常也要用到编程语言,而此处所指的是除上述情况以外使用编程语言来开发网络爬虫程序的方式。直接通过编程语言来开发网络爬虫程序,既可以从头开始进行程序设计和实现,也可以使用一些爬虫框架或库来简化开发工作。后者与结合编程来使用现成的网络爬虫工具的情况有一定交叉,因为很多开发者也将爬虫框架视为网络爬虫工具。不过,上文所指的允许进行编程的网络爬虫工具一般支持多种编程语言,而爬虫框架或库一般是专门针对某一编程语言而开发实现的,是专门针对通过这种编程语言开发网络爬虫程序时,用于简化其开发工作的框架和库。直接用编程语言进行网络爬虫程序的开发一般能更好地满足从业者对数据的个性化定制需求,但通常也更复杂,需要开发者有较强的编程能力,至少能熟练运用一门编程语言。常用于开发网络爬虫程序的编程语言有Java、Python和R等。由于该方式有一定的专业深度,而本书以“可视化”为重点,因此,我们只对其适用条件与情况、实现原理,以及从何开始(开发语言的选择)进行阐释。以下所述的大部分内容针对用现成的网络爬虫工具进行数据抓取的方式(尤其是需要用户进行一定的编程时),其中部分内容也适用于使用站点提供的API搜集和获取数据的方式。
第一,适用条件与情况。应明确的是,能通过开发网络爬虫程序来抓取的网页,通常通过人工搜集的手段也能获得数据。而且,往往在开发程序之前,要首先通过人工搜集部分数据来寻找一定的规律,将数据搜集过程梳理为按照规律重复进行某些操作(如复制/粘贴)的过程;然后编写程序,利用自动化操作帮助开发者更快地完成这些重复性的工作。换言之,程序的最大好处是节省了人工搜集数据花费的时间。鉴于此,需要通过开发程序来抓取数据的情况,通常是在面对数据量比较大或更新比较快(需要频繁采集)的数据需求时。否则,采用人工手动采集的方式有可能反而更快一些,因为编写代码也是需要花费不少时间的。此外,由于有的数据来源站点的服务器禁止机器自动访问或对此有严格的访问限制等,因而通过网络爬虫来抓取数据有时也会面临困难或失效。
第二,实现原理。前面提到,对有重复性操作规律的数据搜集任务适合开发网络爬虫程序来自动完成。《鲜活的数据:数据可视化指南》一书将自动搜集数据的过程概括为“找出规律”“循环”“存储数据”三步 [60] ,但实际上“存储数据”一般是在循环过程中同步进行的,因此,我们将实现原理概括为两步:第1步,找规律,一般是找寻网址及与所需采集的数据对应的HTML标签上的一些规律,以便实现大量的重复性操作;第2步,根据规律编写实现重复(循环)执行搜索、存储等操作的程序,即每循环一次都搜集一部分数据并将其进行存储。至于如何编写网络爬虫程序,则与具体数据需求和所使用的编码语言有关,本书不再详细讨论。
第三,从何开始(开发语言的选择)。想要开发网络爬虫程序,前提是熟练掌握一门计算机语言。因此,选择一门开发语言就成为开始的第一步。到底选择哪一门开发语言?实际上,任何一门你熟悉的编程语言都可以。不过,如前所述,有的编程语言(如Python、Java、PHP、C/C++等)提供了若干爬虫框架或库,也可优先考虑。目前,Python语言在开发网络爬虫程序上就很流行。它提供了丰富的爬虫框架,还包含了大量其他功能强大的类库,开发效率高,而且相对于Java、C、C++等计算机语言来说更为简单。此外,R语言也比较适合作为开发网络爬虫程序的入门语言,其语法也较为简单,但只适合小规模的爬虫应用场景。
此外,要补充说明的是,在使用现成的网络爬虫工具或直接用编程语言进行网络爬虫程序开发时,都应熟悉超文本标记语言(Hyper Text Markup Language,HTML)和层叠样式表(Cascading Style Sheets,CSS),以便分析所要抓取的网页是什么结构,所需抓取的数据在网页中的位置(如所关联的HTML标签及其父标签)及它们的样式特征等。至于HTML和CSS,本书在4.1节会对它们的语法做简单介绍,因为在使用某些工具进行可视化实践时也要用到它们。
总之,在实践中到底选择哪一种方法来搜集数据,要综合考虑数据需求、数据来源站点的情况及从业者的技术水平等一系列因素。而且,实践中往往也会综合使用多种不同的方法来搜集数据。