打开APP
userphoto
未登录

开通VIP,畅享免费电子书等14项超值服

开通VIP
【稳定可用 | 2022 最新】微博超级爬虫 | BuyiXiao''s Blog

写在前面

本文是微博超级爬虫系列 2022 最新最全指南。

微博超级爬虫系列的仓库地址在 https://github.com/Python3Spiders/WeiboSuperSpider

之前的连载全部在公众号,但是由于爬虫时常修改,公众号发文只能修改一次,故开此篇,保持更新!

相关开源代码仅为相关数据研究用,不做任何加速,没有 ip 代理,请勿用作其他用途,由此产生的法律风险本人概不承担。

相关未开源代码均为 pyd 或者 pyc 文件(不了解 pyd 或者 pyc 文件的读者 点击这里,pyd 只兼容 win 系统,pyc 则可以兼容 win/mac/linux ,也没有任何加速或 ip 代理。

运行本项目前,请确保已经关闭了 vpn 或者加速器,或者代理模式设置成 PAC 模式。

运行本项目的任何 py 文件,由于相关语法限制,python 版本大于等于 3.6 即可,32 bit or 64 bit 均可。

运行本项目的任何 pyd or pyc 文件,由于特有文件限制,请确保 python 环境是 python3.6.6 64 bit。

还有一点,需要注意的是,微博的唯一标识 id 有两种形式。纯数字和数字 + 字母形式,这两者可以相互转化。转化的代码在文末,点我直达,遇到相关问题时查阅即可。

单功能微博爬虫

只需要抓取一个用户的所有微博或文章,一个关键词或者话题的特定时间段的微博,一个位置签到的最新微博,特定微博的转发,评论,点赞等功能之一的读者,可以只参考此部分。

用户抓取系列

用户微博爬虫

见名知意,抓取一个用户的所有微博,针对 weibo.cn 站点,代码地址在 WeiboUserScrapy.py

运行代码需要安装的库罗列如下:

pip install requests

pip install lxml

pip install 成功了还报错 module not found?点击这里

csv 结果文件,保存在代码目录下的 user 文件夹中,保存字段格式如下:

字段名解释
wid数字 + 字母格式的微博唯一标识,可与纯数字形式 id 互转,
publish_time发布时间
content内容
image_urls图片链接,以英文空格分隔多个图片链接
weibo_link微博链接
forward_num转发数
comment_num评论数
like_num点赞数
is_origin是否是原创微博
origin_img_urls被转发微博图片链接

微博文章爬虫

在微博上发布的内容有的短文本 + 图片(也就是微博),还有文章等形式,微博文章爬虫爬取用户的所有文章。有文章标题,id,内容,发布时间,阅读数,评论数,点赞数,图片链接等字段或信息。

针对 weibo.com 站点,代码地址在 WeiboComPostSpider.py

cookie 获取及更多信息可以参考:爬取微博用户所有文章的爬虫

用户信息爬虫

微博用户信息爬虫指的是,根据微博用户 id,抓取用户的阳光信用、性别、地区、学校、公司等信息

针对 weibo.com 站点,代码全部开源在 WeiboSuperSpider 的 github 仓库地址,功能独立版文件夹下,取名 WeiboUserInfoSpider

拿到代码后需要填一下 headers 里面的 cookie,随便打开 weibo.com 站点里一个人的主页,比如

plaintext
1
https://weibo.com/u/1764201374

也可以是

plaintext
1
https://weibo.com/xiena

这种微博用户自定义形式,然后 F12 开始找 info 或者 detail 这两个 path 之一,复制它们的 cookie 即可。

有关该爬虫更多信息可以参考:超级方便的微博用户信息爬虫

用户搜索爬虫

微博用户信息爬虫是根据微博用户 Uid 来抓取公开的用户微博信息,但是很多时候,我们可能只知道这个用户的微博名字,并不知道 Uid,用户搜索爬虫就是完成从微博用户名到 Uid 的转换。

针对 weibo.com 站点,代码地址在 SearchUser.py

cookie 获取及更多信息可以参考:微博搜索用户爬虫

话题关键词系列

首先必须搞清楚微博的关键词、话题、超话这三者的区别。

首先 #buyixiao# 这个就是话题, 而 buyixiao 是关键词;使用关键词可以同时搜到同名话题,话题却不能搜到同名关键词。

话题和关键词区别明了,下面看 关键词话题 和 超话的区别

本爬虫只只能抓取关键词或话题,超话后续有精力再开发。抓取保存的结果 csv 文件字段格式如下:

字段名解释
mid纯数字形式的微博唯一标识,可与字母 + 数字形式 id 互转
publish_time发布时间
user_name微博作者名
user_link微博作者链接
content内容
image_urls图片链接
weibo_link微博链接
forward_num转发数
comment_num评论数
like_num点赞数

针对 weibo.com 站点,pyd 或者 pyc 获取及相关配置过程在 新版话题关键词爬虫发布

链接里相关配置流程可能更改,但是公众号文章无法多次修改,以最后获取的百度网盘链接里文件为准。

在这里补充一点,如果需要设置多个关键词同时抓取,按照以下格式设置 keyword:

“keyword”: “a b c”,

实践证明,不需要空格也行,效果相同,爬的结果是多个关键词的关系。

也可以参考视频教程:

转评赞系列

针对指定微博的转发、评论和点赞信息抓取。

评论爬虫

评论数据尤为重要,先来讲讲评论抓取。

评论数据的抓取难度较大,针对一条 100w+ 评论的抓取,通常分为三个量级难度的抓取:0.1w、1w、10w。0.1w 指只能爬到几千条,10w 指的是能爬到几十万条。

本爬虫 针对 weibo.com ,能够保存的字段信息如下:

字段名字段值
parent_comment_id父评论 id,为空说明该评论就是根评论
comment_id评论 id
comment_time评论时间
comment_user_name评论者昵称
comment_user_link评论者主页链接
comment_content评论内容
comment_like_num评论点赞数
child_comment_num子评论数,为 0 说明该评论可能就是子评论

抓取数据量在第二量级,单条 100w+ 的评论能抓到 1w-10w,当然,如果评论总量只有 10w,抓不到 10w。pyd 或者 pyc 获取及相关配置过程在 新版评论爬虫发布

链接里相关配置流程可能更改,但是公众号文章无法多次修改,以最后获取的百度网盘链接里文件为准。

如果想要免费抓取最高量级的评论,可以参考 单机单账号抓取了单条微博的 100w+ 评论

转发爬虫

抓取指定微博的抓发信息,针对 weibo.com,抓取保存的字段如下:

字段名解释
mid纯数字形式的微博唯一标识,可与字母 + 数字形式 id 互转
publish_time发布时间
user_name微博作者名
user_link微博作者链接
content内容
weibo_link微博链接
forward_num转发数
like_num点赞数

pyd 或者 pyc 获取及相关配置过程在 新版转发爬虫发布

链接里相关配置流程可能更改,但是公众号文章无法多次修改,以最后获取的百度网盘链接里文件为准。

点赞爬虫

看名字以为是手动点赞机器人,其实只是抓取点赞信息信息。

针对 m.weibo.cn,只能抓到最新的几千条点赞信息。

代码地址在:WeiboLikeSpider.py

详细信息及配置过程可以参考:新版点赞爬虫

位置签到系列

针对 weibo.com,微博位置签到爬虫,只能抓取到最新 1000 余条,比较稳定,不多赘述,直接查看:新版位置签到爬虫

超话系列

针对 weibo.com,下载超话相册和抓取活跃粉丝,比较稳定,不多赘述,直接查看:【开源】微博超话相册下载及超话活跃粉丝抓取

多功能集成爬虫

主要是针对上一步输出结果为微博信息,想要作为下一步或评论或转发输入的批量抓取,比如抓取一个微博话题下的所有评论,抓取一个用户发博的所有评论… 以及其他 DIY 功能,FT 导向,本部分仍在活跃更新

抓取话题下的所有评论

不只是话题,关键词也行,要求是输入为话题关键词爬虫的结果文件,输出为很多评论文件,也可合并之。

在上文所述 [新版微博评论爬虫] 中,只是针对单条微博的,如果是很多很多个微博需要爬评论,难道需要一个个输入 mid 和 uid 吗?考虑到这个问题,我特意写了个脚本,后,需要获取该话题下所有微博的评论,我们可以使用如下的 py 脚本代码自动构建视频中抓取评论所需要的 json 配置文件。

配套视频如下:

构建评论批量抓取配置文件的脚本附在文末,点我直达

抓取用户发布微博的所有评论

可以直接参考视频:

批量抓取转评赞

待更新…

加字段

给一些 csv 加上学校,地区,性别等字段,总的来说还是需要上文 用户信息爬虫,待更新。

下载图片

就是说,爬虫结果文件里面的图片链接怎么下载到本地,代码贴在文末,点我直达

数据分析及可视化相关

微博评论情感分析

pip install snownlp;然后文末的代码随取随用:点我直达

LDA

代码附在文末,点我直达 , 自行百度相关包安装过程,可能比较麻烦

时间序列可视化

直达文末代码

QA

为什么不做一个系统

以前尝试做过一个 GUI 系统,所有功能点击即可,后来微博改版,流程全部失效了,维护成本巨大,所以只关注基本功能。

为什么有些 pyd/pyc 是付费的

博主大厂全职,维护这个项目三年多,至少花费了我几百个小时的业余时间,为此熬过不少夜,废过不少食。所有设置了一些付费文章,3~9 块不等,算是对项目持续维护的激励,不是为文件付费,知悉。

遇到错误怎么办

可以先查看 常见错误汇总,没有找到答案的可以在本文文末评论。

附录代码

微博两种 id 相互转化代码

python
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
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
# -*- coding: utf-8 -*-
# author:           inspurer(月小水长)
# create_time:      2021/7/6 22:19
# 运行环境           Python3.6+
# github            https://github.com/inspurer
# 微信公众号         月小水长

import execjs
jspython = '''str62keys = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
/**
* 10进制值转换为62进制
* @param {String} int10 10进制值
* @return {String} 62进制值
*/
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;
}
/**
* 62进制值转换为10进制
* @param {String} str62 62进制值
* @return {String} 10进制值
*/
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;
}
/**
* id转换为mid
* @param {String} id 微博id,如 '201110410216293360'
* @return {String} 微博mid,如 'wr4mOFqpbO'
*/
function id2mid(id) {
    if (typeof (id) != 'string') {
            return false; // id数值较大,必须为字符串!
    }
    var mid = '';
    for (var i = id.length - 7; i > -7; i = i - 7) //从最后往前以7字节为一组读取mid
    {
            var offset1 = i < 0 ? 0 : i;
            var offset2 = i + 7;
            var num = id.substring(offset1, offset2);
            num = int10to62(num);
            mid = num + mid;
    }
    return mid;
}
/**
* mid转换为id
* @param {String} mid 微博mid,如 'wr4mOFqpbO'
* @return {String} 微博id,如 '201110410216293360'
*/
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) //若不是第一组,则不足7位补0
            {
                    while (str.length < 7) {
                            str = '0' + str;
                    }
            }
            id = str + id;
    }
    return id;
}'''
ctx = execjs.compile(jspython) # 编译 js

def mid2id(mid):
    return ctx.call('mid2id', mid)

def id2mid(id):
    return ctx.call('id2mid', id)

if __name__ == '__main__':
    global mid
    mid = 'L8J4vC6m7'
    id = mid2id(mid)
    print(id)
    id = '4655725672138197'
    mid = id2mid(id)
    print(mid)

下载图片代码

python
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
49
50
51
52
# -*- coding: utf-8 -*-
# author:           inspurer(月小水长)
# create_time:      2021/11/2 20:48
# 运行环境           Python3.6+
# github            https://github.com/inspurer
# 微信公众号         月小水长

import pandas as pd
df = pd.read_csv('易烊千玺V公益 - 文本.csv')

import os
image_folder = 'image'
if not os.path.exists(image_folder):
    os.mkdir(image_folder)

import hashlib
import requests

headers = {
    'authority': 'weibo.com',
    'x-requested-with': 'XMLHttpRequest',
    'sec-ch-ua-mobile': '?0',
    'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36',
    'content-type': 'application/x-www-form-urlencoded',
    'accept': '*/*',
    'sec-fetch-site': 'same-origin',
    'sec-fetch-mode': 'cors',
    'sec-fetch-dest': 'empty',
    'referer': 'https://weibo.com/1192329374/KnnG78Yf3?filter=hot&root_comment_id=0&type=comment',
    'accept-language': 'zh-CN,zh;q=0.9,en-CN;q=0.8,en;q=0.7,es-MX;q=0.6,es;q=0.5',
    'cookie': 'weibo.com 登录后随便哪一个接口的 cookie',
}

for index, row in df.iterrows():
    print(f'index: {index + 1}/{df.shape[0]}')
    image_urls = row['img_urls']
    if not type(image_urls) is float and len(image_urls) > 0:
        if image_urls == '无':
            print('无')
            continue
        image_url_list = image_urls.split(' ')
        for image_url in image_url_list:
            print(image_url)
            image_spilt = image_url.rsplit('.', 1)
            image_path = os.path.join(image_folder,
                                      '{}.{}'.format(hashlib.md5(image_spilt[0].encode('utf-8')).hexdigest(),
                                                     image_spilt[1]))
            if os.path.exists(image_path):
                continue
            with open(image_path, 'wb') as fp:
                response = requests.get(url=image_url, headers=headers)
                fp.write(response.content)

生成批量抓取评论的 json 配置代码

python
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
49
50
51
52
53
54
55
56
57
58
59
60
# -*- coding: utf-8 -*-
# author:           inspurer(月小水长)
# create_time:      2022/01/17 10:31
# 运行环境           Python3.6+
# github            https://github.com/inspurer
# 微信公众号         月小水长

import json
import pandas as pd
limit = 100000
from time import sleep
config_path = 'topic_comment_config.json'
with open(config_path, 'r', encoding='utf-8-sig') as f:
    config_json = json.loads(f.read())
data_path = f'./topic/{config_json['keyword']}.csv'
def drop_duplicate(path, col='mid'):
    df = pd.read_csv(path)
    # 去除重复行数据
    df.drop_duplicates(keep='first', inplace=True, subset=[col])
    # 可能还剩下重复 header
    df = df[-df[col].isin([col])]
    df.to_csv(path, encoding='utf-8-sig', index=False)

def main():
    drop_duplicate(data_path)

    df = pd.read_csv(data_path)

    # 清楚原有的 comments 配置,如不需要可注释
    config_json['comments'].clear()

    for index, row in df.iterrows():
        print(f'{index + 1}/{df.shape[0]}')
        comment_num = row['comment_num']
        weibo_link = row['weibo_link']
        if int(comment_num) <= 0:
            print(f'\n\n {weibo_link} 没有评论,不加入配置 json \n\n')
            continue
        if '?' in weibo_link:
            weibo_link = weibo_link[:weibo_link.index('?')]
        uid = weibo_link[weibo_link.index('com') + 4:weibo_link.rindex('/')]
        mid = weibo_link[weibo_link.rindex('/') + 1:]
        config_json['comments'].append({
            'index': f'N{len(config_json['comments'])}',
            'mid': mid,
            'uid': uid,
            'limit': limit,
            'user_name': row['user_name']
        })

    config_json['comments_pos'] = 0

    print(f'\n\n\n 共计 {len(config_json['comments'])} 条微博加入评论抓取队列...  \n\n\n')
    sleep(3)

    with open(config_path, 'w', encoding='utf-8-sig') as f:
        f.write(json.dumps(config_json, indent=2, ensure_ascii=False))

if __name__ == '__main__':
    main()

代码所需 topic_comment_config.json 文件格式如下:

json
1
2
3
4
5
6
7
8
{
  'cookie': '话题或评论的cookie',
  'keyword': '云南象2.6',
  'start_time': '2020-01-25-15',
  'end_time': '2020-01-25-17',
  'only_origin': false,
  'comments': []
}

评论情感分析代码

python
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
49
50
51
52
53
# -*- coding: utf-8 -*-
# author:           inspurer(月小水长)
# create_time:      2021/11/2 9:50
# 运行环境           Python3.6+
# github            https://github.com/inspurer
# 微信公众号         月小水长

'''
初步想法

1、评论者都是哪里人,echarts 地图
2、评论者性别分布
3、评论时间段分布,没必要分析,可能和发博时间有关?
4、评论情感倾向

'''
import pandas as pd

import re
def filter_html(text):
    if len(text) == 0 or text == None:
        return text

    # text为包含html标签内容
    content = re.sub('<[^>]*?>', '', text)
    return content

from snownlp import SnowNLP
def sentiment_score(input_file, text_col = 'text'):
    df = pd.read_csv(input_file)
    sentiment_score_col = 'sentiment_score'
    is_scored_col = 'has_scored'
    df[is_scored_col] = [False for _ in range(df.shape[0])]
    for index, row in df.iterrows():
        print(f'{index + 1}/{df.shape[0]}')

        if row[is_scored_col] == True:
            continue

        text = row[text_col]
        # 去除 html 标签
        text = filter_html(text)

        if len(text) == 0 or text == None:
            # 本行没有文本
            sentiment = -1
        else:
            sentiment = SnowNLP(text).sentiments

        df.loc[index, sentiment_score_col] = sentiment
        df.loc[index, is_scored_col] = True

    df.to_csv(input_file, index=False, encoding='utf-8-sig')

LDA 代码

python
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
# -*- coding: utf-8 -*-
# author:           inspurer(月小水长)
# pc_type           lenovo
# create_time:      2020/9/20 13:35
# file_name:        main.py
# github            https://github.com/inspurer
# qq邮箱            2391527690@qq.com
# 微信公众号         月小水长(ID: inspurer)

import pandas as pd

from sklearn.feature_extraction.text import CountVectorizer
from sklearn.decomposition import LatentDirichletAllocation
import pyLDAvis.sklearn

def doLDA(content, n_features=1000, n_topics=5, max_df=5, min_df=1):
    # 向量化
    n_features = n_features

    tf_vectorizer = CountVectorizer(strip_accents='unicode',
                                    max_features=n_features,
                                    stop_words='english',
                                    max_df=max_df,
                                    min_df=min_df)
    tf = tf_vectorizer.fit_transform(content)

    n_topics = n_topics
    # LDA 处理
    lda = LatentDirichletAllocation(n_components=n_topics, max_iter=50,
                                    learning_method='online',
                                    learning_offset=50.,
                                    random_state=0)
    lda.fit(tf)

    data = pyLDAvis.sklearn.prepare(lda, tf, tf_vectorizer)

    print(data)
    pyLDAvis.show(data)  # 可视化主题模型


if __name__ == '__main__':
    df = pd.read_csv('comments.csv')
    doLDA(content=df['content'].values.tolist(),n_topics=2)

时间序列可视化代码

正在更新中…

后话

本文首发: BuyiXiao’s Blog

链接地址:https://buyixiao.github.io/blog/weibo-super-spider.html

转载需注明来源。

如本项目对你有很多帮助,可以点击下方打赏赞助我持续维护。

本站仅提供存储服务,所有内容均由用户发布,如发现有害或侵权内容,请点击举报
打开APP,阅读全文并永久保存 查看更多类似文章
猜你喜欢
类似文章
【热】打开小程序,算一算2024你的财运
如何用Python分析豆瓣电影——以《我不是药神》《邪不压正》为例
Python解读:五月天线上演唱会刷屏!这里有你的青春吗?
基于Python对知网(CNKI)主题文献爬虫
V1.2For循环..htm
使用JavaScript实现移位密码
做动态图表,没有数据?用Python就能获取!
更多类似文章 >>
生活服务
热点新闻
分享 收藏 导长图 关注 下载文章
绑定账号成功
后续可登录账号畅享VIP特权!
如果VIP功能使用有故障,
可点击这里联系客服!

联系客服