基于Java爬取微博数据(一) 微博主页正文列表数据

简介: 【5月更文挑战第16天】讲述如何通过 Java 爬取微博数据 微博主页正文列表数据,以及相应的注意点

爬虫背景

最近有这方面的需求,于是就研究了一下通过Java爬取微博数据,由于本人是后端Java开发,因此没有研究其他爬取微博数据的方法,比如通过Python爬取微博数据。大家感兴趣的可以自行查找基于Python爬取微博数据的方法。在爬取微博数据之前,先声明一下,本人爬取的微博数据仅用于测试Java爬取微博数据的可行性,并不会用于其他非正当地方,另外,爬取的数据也都是每个人都可以通过微博客户端正常看到的,不存在爬取隐秘数据的情况。大家在进行爬取数据的操作时也应注意不该爬取非授权数据,防止给自喜提“非法获取计算机信息系统数据罪”“破坏计算机信息系统罪”等。一切爬虫操作都应在合法合规的情况下进行。

爬虫分析

在进行爬虫操作之前,我们先来看一下微博客户端的页面结构,以及对应的请求链接,数据响应情况等,方便为后续爬取微博数据做准备。比如这里打开一个环球网的微博主页:https://weibo.com/u/1686546714  可以看到

那么我们打开浏览器开发者工具,按F12键,打开开发者工具,选择【网络】或者【network】,然后再次刷新当前页面可以看到如下请求


点击对应的URL,查看URL的响应,最终会找到请求链接 /ajax/statuses/mymblog?uid=1686546714&page=1&feature=0  的响应正是我们需要爬取的数据内容来源



到这里,确定了数据来源URL之后,我们就可以进行后续的爬取数据操作了。

爬取数据

整个爬取数据操作我们需要用到两个 jar 包 hutool-all 、 fastjson ,那么我们需要首先在项目 pom.xml 文件中引入这两个 jar 包

<!-- hutool-all -->
<dependency>
  <groupId>cn.hutool</groupId>
  <artifactId>hutool-all</artifactId>
  <version> 5.3.4</version>
</dependency>
<!-- 阿里JSON解析器 -->
<dependency>
  <groupId>com.alibaba</groupId>
  <artifactId>fastjson</artifactId>
  <version>1.2.80</version>
</dependency>

jar 包引入之后开始编写代码,编写完成后完整代码如下  DemoWeiBo.java

package com.ruoyi.web.controller.demo.controller;

import cn.hutool.http.HttpResponse;
import cn.hutool.http.HttpUtil;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Objects;

public class DemoWeiBo
{
     /**
     * 主函数入口,用于从微博抓取数据并存储到Excel中。
     *
     * @param args 命令行参数(未使用)
     * @throws ParseException 当日期解析发生错误时抛出
     */
    public static void main(String[] args) throws ParseException {
        // 定义微博数据抓取的URL模板
        String url = "https://weibo.com/ajax/statuses/mymblog?uid=1686546714&feature=0&page=%s";

        // 初始化日期格式
        SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

        // 循环抓取3页数据
        for (int i = 1; i <= 1; i++) {
            try {
                // 输出开始抓取的提示信息
                System.out.println("开始获取第" + i + "页数据");

                // 格式化URL并发送HTTP请求获取响应
                String urlstr = String.format(url, i);
                HttpResponse response = HttpUtil.createGet(urlstr)
                        .header("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.0.0 Safari/537.36")
                        .header("Cookie","浏览器Cookie")
                        .execute();

                // 解析响应体
                String body = response.body();
                //System.out.println(body);

                JSONObject jsonObject2 = JSONObject.parseObject(body).getJSONObject("data");
                JSONArray list = null;
                if (Objects.nonNull(jsonObject2)) {
                    // 处理数据列表
                    list = jsonObject2.getJSONArray("list");

                    // 遍历并处理每条微博数据
                    for (Object o : list) {
                        JSONObject data = (JSONObject) o;
                        // 解析并处理微博的其他信息
                        Date created = new Date(data.getString("created_at"));
                        System.out.println("created:"+dateFormat.format(created));
                        String regex = "<[^<>]*>";
                        String text = data.getString("text").replaceAll(regex, "");
                        System.out.println("text:"+text);
                        String repost = data.getString("reposts_count");
                        System.out.println("repost:"+repost);
                        String comment = data.getString("comments_count");
                        System.out.println("comment:"+comment);
                        String like = data.getString("attitudes_count");
                        System.out.println("like:"+like);
                    }
                }

                // 输出完成提示并关闭响应,休眠以避免频繁请求
                System.out.println("第" + i + "页数据获取完毕");
                response.close();
                // 如果列表为空,终止循环
                if (list == null || list.size() == 0) {
                    break;
                }
                Thread.sleep(700);
            } catch (Exception e) {
                // 打印异常信息
                e.printStackTrace();
            }
        }
    }
}

代码中请求 URL 中的参数 page 代表当前爬取的是第几页数据,因此代码中进行了字符占位,方便后续的分页数据的替换


爬取微博数据时,必须要为请求 URL 添加 Header 信息 ,增加请求头 Cookie ,没有请求头 Cookie 的话,无法返回正常的响应数据,而是重定向到登录链接地址



那么关于请求头 Cookie 的来源,我们可以到浏览器的【网络】中刚才找到的请求 URL ,点击【标头】 下滑看到如下内容,红框部分就是 Cookie 内容


由于没有登录账号,因此这里的 Cookie 就属于访客 Cookie,那么微博对于访客 Cookie 的数据访问权限比较有限,在通过访客 Cookie 获取数据时,你只能获取当前请求 URL 的前两页数据,每页 20 条,整体也就是 40条数据,如果有置顶微博的话,置顶微博不算在这两页内,那么你就可能会获取到 大于 40 条的微博数据。当你获取 第 3 页数据时,请求链接只返回成功状态,但是没有 data 数据返回


而正常情况下 response.body() 应该返回这样的内容


response.body() 数据格式化之后 如图



获取到微博数据之后,在代码中打印的数据内容具体属性 text : 文本内容  reposts_count : 转发数  comments_count : 评论数  attitudes_count : 点赞数

最终的打印结果可以看到如下请求链接返回内容,


到这里我们爬取微博数据就完成了,整个代码逻辑比较清晰,后续对于爬取到的微博数据的处理可以根据具体的业务需求。


另外,对于代码中的正则表达式 String regex = "<[^<>]*>"; 表示的意义:【用于匹配以"<"开头,紧接着是0个或多个不包括"<"和">"的字符,最后以">"结尾的字符串。这个正则表达式常用于从一段文本中提取标签内容,例如从

<html><body><h1>Hello, World!</h1></body></html>

中提取出

Hello, World!

在线正则表达式匹配结果如图


当然,微博数据并不是只有这些的,你可以直接将我们爬取数据的请求 URL 放在浏览器看到


注意点

对于请求 URL 请求头 Cookie 的获取,你可以选择游客 Cookie 或者登录账号后的 Cookie ,这里个人建议使用登录账号后从浏览器拿出的 Cookie,可以获取当前登录账号关注过的用户发布的所有微博数据。关于有效期,百度搜索关于微博登录账号后的 Cookie 有效期是 30天,个人实测了一次,大概十几天后失效,由于中途可能会有其他影响,不一定准确。有时间的大家也可以测一下。不建议使用游客 Cookie 的原因除了获取数据只能获取前 2 页数据外的因素,还有就是不知道具体游客 Cookie 的有效期,有不确定因素在里面,无法保证数据来源稳定了。


到这里可能有人会觉得从浏览器拿出登录后的 Cookie 操作显得不太高级,且比较笨拙,想要通过代码模拟微博登录从而获取 Cookie,这里个人给出的建议是微博目前的登录逻辑安全性较高,需要短信验证且有动态图验证,即使通过扫码登录或者账号登录,验证同样也是多重验证,且不说模拟登录的难度有多大,如果你能成功绕过登录或者模拟登录成功,那么感觉你离“破坏计算机信息系统罪”也不远了。因此个人建议保守一点,手动登录后从浏览器拿出 Cookie 放入爬虫代码中进行数据获取即可,无需费力不讨好的模拟登录。


另外说明,本文是把原有的   基于Java爬取微博数据(一) 微博主页正文列表数据  拿过来,而原有的博文将会更名为 基于Java爬取微博数据(完整版),特此说明。

相关文章
|
3天前
|
存储 分布式计算 监控
Java一分钟之-Hazelcast:内存数据网格
【6月更文挑战第17天】**Hazelcast是开源的内存数据网格(IMDG),加速分布式环境中的数据访问,提供内存存储、分布式计算、线性扩展及高可用性。常见挑战包括内存管理、网络分区和数据分布不均。通过配置内存限制、优化网络和分区策略可避免问题。示例展示如何创建Hazelcast实例并使用分布式Map。使用Hazelcast提升性能和扩展性,关键在于理解和调优。**
17 1
|
6天前
|
缓存 NoSQL Java
Java高并发实战:利用线程池和Redis实现高效数据入库
Java高并发实战:利用线程池和Redis实现高效数据入库
24 0
|
2天前
|
存储 Java API
深入剖析Java Map:不只是存储数据,更是设计艺术的体现!
【6月更文挑战第18天】Java Map是键值对数据结构的艺术,展示了设计效率与易用性的平衡。HashMap利用哈希表实现快速访问,TreeMap通过红黑树保证排序。选择合适的实现类如HashMap、TreeMap或LinkedHashMap至关重要。注意空指针异常,谨慎在遍历时修改Map。Map的高效使用能提升编程效果。
|
3天前
|
Java
在 Java 中,类是一种定义对象的模板,它包含数据成员(字段)和方法。
在 Java 中,类是一种定义对象的模板,它包含数据成员(字段)和方法。
|
7天前
|
JSON Java 数据格式
java读取接口返回的json数据 (二)
java读取接口返回的json数据 (二)
18 5
|
7天前
|
JSON Java 数据格式
java读取接口返回的json数据
java读取接口返回的json数据
19 5
|
8天前
|
安全 Java 程序员
Java8实战-用流收集数据
Java8实战-用流收集数据
8 0
|
1天前
|
Java 开发者
线程的诞生之路:Java多线程创建方法的抉择与智慧
【6月更文挑战第19天】Java多线程编程中,开发者可选择继承Thread类或实现Runnable接口。继承Thread直接但受限于单继承,适合简单场景;实现Runnable更灵活,支持代码复用,适用于如银行转账这类需多线程处理的复杂任务。在资源管理和任务执行控制上,Runnable接口通常更优。
|
1天前
|
Java
Java 多线程新手必读:线程的创建技巧与陷阱
【6月更文挑战第19天】Java多线程初学者须知:创建线程可通过继承`Thread`或实现`Runnable`接口。继承`Thread`限制单继承,实现`Runnable`更灵活。记得调用`start()`而非`run()`启动线程,避免并发问题时需正确同步共享资源。示例代码展示两种创建方式及未同步导致的问题。
|
1天前
|
Java
揭秘!为何Java多线程中,继承Thread不如实现Runnable?
【6月更文挑战第19天】在Java多线程中,实现`Runnable`比继承`Thread`更佳,因Java单继承限制,`Runnable`可实现接口复用,便于线程池管理,并分离任务与线程,提高灵活性。当需要创建线程或考虑代码复用时,实现`Runnable`是更好的选择。