前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >微博爬虫重要更新:根据话题爬虫的结果批量化爬评论

微博爬虫重要更新:根据话题爬虫的结果批量化爬评论

作者头像
月小水长
发布2020-05-26 22:34:59
1.1K0
发布2020-05-26 22:34:59
举报
文章被收录于专栏:月小水长月小水长

要实现这个功能,首先要知道,微博的 mid 和 id 分别是什么?

在公众号以前的一篇文章 微博爬虫综述、错误汇总、Q&A 中,阐述了微博爬虫的不同目标站点之间的差异,并明确了我的微博爬虫的站点策略。

  1. 在 weibo.cn 站点爬取指定话题的微博,爬虫文件名是 WeiboTopicScrapy.py 。
  2. 在 m.weibo.cn 站点指定微博的评论,爬虫文件名是 WeiboSuperCommentScrapy.py。

在这两个站点,就算是同一个用户的同一条微博,其唯一标识也不一样,话题爬虫微博的是诸如 Is0XboARR 这样的形式,看上去是不规则的字符串,通常长度为 9,称之为微博的 mid,而后者是 4467107636950632这样的数字形式Is0XboARR4467107636950632 指向同一条微博)。这样就产生了一个问题,如果我们想要爬取一个话题下的所有微博及其评论,难道要在 weibo.cn 爬完微博后,在 m.weibo.cn 搜每一条微博的文本以定位到该微博在 m.weibo.cn 的 id 吗?这样劳神劳力,完全不符合自动化工作的要求。也许你会问,为什么直接在 weibo.cn 爬取评论呢?问得好:weibo.cn 只能抓取前 100 页 差不多 1000 条评论文本,而 m.weibo.cn 可以抓取几千到几万条评论文本,因噎废食,那可不行。

那怎么办?作为一个程序猿,下意识地想到,mid 和 id 肯定存在某种关联,事实上刚好如此。以Is0XboARR4467107636950632为例,讲诉这种转化逻辑。

  1. Is0XboARR从 后 往 前 按四个字符为一组分组,即Is0XboARR
  2. 将这三组字符(串)转成对应的 62 进制的数字,从前往后拼接起来,就得到对应的数字 id 了。

该部分代码如下:

代码语言:javascript
复制
import execjs
jspython = '''str62keys = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
function int10to62(int10) {
    var s62 = '';
    var r = 0;
    while (int10 != 0) {
            r = int10 % 62;
            s62 = this.str62keys.charAt(r) + s62;
            int10 = Math.floor(int10 / 62);
    }
    return s62;
}
function str62to10(str62) {
    var i10 = 0;
    for (var i = 0; i < str62.length; i++) {
            var n = str62.length - i - 1;
            var s = str62.substr(i, 1);  // str62[i]; 字符串用数组方式获取,IE下不支持为“undefined”
            i10 += parseInt(str62keys.indexOf(s)) * Math.pow(62, n);
    }
    return i10;
}
function id2mid(id) {
    if (typeof (id) != 'string') {
            return false; // id数值较大,必须为字符串!
    }
    var mid = '';
    for (var i = id.length - 7; i > -7; i = i - 7)
    {
            var offset1 = i < 0 ? 0 : i;
            var offset2 = i + 7;
            var num = id.substring(offset1, offset2);
            num = int10to62(num);
            mid = num + mid;
    }
    return mid;
}
function mid2id(mid) {
    var id = '';
    for (var i = mid.length - 4; i > -4; i = i - 4) //从最后往前以4字节为一组读取mid字符
    {
            var offset1 = i < 0 ? 0 : i;
            var len = i < 0 ? parseInt(mid.length % 4) : 4;
            var str = mid.substr(offset1, len);
            str = str62to10(str).toString();
            if (offset1 > 0)
            {
                    while (str.length < 7) {
                            str = '0' + str;
                    }
            }
            id = str + id;
    }
    return id;
}'''
ctx = execjs.compile(jspython) # 编译 js
mid = 'Is0XboARR'
id = ctx.call('mid2id', mid)
print(id)

但是,编写代码转化后,我惊讶地发现Is0XboARR转化成的是4466768535861595,而不是4467107636950632 `,在可以确保代码无误的情况下,我试了 N 个 M 次,没有一组匹配上,一首凉凉送给自己。

在 m.weibo.cn 站点上,一条微博评论的起始 URL 如下:

https://m.weibo.cn/comments/hotflow?id=4467107636950632&mid=4467107636950632

当时吧,就抱着试一试的心态,在浏览器输入了

https://m.weibo.cn/comments/hotflow?id=4466768535861595&mid=4466768535861595

没想到,居然出现了想要的微博的评论,真是山重水复疑无路,柳暗花明又一村。

经过大量测试,我发现这上面两条 URL,内容并不是完全相同,两者评论文本有不同程度的时延,有时前者领先 后者几分钟,有时后者领先前者几分钟,不过我觉着问题不大。猜想是微博评论的一个数据备份同步策略:真实的评论保存在某个未知的数据库中,依次同步到不同的站点,所以有时间差(当然只是猜想,具体还得问内部工作人员…)。

于是,在爬取一个话题的所有微博后,我们可以将那些评论数大于 0 的微博的 mid 批量转成 id,然后新建一个过渡 csv 文件,除了 mid、id 列,新增一个字段 isFinished 用来记录哪些微博的评论已经爬取过,方便出错了可以下次直接从没有爬取评论的第一条微博开始

但是这样必须要解决的一个问题是,必须要知道什么时候一条微博的评论全部抓完,在上个版本的 WeiboSuperCommentScrapy.py 中,程序并没有自动判断什么时候停止?其实很简单,假如评论有 100 页,组装参数 101 页爬取后都是重复的评论,爬到重复的就应该停止了,所以每次爬取一条微博的所有评论时,如果列表中不存在评论的唯一标识 wid,就将 wid 追加 保存到列表中,否则就算该条微博的评论爬取结束.。

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2020-05-22,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 月小水长 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 要实现这个功能,首先要知道,微博的 mid 和 id 分别是什么?
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档