微博榜单爬虫

本文主要是介绍关于微博榜单的博文以及转发、评论等各种信息爬取。

榜单博文爬取方面,使用的是微博移动端(https://m.weibo.cn)。

因为对于该页面中微博移动版中热门内容、榜单的爬取,不需要使用到cookies

榜单和微博热门的爬取中,具体的内容细节抓取基本差不多,本文以爬取汽车榜单为例进行解析。

微博—汽车榜单博文爬取

首先进入微博移动端(https://m.weibo.cn),打开开发者模式在网络中找到如下包

对应请求网址如下:

https://m.weibo.cn/api/feed/trendtop?containerid=102803_ctg1_5188_-_ctg1_5188

这个请求网址里面代表的是汽车榜单中的相关内容,由于里面内容是随即滚动的,并且带一定的推荐功能,会随登陆账号的不同显示不一样,每次刷新也都会有不同的数据出现。

进去后可以看到,移动端是用滑动的模式,而不是翻页的模式,那么怎么获取下一页的内容呢?

该页面是可以直接用页数&page加一的操作来更新的,但是在后面的用户评论的爬取却不是这个规则,当然这是后话了。

爬取过程详解

首先依据将前面找到的数据接口爬下数据,看看数据格式。

在预览中可以看到包中的数据内容,直接使用requests就可以拿到页面数据,再提取对应的值,再将数据以Json格式存储就可以了。

def crawler(url,page,name):
   num=1
   c=1
   allData=[]
   for i in range(page):
      res=requests.get("{}&page={}".format(url,i))
      data=res.json()['data']['statuses']

包中的具体数据解析

博文等相关数据存储在data->statuses中,里面0~17代表了,该页有18条微博,我们再点进去观察数据表示的含义

ab_switcher: 4
attitudes_count: 89
bid: "LAteeiwt5"
bmiddle_pic: "http://wx3.sinaimg.cn/bmiddle/7fd514fdly1h3szgp0feaj235s2dchdv.jpg"
buttons: [{type: "follow", name: "关注",…}]
can_edit: false
comment_manage_info: {comment_permission_type: -1, approval_comment_type: 0, comment_sort_type: 0}
comments_count: 16
content_auth: 0
created_at: "Sat Jul 02 23:08:44 +0800 2022"
darwin_tags: []
extern_safe: 0
falls_pic_focus_point: []
favorited: false
from_cateid: "5188"
hot_ext: "source_type:5188|recommend_source:87|isPageUp:1|position:2"
hot_page: {fid: "232532_mblog", feed_detail_type: 0}
id: "4786921664414715"
isLongText: false
is_paid: false
mblog_buttons: [{type: "mblog_buttons_forward", name: "转发", pic: "",…},…]
mblog_vip_type: 0
mblogtype: 0
mid: "4786921664414715"
mlevel: 0
negative_tags: [{tag: "1042015:carBrand_c3f70203da24f043de5d59bf97bfc12d", type: "3", name: "大众",…},…]
new_comment_style: 0
number_display_strategy: {apply_scenario_flag: 3, display_text_min_number: 1000000, display_text: "100万+"}
original_pic: "https://wx3.sinaimg.cn/large/7fd514fdly1h3szgp0feaj235s2dchdv.jpg"
pending_approval_count: 0
picStatus: "0:1"
pic_flag: 1
pic_focus_point: [{focus_point: {left: 0.3942028880119324, top: 0.3861003816127777, width: 0.28985506296157837,…},…}]
pic_ids: ["7fd514fdly1h3szgp0feaj235s2dchdv"]
pic_num: 1
pic_rectangle_object: []
pics: [{pid: "7fd514fdly1h3szgp0feaj235s2dchdv",…}]
recommend_source: 87
region_name: "发布于 北京"
region_opt: 1
reposts_count: 0
reprint_cmt_count: 0
reward_scheme: "sinaweibo://reward?bid=1000293251&enter_id=1000293251&enter_type=1&oid=4786921664414715&seller=2144670973&share=18cb5613ebf3d8aadd9975c1036ab1f47&sign=95f1971a1f966218fee334dd90f4fb43"
rid: "1_0_0_6666695739198377824_0_0_0"
show_additional_indication: 0
source: "OPPO Find X5 Pro"
text: "帅就完了,终于低下来了! "
textLength: 24
thumbnail_pic: "https://wx3.sinaimg.cn/thumbnail/7fd514fdly1h3szgp0feaj235s2dchdv.jpg"
title: {text: ""}
user: {id: 2144670973, screen_name: "说车的小宇",…}
visible: {type: 0, list_id: 0}

包含了十分完整且丰富的数据,在本文中所需的数据主要有:

id=singleMess['user']['id'] //用户id
messageid=singleMess['id'] //博文id
mid=singleMess['mid'] //微博在web系统中的id值
username=singleMess['user']['screen_name'] //博主用户名
messagetime=singleMess['created_at'] //发博时间
messagetime=getStandard(messagetime) 
message=singleMess['text'] //博文内容
like=singleMess['attitudes_count'] //点赞数
transmit=singleMess['reposts_count'] //转发数
commentNum=singleMess['comments_count'] //评论数

至此,榜单的博文等信息便可以抓取完毕,接下来是博文中的评论和转发信息。

微博—博文评论抓取

我们在汽车榜单中,随便点进去一个微博

在开发者模式中找到如下请求包

请求网址为:

https://m.weibo.cn/comments/hotflow?id=4786436290642684&mid=4786436290642684&max_id_type=0

通过对请求网址的分析,id和mid对应为上节中爬取的相关数据,因此便可以通过将榜单中的博文的id和mid提取出来,然后修改该请求头的id和mid为提取的数值就可以实现对评论的爬取了。

那么如何进行翻页的操作呢?

我们观察这两个请求网址有什么不一样

https://m.weibo.cn/comments/hotflow?id=4786436290642684&mid=4786436290642684&max_id_type=0//第一页

https://m.weibo.cn/comments/hotflow?id=4786436290642684&mid=4786436290642684&max_id=138173583930408&max_id_type=0 //第二页

发现多了一个&max_id的数据,那么这个数据是如何获取的呢?

我们再次回到第一页的网络包中,在预览中查看包中的数据

{ok: 1, data: {data: [,…], total_number: 74,…}}
data: {data: [,…], total_number: 74,…}
data: [,…]
max: 4
max_id: 138173583930408
max_id_type: 0
status: {comment_manage_info: {comment_permission_type: -1, approval_comment_type: 0, comment_sort_type: 0}}
total_number: 74
ok: 1

里面的max_id的数据是不是就出来了呢?

总结:评论的翻页是通过对该页面的包中max_id 而对应到下一页的

爬取过程详解

通过构造请求头,进行数据网址的请求,然后进行数据的解析就可以了,然后通过本页的max_id 的值来进行翻页操作。

爬取代码如下:

def getSingleMicroblogInfo(id,mid):
   headers = {
        "user-agent":"Mozilla/5.0 (Linux; Android 6.0; Nexus 5 Build/MRA58N) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/100.0.4896.127 Mobile Safari/537.36",
      "cookie":'input your cookie'
      }
   microblog=[]
   url = 'https://m.weibo.cn/comments/hotflow?id={}&mid={}&max_id_type=0'.format(id,mid)
   num=1
   while num<=200:
      res = requests.get(url,headers=headers)
      data = res.json()['data']
      max_id = data['max_id']
      user_info = data['data']
      for single_info in  user_info:
         Retext=single_info['text']
         Retext_id=single_info['id']
         user_id=single_info['user']['id']
         user_name=single_info['user']['screen_name']
         user_messagetime = single_info['created_at']
         user_messagetime=getStandard(user_messagetime)
         comment_flag = 1
         user_comment=[user_messagetime,user_id,user_name,Retext_id,Retext,comment_flag]
         microblog.append(user_comment)
         num+=1
         time.sleep(1)
      if max_id!=0:
         url = 'https://m.weibo.cn/comments/hotflow?id={}&mid={}&max_id={}&max_id_type=0'.format(id, mid, max_id)
      else:
         break
   return microblog

微博—转发信息抓取

点进转发界面

同样如上节,到如下请求包

转发的翻页和博文爬取一样通过&page操作来进行

具体数据的提取操作和评论的爬取相同,传入博文的id,也就不累赘了,直接上代码:

def getTranspondInfo(id):
   headers = {
      "user-agent": "Mozilla/5.0 (Linux; Android 6.0; Nexus 5 Build/MRA58N) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/100.0.4896.127 Mobile Safari/537.36",
      "cookie": 'input your cookie'
   }
   url = 'https://m.weibo.cn/api/statuses/repostTimeline?id={}&page=1'.format(id)
   res = requests.get(url, headers=headers)
   data = res.json()['data']
   page = data['max']
   current_page = 1
   num = 1
   total_number = data['total_number']
   microblog = []
   transpondInfo = data['data']
   while num <= 100 and num<total_number:
      if current_page!=1:
         res = requests.get(url, headers=headers)
         data = res.json()['data']
         total_number = data['total_number']
         transpondInfo = data['data']
      else:
         pass
      for single_info in transpondInfo:
         Retext = single_info['text']
         Retext_id = single_info['id']
         user_id = single_info['user']['id']
         user_name = single_info['user']['screen_name']
         user_messagetime = single_info['created_at']
         user_messagetime = getStandard(user_messagetime)
         transpond_flag=2
         user_comment = [user_messagetime, user_id, user_name, Retext_id, Retext, transpond_flag]
         microblog.append(user_comment)
         num += 1
         time.sleep(1)
      if current_page <= page:
         current_page += 1
         url = 'https://m.weibo.cn/api/statuses/repostTimeline?id= {}&page={}'.format(id, current_page)
      else:
         break
   return microblog

数据清洗

爬取中的数据发现存在大量的网址标签等信息,我们需要进行数据的清洗,去除这些不需要的数据

def cleanData(df):
    发文=[]
    评论=[]
    for item,item2 in zip(df['发文/转发内容'],df['转发/评论内容']):
        scriptRegex = "<script[^>]*?>[\\s\\S]*?<\\/script>";
        styleRegex = "<style[^>]*?>[\\s\\S]*?<\\/style>";
        htmlRegex = "<[^>]+>";
        spaceRegex = "\\s*|\t|\r|\n";
        item=re.sub(scriptRegex,'', str(item))  # 去除网址
        item=re.sub(styleRegex,'', str(item))
        item=re.sub(htmlRegex,'', str(item))
        item=re.sub(spaceRegex,'', str(item))
        item=re.sub('网页链接','', str(item))
        item2 = re.sub(scriptRegex, '', str(item2))
        item2= re.sub(styleRegex, '', str(item2))
        item2 = re.sub(htmlRegex, '', str(item2))
        item2 = re.sub(spaceRegex, '', str(item2))
        item2 = re.sub('网页链接', '', str(item2))
        发文.append(item)
        评论.append(item2)
    df['发文/转发内容']=发文
    df['转发/评论内容']=评论

至此,爬取工作也就结束了。

爬取数据展示

常用的榜单请求地址

urls = [
        'https://m.weibo.cn/api/feed/trendtop?containerid=102803_ctg1_8999_-_ctg1_8999_home', ## 榜单
        'https://m.weibo.cn/api/feed/trendtop?containerid=102803_ctg1_2088_-_ctg1_2088', ## 科技
        'https://m.weibo.cn/api/feed/trendtop?containerid=102803_ctg1_4288_-_ctg1_4288', ## 明星
        'https://m.weibo.cn/api/feed/trendtop?containerid=102803_ctg1_3288_-_ctg1_3288', ## 电影
        'https://m.weibo.cn/api/feed/trendtop?containerid=102803_ctg1_5288_-_ctg1_5288', ## 音乐
        'https://m.weibo.cn/api/feed/trendtop?containerid=102803_ctg1_1988_-_ctg1_1988', ## 情感
        'https://m.weibo.cn/api/feed/trendtop?containerid=102803_ctg1_4488_-_ctg1_4488', ## 时尚
        'https://m.weibo.cn/api/feed/trendtop?containerid=102803_ctg1_1588_-_ctg1_1588', ## 美妆
        'https://m.weibo.cn/api/feed/trendtop?containerid=102803_ctg1_4888_-_ctg1_4888', ## 游戏
        'https://m.weibo.cn/api/feed/trendtop?containerid=102803_ctg1_5188_-_ctg1_5188', ## 数码
        ]