微博抓取的策略及实现
微博获取的方法不同于一般的网页获取,一般网页总是给定一个初始URL,按照一定的规则例如深度优先、广度优先、大站优先、小站优先等方法进行扩展其URL地址进行爬取数据,而微博抓取的实质为在一个给定的微博URL之中,直接抓取页面,并对页面进行解析,例如获取粉丝数、微博数、关注数、发表的帖子等等数据。其抓取的方法本质上可以归结为两种:直接调用官方给定的开放api和间接进行硬性爬取。下面以新浪微博为例,分别介绍这两种方法。
1调用官方给定的api进行获取
直接调用官方api,是按照微博给定的开放api接口进行获取数据。
利用开放的api进行获取微博数据主要要解决以下几方面问题:
1.1 OAUTH认证
使用新浪API首先要解决的是用户认证问题。所谓认证是指用户在不向第三方透露自己的用户名密码的同时,使第三方软件提供方申请获得该用户资源的授权。OAUTH认证为用户资源的授权提供了一个安全的、开放而又简易的标准,被用于新浪微博API的用户验证协议,过程如下:
1)用户向新浪微博OAUTH服务提供商申请应用,获得应用专属App Key和App Secret,分别以HMAC-SHA1算法对用户发出的请求进行数字签名。
2)通过新浪微博开放平台获取RequestToken。未经服务器授权的Request Token中包含了对应密钥、加密算法、发起请求的时间戳、随机字符串与版本号信息。
3)向新浪微博服务器Request Token授权地址发送请求,服务器同意用户的请求,并向其颁发未经用户授权的Oauth Token与对应的Oauth Secret。
4)将上一步得到的Token与Secret发给新浪微博用户授权地址申请Request Token授权。
5)授权后,用户再向新浪微博Access Toke地址发起请求,将上步授权的Request Token换取成Access Token。
6)服务器同意用户请求,并向其颁发通过新浪微博授权的Access Token与对应的密钥。
7)用户将获得的授权的Access Token,以基于http-header的OAUTH形式对请求进行签名,
就可以获得软件对于用户身份资源的使用授权。
1.2新浪微博API
OAUTH授权解决了程序访问API的用户身份认证问题。新浪API可根据请求内容的不同,返回特定的XML或JSON文件。XML作为一种跨平台的强结构性扩展标记语言,因为所有的用信息都被对应的标签所标记,例如:〈id〉1861021910〈/id〉〈name〉Hugo〈/name〉,所以用户可以便捷地找出相应信息并理解其中内容。
JSON是一种轻量级的数据交换格式,文件不具有明显的强结构特征,如: {“id”:”18610219100”,”name”:”Hugo”}。在复杂的JSON对象中,因为它不像XML文件用规范的标签形式标记有效的内容,虽然对于人来说较难整理,但因为JSON文件结构简单,因此通过电脑分析JSON文件具有强大的处理能力。另外JSON文件中因为不再具有用于标记内容属性的说明性标签,所以JSON文件相比XML文件,查询相同内容的返回文件更小,因此更适合作为微博海量数据获取中的文件传输形式。
图1.新浪微博提供了许多种类的api接口
可以自由选择使用相关接口,例如statuses/home_timeline接口获取当前登录用户及其所关注用户的最新微博。https://api.weibo.com/2/statuses/home_timeline.json?source=appkey&user_id=11051&count=100&cursor=1600。这个地址中, http: //api.t.sina.com.cn为新浪API存放服务器地址, statuses/followers为调用请求的具体方法, json?表示返回的是JSON文件形式,问号之后为传递参数。appkey是上述OAUTH认证中用户第一步申请的专属App Key字符串; user_id是所查询用户的数字ID; count=100表示每一次查询最多返回100条记录,在新浪API中这个数值最大为200,缺省值为20; cursor=1600表示这一次查询从第1600条记录开始返回之后的100条数据,根据新浪微博API调用限制,每次查询最大只能返回5 000条数据。为了均衡服务器的负载,通常API服务商对用户的API接口调用频率与查询范围也会根据用户权限的不同有所限制。除了上述一次请求最多只能返回5 000个结果之外,新浪微博API对用户调用接口的查询次数也有限制。普通授权用户每小时接口使用上限1 000次,并且在程序运行中如果短时间内较多地调用API接口,虽然总次数并没有达到每小时的1 000次,但因为在这段时间内调用高度频繁,程序调用结果依然会返回403错误,即用户已达到API使用上限。为了避免用户过高访问新浪API接口,程序必须通过线程控制API访问频率。
图2.使用API的诸多限制部分截图
1.3 新浪微博SDK
新浪SDK是为方便微博API调用而开发的一套软件开发包,其中封装了从授权认证到数据获取与解析的各项功能。SDK是建立在API基础上的集成与开发,基于SDK的工程可以大大降低程序开发的工作量。目前已开发并发布的SDK包括支持JAVA、C++、PHP、PYTHON等12种不同计算机语言的版本。但新浪微博作为一种新生网络应用, SDK开发并不完善,功能性与稳定性均不如API表现出色。另外,因为主要微博服务提供商,如美国的Twitter、中国的新浪等,授权验证与API调用形式是相同的,唯一不同的只是API请求发送地址的区别,因此通过API自行编写的程序,不但可以灵活实现新浪微博开放API接口的所有功能,同时只需要修改API调用地址与参数,就可以实现其他微博平台数据的抓取与处理。
以java为例,sdk的使用。
1、 请先填写相关配置:在Config.properties里 client_ID :appkey 创建应用获取到的appkey client_SERCRET :app_secret创建应用获取到的appsecret redirect_URI :回调地址 OAuth2的回调地址
2.然后调用example包里的OAuth4Code.java
3.运行后会弹出浏览器地址跳转到授权认证页面,然后输入你的微博帐号和密码,会调转到你的回调地址页面,url后面会传递code参数 ,然后在console输入code就能获取到oauth2的accesstoken
4.接下来即可调用example中的相关接口例如user/show接口等
详细使用方法可见:http://code.google.com/p/weibo4j/
2.绕过绕过权限认证进行直接爬取
间接进行硬爬主要是指不调用官方给定的api,绕过权限认证进行解析页面直接获取数据。通过调用API接口可以实现新浪微博数据的便捷抓取与解析,但所有微博服务商都不会无条件将完整API开放给普通用户,因此使用API的方式永远只可以解决微博数据获取中的一部分问题。如在新浪微博中,很多重要查询功能的API是不开放的,同时对于开放的API,一条查询的返回结果数目上限为5000,而往往那些拥有较大信息量的节点才是微博研究最关心的问题。于是在API之外,进行直接爬取需要绕过权限认证进行页面间隙的方式进行获取更多的信息。获取数据要解决以下几个问题:1.模拟登陆问题2.解析页面问题。
2.1模拟登陆问题
只有通过账号用户才能有权限进行访问用户页面,所以首要的问题是解决怎样登陆的问题。新浪微博的模拟登录过程,是向服务器端以一定的格式发送经过Base64编码加密的原始用户名与密码信息,服务器从http-header里包含的授权信息Authorization中提取字符串并解密后得到原有用户名与密码,实现程序对网页的模拟登录过程。
图3.新浪微博模拟登陆过程
具体过程说明:
-
登陆 weibo.com ,这一步的主要目的是获取新浪微博的一个名字为ssologin.js的 js 脚本文件,在weibo.com的页面中连接为
http://js.t.sinajs.cn/t35/miniblog/static/js/sso.js?version=8818b2c42b785af9 。
该脚本文件中包含了整个登陆过程,同时包含了 RSA加密算法,WSSE加密算法和BASE64加密算法。目前该脚本文件的版本为 1.4.11,版本一直在升级,升级过程加密算法可能会做更改。
2.请求servertime,pubkey等数据,通过GET 请求获取一个 JSON格式的数据。URL为
该url请求的过程在上面的js脚本里面也有描述。
js脚本内容为:
url=makeURL(url,{"entry":me.entry,"callback":me.name+".preloginCallBack","su":username,"rsakt":"mod"});
Entry 值为 sso ,
callback 值为 sina ,
su 为用户名 该用户名经过 base64 加密,js脚本内加密方法为
username = sinaSSOEncoder.base64.encode(urlencode(username));
Urlencode方法填充了 username ,是js自带的方法
base64即为 base64加密算法
请求完成后会得到一组JSON格式的数据,如:
Retcode 0 代表执行成功
Pcid 暂时用不到
Servertime和nonce 很重要,这两个数据很重要,是配合对账户密码进行加密的值Pubkey 是加密算法的公钥Rsakv 代表rsa加密算法上述数据中,servertime,nonce,rsakv是需要传回服务器的数据3.提交的表单格式如下:
该表单提交到 URL:http://login.sina.com.cn/sso/login.php?client=ssologin.js(v1.4.11) 此处显示了ssologin.js 的版本,该版本一直在变化
关于 sp 字段的说明:
对于sp的计算新浪给出了两种加密算法,代码如下
RSA:
request["servertime"] = me.servertime;
request["nonce"] = me.nonce;
request["pwencode"] = "rsa2";
equest["rsakv"] = me.rsakv;
var RSAKey = new sinaSSOEncoder.RSAKey();
RSAKey.setPublic(me.rsaPubkey, '10001');
password = RSAKey.encrypt([me.servertime, me.nonce].join("\t") + "\n" + password);
WSSE:
request["servertime"] = me.servertime;
request["nonce"] = me.nonce;
request["pwencode"] = "wsse";
password=sinaSSOEncoder.hex_sha1(""sinaSSOEncoder.hex_sha1(sinaSSOEncoder.hex_sha1(password)) + me.servertime + me.nonce);
RSA中将 servertime,nonce与账户密码连接然后加密
WSSE中经过了三次SHA1 加密,且其中加入了 servertime 和 nonce 的值来干扰。即: 两次SHA1加密后, 将结果加上 servertime 和 nonce 的值, 再SHA1 算一次。
我对于sp的处理是直接将 ssologin.js 脚本中的RSA加密算法部分抽取到一个新建的js脚本中,然后通过java进行调用,不过抽取的js代码需要做一些变化。
4.表单提交之后会得到一个html文件,文件内容如下:
下一步请求的 url ,接着 GET请求字段的url,得到结果如下:
这个地方获得的cookie比较多,有什么UOV,SUP等等很多。我们需要将这些cookies都保存好。
5.上一步得到的网页中包含下面json数据
2.2页面解析技术
因为网页HTML文件是一种不严谨的网页标记语言,这会对网页信息的提取造成一定困难,因此首先需要将标准的HTML语言转化为标准的DOM树结构,然后利用XPath可以定位存放关键信息的DOM节点位置,最后抽取XPath特征节点中的内容。可以使用jdom,dom4j进行解析。但是,微博页面就是微博页面,不同于一般的网页页面,其元素及内容组织在script中,如:
从上图的下面的滚动条可以看出,页面的数据还有很多没有显示。考虑到其格式类似于json格式,可以采用一些json包进行解析如jsoup、jackson、org.json、fast-json等方法进行解析。
3、获取数据的比较
总体来说,两种方式获取的数据有所不同,下面将从速度、获取总量、获取内容项、次数限制等方面进行比较。
比较项 | api | 爬虫 |
---|---|---|
速度 | 快 | 一般 |
获取总量 | 如图 | |
次数限制 | 有 | 无 |
获取内容项 | 如图 |