Python 微博爬虫设计思路参考

目标

  • 获取微博热榜
  • 获取微博博文
  • 获取博文评论

实践

使用 Python 爬虫进行词频统计,分析网友评论倾向。

  • 获取某一条博文的所有评论
  • 分词、统计词频
  • 制作词云

流程与分析

获取 XSRF-TOKEN

需要先获取 XSRF-TOKEN ,请求如下接口即可:(这一步不定需要,但是前端每一部请求都携带有 XSRF-TOKEN 所以还是要获取一下)
GET https://weibo.com/newlogin

参数:

params = {
    'tabtype': 'weibo',
    'gid': '102803',  # 貌似是固定的
    'openLoginLayer': '0',
    'url': 'https://weibo.com/',
}

热榜请求

URL:GET https://weibo.com/ajax/side/hotSearch

不需要任何验证,直接可以请求。

获取推荐博文

URL:GET https://weibo.com/ajax/feed/hottimeline

参数:

params = {
    'since_id': '0',
    'refresh': '0',
    'group_id': '102803',
    'containerid': '102803',
    'extparam': 'discover|new_feed',
    'max_id': '0',
    'count': '10',
}

如果没有进行游客验证会被重定向到:GET https://passport.weibo.com/visitor/visitor 进行游客验证。

参数:

params = {
    'entry': 'miniblog',
    'a': 'enter',
    'url': ''  # 自定义来时的链接
}

经过测试发现不需要先访问这个地址,可以直接去游客验证请求

游客验证请求(获取门票):

POST https://passport.weibo.com/visitor/genvisitor2

参数:

params = {
    'cb': 'visitor_gray_callback',
    'tid': '',  # 可以不填
    'from': 'weibo',
}

服务器会响应类似如下的内容:

window.visitor_gray_callback &&
visitor_gray_callback({"retcode":20000000,"msg":"succ","data":
        {"next":"cross_domain","sub":"_2AkMR3yxzf8NxqwFRmfwTyWLmZIhzzAjEieKng92oJRMxHRl-yj9kqhQItRB6Ol8CnIdwUDcyy_MV5xEsWRW6mxQNIM5P",
        "subp":"0033WrSXqPxfM72-Ws9jqgMF55529P9D9WhKudzL7vNo6rVgM_I8.Nfw","alt":"","savestate":0,
        "tid":"01Aa9SQlUD5uH1PaX5dB4hUTYf1vHk_1S3H6bnpEw2bN1p","new_tid":false,"confidence":90}});

我们需要用到其中的几个参数:subsubp。可以使用正则表达式匹配。

然后用如上的参数重新去请求:

GET https://login.sina.com.cn/visitor/visitor

params = {
    'a': 'crossdomain',  # 踩的坑:`a` 参数是固定 `crossdomain` 而不是服务器传来的 `next` 参数值。
    's': sub,
    'sp': subp,
    'from': 'weibo',
    '_rand': random.random(),
    'entry': 'miniblog',
    'url': 'https://weibo.com/ajax/feed/hottimeline?since_id=0&refresh=0&group_id=102803&containerid=102803&extparam=discover%7Cnew_feed&max_id=0&count=10',
}

触发 302 跳转则代表验证通过。

获取长文本

GET https://weibo.com/ajax/statuses/longtext

参数:

params = {
    'id': ''  # 博文 mblogid
}

扫码登录

  • 前置验证
    请求 GET https://passport.weibo.com/sso/signin 获取 X-CSRF-TOKEN

参数:

params = {
    'entry': 'miniblog',
    'source': 'miniblog',
    'disp': 'popup',
    'url': 'https://weibo.com/newlogin?tabtype=weibo&gid=102803&openLoginLayer=0&url=https%3A%2F%2Fweibo.com%2F',  # 重定向
}
  • 获取二维码门票

请求 GET https://passport.weibo.com/sso/v2/qrcode/image

参数:

params = {
    'entry': 'miniblog',
    'size': '180',
}

请求标头带上 X-Csrf-Token

headers = {
    'Referer': 'https://passport.weibo.com/sso/signin?entry=miniblog&source=miniblog&disp=popup&url=https%3A%2F%2Fweibo.com'
}

需要先获取 X-Csrf-Token

响应:

{
  "retcode": 20000000,
  "msg": "succ",
  "data": {
    "qrid": "2MmZmg8E_AAM_bZzVmsg0CUhy_3DqSvEHBnFyY29kZQ..",
    "image": "https:\/\/v2.qr.weibo.cn\/inf\/gen?api_key=a0241ed0d922e7286303ea5818292a76&data=https%3A%2F%2Fpassport.weibo.cn%2Fsignin%2Fqrcode%2Fscan%3Fqr%3D2MmZmg8E_AAM_bZzVmsg0CUhy_3DqSvEHBnFyY29kZQ..%26sinainternalbrowser%3Dtopnav%26showmenu%3D0&datetime=1719910719&deadline=0&level=M&logo=https%3A%2F%2Fimg.t.sinajs.cn%2Ft6%2Fstyle%2Fimages%2Findex%2Fweibo-logo.png&output_type=img&redirect=0&sign=75306149231bc90427b64f08148a6123&size=180&start_time=0&title=sso&type=url"
  }
}
  • 获取二维码图片(生成二维码图片)

这个其实就是上一个接口的 image 数据,格式为 png 。

请求 GET https://v2.qr.weibo.cn/inf/gen

参数:

params = {
    'api_key': 'a0241ed0d922e7286303ea5818292a76',
    'data': 'https://passport.weibo.cn/signin/qrcode/scan?qr=2MmZmg8E_AAM_bZzVmsg0CUhy_3DqSvEHBnFyY29kZQ..&sinainternalbrowser=topnav&showmenu=0',
    'datetime': '1719910719',
    'deadline': '0',
    'level': 'M',
    'logo': 'https://img.t.sinajs.cn/t6/style/images/index/weibo-logo.png',
    'output_type': 'img',
    'redirect': '0',
    'sign': '75306149231bc90427b64f08148a6123',
    'size': '180',
    'start_time': '0',
    'title': 'sso',
    'type': 'url',
}
  • 巡回查码

请求 GET https://passport.weibo.com/sso/v2/qrcode/check

参数:

params = {
    'entry': 'miniblog',
    'source': 'miniblog',
    'url': 'https://weibo.com/newlogin?tabtype=weibo&gid=102803&openLoginLayer=0&url=https%3A%2F%2Fweibo.com%2F',
    # 重定向地址
    'qrid': '2MmZmg8E_AAM_bZzVmsg0CUhy_3DqSvEHBnFyY29kZQ..',  # 二维码id
    'disp': 'popup',
}

未扫描情况响应:

{
  "retcode": 50114001,
  "msg": "未使用",
  "data": null
}

已扫描情况响应:

{
  "retcode": 20000000,
  "msg": "succ",
  "data": {
    "url": "跳转URL"
  }
}

请求标头带上 X-Csrf-Token

headers = {
    'Referer': 'https://passport.weibo.com/sso/signin?entry=miniblog&source=miniblog&disp=popup&url=https%3A%2F%2Fweibo.com'
}
  • 验证登录的方法

请求 GET https://weibo.com/ajax/log/action

查看返回标头是否含有 X-Log-Uid 如果有则是用户ID。

获取评论

请求 GET https://weibo.com/ajax/statuses/buildComments 获取评论。

参数:

params = {
  'flow': '0',  # 按热度,1为按时间
  'is_reload': '1',
  'id': '博文数字ID',
  'is_show_bulletin': '2',
  'is_mix': '0',
  'count': '几个',
  'uid': '发文博主ID',
  'fetch_level': '0',
  'locale': 'zh-CN',
  'max_id': ''  # 用于下一趟加载评论,会这个值第一次请求这个接口时会提供,为0则已经获取全部
}

模块使用例子

from weibo import Weibo

wb = Weibo()

游客登录

wb.login_as_visitor()
print(wb.get_hottimeline())

扫码登录

import time

qrcode, data = wb.get_login_qrcode()
login = wb.check_qrcode(qrcode)
count = 0
while not login:
    time.sleep(1)
    login = wb.check_qrcode(qrcode)
    print(f"\r等待扫码登录......({count}s)", end="")
    count += 1
print("\r", end="")
print("登录成功。")

获取动态

# 获取用户动态
data = wb.get_mymblog(uid=7467555881,
                      page=0)

since_id = data['since_id']
for blog in data['list']:
    print("-" * 150)
    print("发布者:", blog['user']['screen_name'])
    print("发布时间:", blog['created_at'])
    print("发布内容:\n" + blog['text_raw'])
    print("博文ID:", blog['idstr'])

获取博文

blog = wb.get_status("Nw310uTcQ")
print("发布者:", blog['user']['screen_name'])
print("博文发布时间:", blog['created_at'])
print("发布内容:\n" + blog['text_raw'])
print("博文数字ID:", blog['idstr'])

获取评论

info = wb.get_comments(id=blog['idstr'],
                       user_id=blog['user']['id'],
                       count=10)

i = 0
while info['max_id'] != 0:
    for comment in info['data']:
        i += 1
        print(f"\r计数:{i}", comment['user']['screen_name'] + ":" + comment['text_raw'], end="")
        print(comment['text_raw'], file=comment_file, flush=True)

    time.sleep(0.5)
    info = wb.get_comments(id=blog['idstr'],
                           user_id=blog['user']['id'],
                           max_id=info['max_id'],
                           count=10)

获取热榜

for realtime in wb.get_hot_search()['realtime']:
    print(realtime['word'])
此文章同步至开源仓库(https://gitee.com/wojiaoyishang/everything-here)。
您可以点击链接查看更多详细信息,十分欢迎给我们提交 Issue 或者 PR ,一同为开源社区做贡献。
最近一次文章同步于 2024-07-08 20:42:51 。
暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇