基于Java爬取微博数据(五) 补充微博正文列表图片 or 视频 内容

简介: 【5月更文挑战第15天】基于Java爬取微博数据(五) 补充微博正文列表图片 or 视频 内容

在通过对微博正文内容中的图片 or 视频内容进行分析后,图片 or 视频 链接是可以直接通过 Java 代码下载或者转存的,那么这样就可以补充我们在 【基于Java爬取微博数据(一) 微博主页正文列表数据  时缺失的图片 or 视频信息了,当然,如果你的需求并不需要转存微博正文列表内容中的图片 or 视频的话,那么你就无需进行下面的操作了。在开始进行微博主页正文列表数据 补充 图片 or 视频内容之前,先来分析一下获取到的微博正文列表数据的内容。

数据分析

同样的,我们先找到获取微博正文列表数据的 ajax 请求 /ajax/statuses/mymblog?uid=1686546714&page=1&feature=0 的响应返回数据

image.png

获取到微博正文列表请求响应返回的数据之后,我从中取出一个含图片的完整的微博正文 json 对象 以及 一个含视频的完整的微博正文 json 对象来做一个比较

image.png

通过对比工具 Beyond Compare 进行比较这两种情况下返回数据格式的不同,可以看到 含图片的微博正文 返回数据比 含视频的微博正文多了 pic_infos 对象

image.png

继续向下比较可以看到 含图片的微博正文 比 含视频的微博正文 少了 page_info对象 而 page_info对象 里面的 media_info 对象正是视频所在对象

image.png

到这里,对于微博正文列表内容 含图片微博正文 以及 含视频微博正文 的数据格式基本的分析及对比就结束了,下面开始在 获取微博正文列表内容 DemoWeiBo 的 main 方法中补充这一块内容的获取。

补充图片 or 视频

下面开始补充图片 or 视频 链接的获取操作,考虑到视频链接有 Expires  过期时间字段,那么这里在导出 微博正文列表内容 到 Excel 中时保存 转存后的图片 or 视频路径,首先给导出实体类 ExcelData 增加如下字段

image.png

然后在获取微博正文内容列表 main 方法中增加如下代码,这里需要注意的是 pic_ids 和 pic_infos 是配套出现的, pic_ids 的值 就是 pic_infos 子对象的 key

image.png

关于 pic_infos 的子对象包括多种 宽高 尺寸的图片链接地址,你可以根据自己的需要选择不同宽高的图片进行转存

image.png


最后补充的转存微博正文图片的代码如下

image.png

下面再来看获取视频操作,你可以选择 media_info 对象内的以下几种清晰度的视频,

image.png

或者也可以选择 media_info 对象内的 playback_list ,里面是 四种清晰度的视频选择,你可以选择其中一种或者多种清晰度的视频链接

image.png

最终补充获取微博正文视频内容的代码如下

image.png

到这里,补充微博正文内容列表 获取 图片 or 视频的操作就完成了,改造后的 DemoWeiBo.java 代码完整版如下

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

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

import java.io.BufferedInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.net.HttpURLConnection;
import java.net.URL;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
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";
        String unfoldurl = "https://weibo.com/ajax/statuses/longtext?id=%s";
        String cookie = "你的 Cookie";

        // 初始化日期格式
        SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        //初始化导出Excel数据列表
        List<ExcelData> excelDataList = new ArrayList<>();

        // 循环抓取前2页数据
        for (int i = 1; i <= 3; 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 jsonObject = JSON.parseObject(body).getJSONObject("data");
                JSONArray list = null;
                if (Objects.nonNull(jsonObject)) {
                    // 处理数据列表
                    list = jsonObject.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, "");
                        String repost = data.getString("reposts_count");
                        String comment = data.getString("comments_count");
                        String like = data.getString("attitudes_count");

                        //获取微博正文图片信息
                        StringBuffer pic_url = new StringBuffer();
                        Long pic_num = data.getLong("pic_num");
                        if (pic_num > 0 ) {
                            JSONArray pic_ids = data.getJSONArray("pic_ids");
                            JSONObject pic_infos = data.getJSONObject("pic_infos");
                            // 遍历 pic_ids 获取 pic_infos 子对象 key
                            for (Object json : pic_ids) {
                                String key = (String) json;
                                JSONObject pic = pic_infos.getJSONObject(key);
                                JSONObject largest = pic.getJSONObject("largest");
                                // 提取图片URL并处理
                                String imageUrl = largest.getString("url");
                                String filename = imageUrl.substring(imageUrl.lastIndexOf("/") + 1);
                                // 下载图片
                                String savePath = "E:\\2024weibo\\" + filename;
                                downloadPicture(imageUrl, savePath);
                                pic_url = pic_url.append(savePath).append(",");
                            }
                        }

                        //获取微博正文视频信息
                        String video_url = "";
                        JSONObject page_info = data.getJSONObject("page_info");
                        if (Objects.nonNull(page_info)) {
                            JSONObject media_info = page_info.getJSONObject("media_info");
                            String mp4_hd_url = media_info.getString("mp4_hd_url");
                            String filename = mp4_hd_url.substring(mp4_hd_url.lastIndexOf("/") + 1, mp4_hd_url.indexOf("?"));
                            // 下载视频
                            String savePath = "E:\\2024weibo\\" + filename;
                            downloadPicture(mp4_hd_url, savePath);
                            video_url = savePath;
                        }

                        //有一种情况,就是当页面文本内容过多的时候,微博默认不展示全部,而是出现 【...展示】 按钮,此时需要再请求一个 URL 获取展开后的文本内容
                        if (text.lastIndexOf("...展开") != -1) {
                            //说明存在 展开 需要重新获取 text 内容
                            String mblogid = data.getString("mblogid");
                            // 格式化URL并发送HTTP请求获取响应
                            String unfoldurlstr = String.format(unfoldurl, mblogid);
                            HttpResponse response2 = HttpUtil.createGet(unfoldurlstr)
                                    .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();
                            // {"ok": 1,"http_code": 200,"data": {}}
                            String body2 = response2.body();
                            JSONObject jsonObject2 = JSONObject.parseObject(body2).getJSONObject("data");
                            String longTextContent = jsonObject2.getString("longTextContent");
                            System.out.println("longTextContent:"+longTextContent);
                            //补全后的内容赋给 text
                            text = longTextContent;
                        }

                        // 创建ExcelData对象并填充数据
                        ExcelData excelData = new ExcelData();
                        //发布时间
                        excelData.setDate(created);
                        //点赞数
                        excelData.setLike(Long.parseLong(like));
                        //评论数
                        excelData.setComment(Long.parseLong(comment));
                        //转发数
                        excelData.setRepost(Long.parseLong(repost));
                        //原始内容
                        excelData.setContent(text);
                        //图片地址
                        excelData.setImgUrl(pic_url.toString());
                        //视频地址
                        excelData.setVideoUrl(video_url);
                        excelDataList.add(excelData);
                    }
                }

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

        // 输出开始写入Excel的提示
        System.out.println("Excel写入数据开始");
        // 写入Excel的函数调用
        EasyExcel.write("E:/微博.xlsx", ExcelData.class)
                .sheet("Sheet1")
                .doWrite(excelDataList);
        System.out.println("Excel写入数据结束");
    }

    /**
     * 下载图片到指定路径
     *
     * @param imageUrl 图片的URL地址
     * @param savePath 图片保存的本地路径
     */
    public static void downloadPicture(String imageUrl, String savePath){

        BufferedInputStream in = null;
        FileOutputStream out = null;
        HttpURLConnection connection = null;
        try {
            // 创建URL对象并打开连接
            URL url = new URL(imageUrl);
            connection = (HttpURLConnection) url.openConnection();
            // 设置请求方法为GET
            connection.setRequestMethod("GET");
            // 建立连接
            connection.connect();

            // 获取响应码并判断是否下载成功
            int responseCode = connection.getResponseCode();
            if (responseCode == HttpURLConnection.HTTP_OK) {
                // 创建输入流和输出流,用于读取和保存图片
                in = new BufferedInputStream(connection.getInputStream());
                out = new FileOutputStream(savePath);

                // 缓冲区,用于一次读取和写入一定量的数据
                byte[] buffer = new byte[1024];
                int bytesRead;
                // 循环读取直到没有数据
                while ((bytesRead = in.read(buffer)) != -1) {
                    out.write(buffer, 0, bytesRead);
                }
                System.out.println("图片/视频 下载成功,保存路径:" + savePath);
            } else {
                // 响应码不为HTTP_OK,下载失败
                System.out.println("无法下载图片/视频,响应码:" + responseCode);
            }

        }catch (Exception e) {
            // 捕获异常并打印堆栈信息
            e.printStackTrace();
        }finally {
            // 无论成功或失败,最后都关闭流和连接
            // 关闭输入流
            if (in != null) {
                try {
                    in.close();
                } catch (IOException e) {
                    // 将IO异常转为运行时异常抛出
                    throw new RuntimeException(e);
                }
            }
            // 关闭输出流
            if (out != null) {
                try {
                    out.close();
                } catch (IOException e) {
                    // 将IO异常转为运行时异常抛出
                    throw new RuntimeException(e);
                }
            }
            // 关闭连接
            if (connection != null) {
                connection.disconnect();
            }
        }
    }
}

执行结果

执行main 方法后的输出 Excel 结果如图

image.png

图片链接和视频链接都已经转存记录成功。

相关文章
|
1天前
|
JSON Java 数据格式
java读取接口返回的json数据 (二)
java读取接口返回的json数据 (二)
13 5
|
1天前
|
JSON Java 数据格式
java读取接口返回的json数据
java读取接口返回的json数据
15 5
|
1天前
|
安全 Java 程序员
Java8实战-用流收集数据
Java8实战-用流收集数据
6 0
|
6天前
|
Java 开发工具 计算机视觉
Java使用OpenCV3.2实现视频读取与播放
Java使用OpenCV3.2实现视频读取与播放
5 0
|
6天前
|
监控 前端开发 JavaScript
|
6天前
|
Java Maven Windows
java读写串口数据
java读写串口数据
|
9天前
|
Java 程序员 Linux
网络编程套接字(3)——Java数据报套接字(UDP协议)
网络编程套接字(3)——Java数据报套接字(UDP协议)
11 0
|
9天前
|
JavaScript Java 测试技术
基于springboot+vue.js+uniapp小程序的java语言的考试信息报名系统附带文章源码部署视频讲解等
基于springboot+vue.js+uniapp小程序的java语言的考试信息报名系统附带文章源码部署视频讲解等
12 0
|
10天前
|
数据采集 存储 NoSQL
Java爬虫-爬取疫苗批次信息
为了解决疫苗批号查询难题,作者因个人情况需查询脊髓灰质炎灭活疫苗信息,发现官网查询系统不便使用。于是,技术大展身手,编写了一个Java爬虫,利用Hutool、Jsoup和Spring Boot的MongoDB库,抓取并存储了中国食品药品检定研究院等多家机构近十年的疫苗批次信息。代码示例展示了如何爬取数据并存入MongoDB,方便按需查询。
44 0
|
10天前
|
NoSQL Java Redis
【Redis】 Java操作客户端命令——列表操作与哈希操作
【Redis】 Java操作客户端命令——列表操作与哈希操作