新浪微博数据的爬取主要有两种方法,当然也可以说博主只知道这两种方法,一种是使用新浪API获取,另一种是结合正则直接爬取页面信息。第一种方法虽然官方封装甚好,给出的数据也比较丰富,但说到底还是限制太多,很多接口只能获取当前登录用户的信息,无法获取好友的信息(你若不信,可以实践一下),所以在爬取数据的过程中干脆放弃了。本文主要介绍第二种方法,即如何结合正则爬取页面信息。
首先是登录微博,博主使用的是urllib2(当然你也可以使用requests),说明一下,有关爬取的相关代码,都写在SinaClient这个类中,login方法如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
| #使用urllib2模拟登录过程 def login(self, username=None, password=None): self.status = False #重新将登录状态设置为False self.logger.info("Start to login...") #根据用户名和密码给默认参数赋值,并初始化post_data self.setAccount(username, password) self.setPostData() self.enableCookie() #登录时请求的url login_url = r'https://login.sina.com.cn/sso/login.php?client=ssologin.js(v1.4.15)' headers = self.headers request = urllib2.Request(login_url, urllib.urlencode(self.post_data), headers) resText = urllib2.urlopen(request).read() try: jsonText = json.loads(resText) if jsonText["retcode"] == "0": self.logger.info("Login success!") self.status = True #将cookie加入到headers中 cookies = ';'.join([cookie.name + "=" + cookie.value for cookie in self.cookiejar]) headers["Cookie"] = cookies else: self.logger.error("Login Failed --> " + jsonText["reason"]) except Exception, e: print e self.logger.info("Login Failed2!") self.headers = headers return self
|
上面用到了几个方法,与先前的模拟新浪微博登录:从原理分析到实现这篇博文的源码类似,可以参考模拟登录新浪的源码https://github.com/csuldw/WSpider/tree/master/SinaLogin。本文的完整源码,待后续整理完整后,也会在该github的WSpider仓库中给出。
登录之后,就可以进行数据爬取了。
为了方便,博主将请求ULR的内容写在了openURL方法里,该方法返回的是该url链接的源码,代码如下:
1 2 3 4 5
| #打开url时携带headers,此header需携带cookies def openURL(self, url, data=None): req = urllib2.Request(url, data=data, headers=self.headers) text = urllib2.urlopen(req).read() return text
|
爬取用户个人信息时,为了得到更多的信息,我们需请求多个地址,博主在爬取时访问了如下四个:
url_app = “http://weibo.cn/%s/info“ %uid
app_page = “http://weibo.cn/%s“ %uid
url_web = “http://weibo.com/%s/info“ %uid
tag_url = “http://weibo.cn/account/privacy/tags/?uid=%s“ %uid
温馨提示:%uid是新浪微博用户ID,若想查看四个页面的信息,将%s替换成用户ID即可。比如将url_app中的uid赋值为1669282904,则网址为http://weibo.cn/1669282904/info。
在上述网址中,从url_app中可以得到昵称、性别、地区、生日、简介、性取向、婚姻状况、首页链接八个字段;从app_page中可以得到用户的关注量、粉丝量、微博量;从url_web中可以获取用户的注册日期;从tag_url中则可以得到用户的标签信息。将这些信息合并到一起,加上uid,共可得14个字段。爬取过程中有的字段取值因用户没填写而造成结果不存在,为了统一字段数量,我们将这些不存在的字段统一置为空串。请求一个页面时,我们可以将页面的源码保存下来,然后使用BeautifulSoup进行解析,再结合正则找到需要的字段值。整个代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48
| from bs4 import BeautifulSoup as BS def getUserInfos(self, uid): url_app = "http://weibo.cn/%s/info" %uid text_app = self.openURL(url_app) soup_app = unicode(BS(text_app, "html.parser")) nickname = re.findall(u'\u6635\u79f0[:|\uff1a](.*?) gender = re.findall(u'\u6027\u522b[:|\uff1a](.*?) address = re.findall(u'\u5730\u533a[:|\uff1a](.*?) birthday = re.findall(u'\u751f\u65e5[:|\uff1a](.*?) desc = re.findall(u'\u7b80\u4ecb[:|\uff1a](.*?) sexorientation = re.findall(u'\u6027\u53d6\u5411[:|\uff1a](.*?) marriage = re.findall(u'\u611f\u60c5\u72b6\u51b5[:|\uff1a](.*?) homepage = re.findall(u'\u4e92\u8054\u7f51[:|\uff1a](.*?) #根据app主页获取数据 app_page = "http://weibo.cn/%s" %uid text_homepage = self.openURL(app_page) soup_home = unicode(BS(text_homepage, "html.parser")) tweets_count = re.findall(u'\u5fae\u535a\[(\d+)\]', soup_home) follows_count = re.findall(u'\u5173\u6ce8\[(\d+)\]', soup_home) fans_count = re.findall(u'\u7c89\u4e1d\[(\d+)\]', soup_home) #根据web用户详情页获取注册日期 url_web = "http://weibo.com/%s/info" %uid text_web = self.openURL(url_web) reg_date = re.findall(r"\d{4}-\d{2}-\d{2}", text_web) #根据标签详情页获取标签 tag_url = "http://weibo.cn/account/privacy/tags/?uid=%s" %uid text_tag = self.openURL(tag_url) soup_tag = BS(text_tag, "html.parser") res = soup_tag.find_all('div', {"class":"c"}) tags = "|".join([elem.text for elem in res[2].find_all("a")]) #将用户信息合并 userinfo = {} userinfo["uid"] = uid userinfo["nickname"] = nickname[0] if nickname else "" userinfo["gender"] = gender[0] if gender else "" userinfo["address"] = address[0] if address else "" userinfo["birthday"] = birthday[0] if birthday else "" userinfo["desc"] = desc[0] if desc else "" userinfo["sex_orientation"] = sexorientation[0] if sexorientation else "" userinfo["marriage"] = marriage[0] if marriage else "" userinfo["homepage"] = homepage[0] if homepage else "" userinfo["tweets_count"] = tweets_count[0] if tweets_count else "0" userinfo["follows_count"] = follows_count[0] if follows_count else "0" userinfo["fans_count"] = fans_count[0] if fans_count else "0" userinfo["reg_date"] = reg_date[0] if reg_date else "" userinfo["tags"] = tags if tags else "" return userinfo
|
上述方法传入的只有一个用户IDuid,最终返回的是一个dict,也就是json串。之所以以JSON串返回是因为这会方便我们后续的数据处理,比如存储至本地或者写入到数据库中。结果字段值如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| uid:用户ID nickname:昵称 address:地址 sex:性别 birthday:生日 desc:简介 marriage:婚姻状况 follows_count:关注数 fans_count:粉丝数 tweets_count:微博数 homepage:首页链接 reg_date:注册时间 tag:标签 sex_orientation:性取向
|
运行代码后,最终的结果将以JSON串返回,传入uid为1669282904的参数,返回结果如下:
目前只包含这14个字段,如果需要更多的信息,可去新浪微博网址中仔细查看相关字段,然后将想要的信息加入到userinfo中即可。在后续博文中,将给出用户粉丝爬取、用户关注爬取、用户微博爬取等相关信息,敬请期待!
End.
作者:刘帝伟 (中国统计网特邀认证作者)
本文为中国统计网原创文章,需要转载请联系中国统计网(小编微信:itongjilove),转载时请注明作者及出处,并保留本文链接。