继续浏览精彩内容
慕课网APP
程序员的梦工厂
打开
继续
感谢您的支持,我会继续努力的
赞赏金额会直接到老师账户
将二维码发送给自己后长按识别
微信支付
支付宝支付

Python系列之——利用Python实现微博监控

千万里不及你
关注TA
已关注
手记 318
粉丝 51
获赞 237

x00 前言:

前几个星期在写一个微博监控系统 可谓是一波三折啊 获取到微博后因为一些字符编码问题 导致心态爆炸开发中断 但是就在昨天发现了另外一个微博的接口

一个手机微博的接口https://m.weibo.cn/ 经过一番测试后认为这个接口满足我的要求 就继续完成未完成的使命吧

0x01 分析:

这个接口直接访问的话会有一个302跳转到一个登陆界面

https://img1.mukewang.com/5d57f5c10001f59409040310.png


也就是说这里需要先模拟登陆一下才可以访问到微博
抓个包分析了一下

https://img4.mukewang.com/5d57f5c5000134f108970568.png


发现只要用户名和密码正确既返回200且json部分的retcode会返回20000000

少了验证码这一大坑 那模拟登陆就相当简单啦


登陆完后访问用户主页 例如:https://m.weibo.cn/u/3023940914
可以在审查元素的Network模块看到 这里用了两个xhr来加载用户信息及微博信息

https://img2.mukewang.com/5d57f5d90001059108850207.png

分别是
https://m.weibo.cn/api/container/getIndex?type=uid&value=3023940914&containerid=1005053023940914
https://m.weibo.cn/api/container/getIndex?type=uid&value=3023940914&containerid=1076033023940914
经过测试这个接口直接加上typevalue参数访问 就相当于第一个接口 不必加上containerid参数
而第二个接口的containerid参数则是通过第一个接口获取的

获取到第二个containerid参数访问第二个接口就可以获取到这个uid发布的微博了

https://img4.mukewang.com/5d57f5f60001755908800540.png


返回的是json格式的数据 用户的微博信息都在cards列表里每条数据的mblog数组里面 包括微博正文、图片、来源与时间

其中card_type标识的是微博类型 例如:文字微博 图片微博 视频微博 转发等 经过测试文字微博和图片微博的card_type标识都一样为9


这里初步只开发监控文字和图片微博的功能<del>其实就是懒</del>

0x02 开发

首先需要模拟登陆 后续的操作都需要基于登陆的格调来进行 也是需要在同个会话进行 可以使用requests.session() 方法来完成
代码片段:


reqHeaders = {    'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; WOW64; rv:54.0) Gecko/20100101 Firefox/54.0',    'Content-Type': 'application/x-www-form-urlencoded',    'Referer': 'https://passport.weibo.cn/signin/login',    'Connection': 'close',    'Accept-Language': 'zh-CN,zh;q=0.8,en-US;q=0.5,en;q=0.3'}
loginApi = 'https://passport.weibo.cn/sso/login'loginPostData = {    'username':userName,    'password':passWord,    'savestate':1,    'r':'',    'ec':'0',    'pagerefer':'',    'entry':'mweibo',    'wentry':'',    'loginfrom':'',    'client_id':'',    'code':'',    'qq':'',    'mainpageflag':1,    'hff':'',    'hfp':''}#get user sessionsession = requests.session()try:
    r = session.post(loginApi,data=loginPostData,headers=reqHeaders)    if r.status_code == 200 and json.loads(r.text)['retcode'] == 20000000:        #successful
        #do someting
    else:        #Logon failure!except Exception as e:    #Logon failure!


登陆完成后就可以拼接用户id访问前面说的第一个接口了
访问完后再拼接containerid参数获取微博信息的json数据
代码片段:


#get user weibo containeriduserInfo 'https://m.weibo.cn/api/container/getIndex?uid=%s&type=uid&value=%s'%(wbUserId,wbUserId)try:
    r = session.get(userInfo,headers=reqHeaders)    for i in r.json()['tabsInfo']['tabs']:        if i['tab_type'] == 'weibo':
            conId = i['containerid']except Exception as e:    #failure!#get user weibo indexweiboInfo = 'https://m.weibo.cn/api/container/getIndex?uid=%s&type=uid&value=%s&containerid=%s'%(wbUserId,wbUserId,conId)try:
    r = session.get(weiboInfo,headers=reqHeaders)
    itemIds = []   #WBQueue
    for i in r.json()['cards']:        if i['card_type'] == 9:
            itemIds.append(i['mblog']['id'])except Exception as e:    #failure!


这里把所有获取到的微博的id存起来 后面继续访问是发现有新的微博id不在这个列表里就证明是新发布的微博
代码片段:


def startMonitor():
      returnDict = {}      try:
          r = session.get(weiboInfo,headers=reqHeaders)          for i in r.json()['cards']:              if i['card_type'] == 9:                  if str(i['mblog']['id']) not in itemIds:
                      itemIds.append(i['mblog']['id'])                      #Got a new weibo
                      #@ return returnDict dict
                      returnDict['created_at'] = i['mblog']['created_at']
                      returnDict['text'] = i['mblog']['text']
                      returnDict['source'] = i['mblog']['source']
                      returnDict['nickName'] = i['mblog']['user']['screen_name']                      #if has photos
                      if i['mblog'].has_key('pics'):
                          returnDict['picUrls'] = []                          for j in i['mblog']['pics']:
                              returnDict['picUrls'].append(j['url'])                      return returnDict      except Exception as e:          #failure!

将这些方法封装成了一个类 完整代码如下

#!/usr/bin/env python# -*- coding: utf-8 -*-# Author    : 奶权# Action    : 微博监控# Desc      : 微博监控主模块import requests,json,sysfrom lxml import etreeclass weiboMonitor():
    """
        @   Class self  :
    """
    def __init__(self, ):
        self.session = requests.session()
        self.reqHeaders = {            'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; WOW64; rv:54.0) Gecko/20100101 Firefox/54.0',            'Content-Type': 'application/x-www-form-urlencoded',            'Referer': 'https://passport.weibo.cn/signin/login',            'Connection': 'close',            'Accept-Language': 'zh-CN,zh;q=0.8,en-US;q=0.5,en;q=0.3'
        }    """
        @   Class self  :
        @   String userName  : The username of weibo.cn
        @   String passWord  : The password of weibo.cn
    """
    def login(self, userName, passWord):
        loginApi = 'https://passport.weibo.cn/sso/login'
        loginPostData = {            'username':userName,            'password':passWord,            'savestate':1,            'r':'',            'ec':'0',            'pagerefer':'',            'entry':'mweibo',            'wentry':'',            'loginfrom':'',            'client_id':'',            'code':'',            'qq':'',            'mainpageflag':1,            'hff':'',            'hfp':''
        }        #get user session
        try:
            r = self.session.post(loginApi,data=loginPostData,headers=self.reqHeaders)            if r.status_code == 200 and json.loads(r.text)['retcode'] == 20000000:
                self.echoMsg('Info','Login successful! UserId:'+json.loads(r.text)['data']['uid'])            else:
                self.echoMsg('Error','Logon failure!')
                sys.exit()        except Exception as e:
            self.echoMsg('Error',e)
            sys.exit()    """
        @   Class self  :
        @   String wbUserId  : The user you want to monitored
    """
    def getWBQueue(self, wbUserId):
        #get user weibo containerid
        userInfo = 'https://m.weibo.cn/api/container/getIndex?uid=%s&type=uid&value=%s'%(wbUserId,wbUserId)        try:
            r = self.session.get(userInfo,headers=self.reqHeaders)            for i in r.json()['tabsInfo']['tabs']:                if i['tab_type'] == 'weibo':
                    conId = i['containerid']        except Exception as e:
            self.echoMsg('Error',e)
            sys.exit()        #get user weibo index
        self.weiboInfo = 'https://m.weibo.cn/api/container/getIndex?uid=%s&type=uid&value=%s&containerid=%s'%(wbUserId,wbUserId,conId)        try:
            r = self.session.get(self.weiboInfo,headers=self.reqHeaders)
            self.itemIds = []   #WBQueue
            for i in r.json()['cards']:                if i['card_type'] == 9:
                    self.itemIds.append(i['mblog']['id'])
            self.echoMsg('Info','Got weibos')
            self.echoMsg('Info','Has %d id(s)'%len(self.itemIds))        except Exception as e:
            self.echoMsg('Error',e)
            sys.exit()    """
        @   Class self  :
    """
    def startMonitor(self, ):
        returnDict = {}        try:
            r = self.session.get(self.weiboInfo,headers=self.reqHeaders)            for i in r.json()['cards']:                if i['card_type'] == 9:                    if str(i['mblog']['id']) not in self.itemIds:
                        self.itemIds.append(i['mblog']['id'])
                        self.echoMsg('Info','Got a new weibo')                        #@ return returnDict dict
                        returnDict['created_at'] = i['mblog']['created_at']
                        returnDict['text'] = i['mblog']['text']
                        returnDict['source'] = i['mblog']['source']
                        returnDict['nickName'] = i['mblog']['user']['screen_name']                        #if has photos
                        if i['mblog'].has_key('pics'):
                            returnDict['picUrls'] = []                            for j in i['mblog']['pics']:
                                returnDict['picUrls'].append(j['url'])                        return returnDict
            self.echoMsg('Info','Has %d id(s)'%len(self.itemIds))        except Exception as e:
            self.echoMsg('Error',e)
            sys.exit()    """
        @   String level   : Info/Error
        @   String msg     : The message you want to show
    """
    def echoMsg(self, level, msg):
        if level == 'Info':            print '[Info] %s'%msg        elif level == 'Error':            print '[Error] %s'%msg


写了个一发现有新微博就发邮件提醒的功能 完整代码见Github地址 https://github.com/naiquann/WBMonitor


0x03 测试

运行代码

https://img1.mukewang.com/5d57f63200015ef408010334.png


填写完相关的登陆信息及要监控的用户的id后

https://img.mukewang.com/5d57f6360001bee908240412.png

这里写了一个心跳包 每三秒访问一次看看有没有新微博发布
测试的时候这样比较方便 要是拿来用的话可以酌情增加间隔时间

当有微博发布的时候

https://img1.mukewang.com/5d57f6590001d7e506390788.png


https://img4.mukewang.com/5d57f65d00016c2708640372.png

大功告成啦 监控小姐姐的微博去喽~


本文作者:奶权#米斯特安全团队 转载请注明出处 http://www.hi-ourlife.com/study/index.html



作者:奶权
链接:https://www.jianshu.com/p/9e7ba0a0a610


打开App,阅读手记
0人推荐
发表评论
随时随地看视频慕课网APP