Python抓取微博评论


写在前面

一直以为微博的东西比较好搞,没想到还是有点坑。新浪把评论的模块保存在一个json字典里,真的是够了。。。前20页可以轻易爬取,21页以后需要获取前一页最后一个评论的ID以及已经展示的评论总数。

包和全局变量

#时间管理带师
import time
#网页请求
import requests
#解析网页
from bs4 import BeautifulSoup as bs

#统计已经展示的评论数量
num = 0
#请自行登录新浪获取cookie
cookie = {}
#请求头
headers = {
    'sec-fetch-dest':'empty',
    'sec-fetch-mode':'cors',
    'sec-fetch-site':'same-origin',
    'referer':'https://weibo.com/2803301701/J6iwvbK2m?filter=hot&root_comment_id=0&type=comment',
    'User-Agent':'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.66 Safari/537.36',
    'x-requested-with':'XMLHttpRequest'
    }

#爬取前20页的参数,目前缺少page参数
params_1 = {
        "ajwvr":6,
        "id":"4515011752798578",
        "from":"singleWeiBo",
        }

#爬取21页以后的参数,目前缺少两个参数
params_2 = {
        "ajwvr":6,
        "id":"4515011752798578",
        "root_comment_max_id_type":"1",
        "root_comment_ext_param":"",
        "filter":"hot",
        "filter_tips_before":"1",
        "from":"singleWeiBo",
        }

#评论接口
url = 'https://weibo.com/aj/v6/comment/big'

几个函数

#获取毫秒级时间戳
def get_time():
    cur_time = int(round(time.time() * 1000))
    return cur_time

#获取包含评论的网页标签
def get_html(params):
    #请求网页
    res = requests.get(url = url,headers = headers,cookies = cookie,params = params)
    #从json中获取数据
    html = res.json()['data']['html']
    #解析文本
    bf = bs(html,'lxml')
    #找到当前页全部评论并以列表形式返回
    WB_texts = bf.find_all('div',class_ = 'list_li S_line1 clearfix')
    return WB_texts

#获取20页之前的评论
def parse_before(page,params):
    #num作为全局变量
    global num
    #补充参数,页数和当前时间
    params['page'] = page
    params['__rnd'] = get_time()
    #获取评论列表
    WB_texts = get_html(params)
    #逐条写入并统计评论数量
    for WB_text in WB_texts:
        #因为class属性为WB_text的div有两个,所以用try-except来筛选
        try:
            f.write(WB_text.find('div',class_ = 'WB_text').text.strip().split(':')[1] + '\n')
            num += 1
        except:
            pass
    print('第{}页抓取完毕'.format(page))

#抓取21页之后的评论
def parse_after(page):
    #num全局变量
    global num
    #补充参数,第21页暂不需要root_comment_max_id和sum_comment_number
    params_2['page'] = page
    params_2['__rnd'] = get_time()
    #获取评论列表
    WB_texts = get_html(params_2)
    #逐条写入并统计评论数量
    for WB_text in WB_texts:
        try:
            f.write(WB_text.find('div',class_ = 'WB_text').text.strip().split(':')[1] + '\n')
            num += 1
        except:
            pass
    #尝试设置root_comment_max_id,可能会因爬取速度过快而出现异常,而且会导致后续一直异常
    try:
        #获取最后一条评论的comment_id
        max_id = int(WB_texts[-1].get('comment_id'))
        #补充参数
        params_2['root_comment_max_id'] = max_id
        print('第{}页抓取完毕'.format(page))
    except:
        #异常原因是当前页根本没有抓到评论
        if len(WB_texts) == 0:
            print('第{}页抓取失败'.format(page))
        pass
    #补充评论数量参数
    params_2['sum_comment_number'] = num

入口函数

if __name__ == '__main__':
    #创建文本文件
    f = open('weibo.txt','wt',encoding = 'utf-8')
    #抓取120页的评论
    for page in range(1,121):
        #前20页以第一种方式获取,后面的以另一种方式
        if page <= 20:
            parse_before(page,params=params_1)
        else:
            parse_after(page)
        #暂停一秒
        time.sleep(1)
    #关闭文件
    f.close()

写在后面

只是粗略写了一下,好多代码可以复用。。懒得优化了。