使用Java和XxlCrawler获取各城市月度天气情况实践

目录

前言

一、历史数据获取

1、关于天气后报

2、信息界面分析 

二、数据的提取开发

1、PageVo的定义

 2、属性定义

3、实际信息抓取

三、信息抓取调试以及可能的问题

1、信息获取成果

2、关于超时的问题

四、总结


前言

        这篇文章主要来源于一个我们家小朋友的一个作业,作业的主要内容是要求小朋友做一个统计,在上半学期学习了统计知识,然后要结合生活实际进行统计应用,因此有了这个作业。具体要求是在一定时间范围内(一个月),要求小朋友制作一个表格,需要记录一个月内每一天的天气情况,比如阴晴雨雪。然后在这个记录之上,要求统计出这个月不同的天气有多少天?比如晴天多少天,雨天多少天,然后根据统计结果,计算这个月最多的天气是什么?最少的是什么。这题目本身不难,只要每天都进行记录的话,基本也就没什么问题。然而,中间因为小朋友身体原因。没有及时记录,中间有一段时间没有及时记录。于是我们想,只能到网上查一下历史天气。

        然而我发现,小朋友中间有好几天都忘了记录,数据都有空缺。于是只能按照遗忘的日期来进行补数据。虽然最后把缺失的数据都补回来了。当时在想,还好只是一个月的数据,如果要三个月,半年,甚至是一年的数据,我还能一天一天的找数据不成。作为技术人,需要用一点技术手段来解决这个问题。

        本文主要讲解使用Java开发语言,使用XxlCrawler框架进行智能的某城市月度天气抓取实践开发。文章首先介绍目标网站的相关页面及目标数据的元素,然后讲解在信息获取过程的一些参数配置以及问题应对,最后结合实际代码实际抓取一个城市(以长沙为例)某月度天气数据。通过本文,您可以更加了解XxlCrawler的具体使用,知道如何解决页面返回慢的情况下如何通过超时参数来控制数据返回的问题,如果您是气象人,需要气象数据,则可以通过本文来获取想研究的地域的历史天气数据。

一、历史数据获取

        由于我们需要历史数据,因此需要找到历史数据源网站。关于天气的数据有很多网站可以提供。比较权威的就是国家的官方网站。这里呢,分享一个天气后报网站天气后报网,这个网站上可以提供城市的天气信息。本节主要介绍这个网站的内容和具体月度天气的页面。为下一步的信息获取做准备。

1、关于天气后报

        在浏览器中,输入它的官方网站:http://www.tianqihoubao.com/。可以看到它的官方界面。

        在上方的导航栏中,点击历史天气,可以切换到历史天气查询列表,默认按照行政区划列表的形式展示。

        根据我们的需要,比如(长沙),点击我们感兴趣的城市,打开城市历史天气列表:

        然后打开对应的月度天气连接,24年4月份。 

http://www.tianqihoubao.com/lishi/changsha/month/202404.html

         这是实际的网页地址,请注意这个地址,这里其实有两个变量,第一个是城市,也就是地址信息中的changsha,另外一个是时间即202404,通过网站静态化之后,这些信息都是有规律的。因此我们可以采用XxlCrawler来自动获取。

2、信息界面分析 

        在找到了信息源之后,我们需要分析一些网页的结构,网页信息很多,我们只关心目标数据。这里只需要把表格中的几个关键信息提取出来即可。比如日期、天气状况、气温信息、风力风向信息。这些关键的信息都是在一个表格中展示出来的。在页面中打开调试窗口,来看一下结构:

        首先来看一下网页结构,其主要的div是绑定在一个id='content'的网页元素下的。同时下面的数据是存在在标准的table中,因此我们只需要将table中的tr中循环提取出来即可。

二、数据的提取开发

        在明确了数据来源的网页结构之后,这一节我们来进行实际的数据提取的开发。通过XxlCrawler组件来获取信息。本小节着重讲解代码的设计与实现。

1、PageVo的定义

        熟悉XxlCrawler的朋友知道,PageVO是解析页面的一个对象。框架在读取到页面的信息后,会自动的将信息按照PageVO的配置,解析到实体类中。因此需要对PageVO进行定义。

@PageSelect(cssQuery = "#content >table >tbody >tr")
@AllArgsConstructor
@NoArgsConstructor
public static class PageVo {@PageFieldSelect(cssQuery=" >td:eq(0)")@Excel(name = "日期")private String day;@PageFieldSelect(cssQuery = ">td:eq(1)")@Excel(name = "天气状况")private String weatherInfo;@PageFieldSelect(cssQuery = ">td:eq(2)")@Excel(name = "最低气温/最高气温")private String weatherTemp;@PageFieldSelect(cssQuery = ">td:eq(3)")@Excel(name = "风力风向(夜间/白天)")private String weatherWind;
}

        在PageVO的定义过程中,我们使用了三个注解,第一个是@PageSelect(cssQuery = "#content >table >tbody >tr"),这个注解是用来进行页面抓取绑定的。第二个是@PageFieldSelect(cssQuery=" >td:eq(0)"),这个主要是用来进行具体的属性信息绑定,即解析哪个信息,设置到哪个属性当中去,在循环中特别好用。不用向之前那样,自己去解析。第三个是@Excel(name = "日期"),这个跟信息获取关系不大,只是用来最后将获取的信息写入到Excel表格中。当然,结合实际的需求,您可以把数据写入到数据库中,这样子可以在后期在需要的时候进行查询进行分析。

 2、属性定义

        按照JavaOOP的设计思想,这里我们将一些信息封装起来,比如User-Agent还有公共的请求地地址等统一定义,在进行信息抓取时可以直接使用。关键代码如下:

private static final String USER_AGENT = "Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/102.0.0.0 Safari/537.36";private List<PageVo> weatherList = new ArrayList<PageVo>();private static final String COMMON_URL  = "http://www.tianqihoubao.com/lishi/changsha/month/";

weatherList就是用来保存所有的天数数据的,在程序的最后可以用来保存数据或者持久化的作用。

3、实际信息抓取

        这里来定义实际信息抓取对象的配置,以及实际启动逻辑。

@Test
public void fetchWeaterInfo() {int year = 2023;int month = 9; // 月份从 0 开始,3 表示4月份String monthStr = "";monthStr +=  month < 10 ? "0" + month : month;String targetUrl = COMMON_URL + year + monthStr + ".html";System.out.println(targetUrl);// 构造爬虫XxlCrawler crawler = new XxlCrawler.Builder().setUrls(targetUrl).setAllowSpread(false)// 不允许扩散爬取.setThreadCount(3).setPauseMillis(3000).setUserAgent(USER_AGENT)//设置user_agent.setIfPost(false).setFailRetryCount(3)// 重试三次.setTimeoutMillis(1000 * 12)//超时时间,有些网站加载慢,一定要加这个时间.setPageParser(new PageParser<PageVo>() {@Overridepublic void parse(Document html, Element pageVoElement, PageVo pageVo) {//System.out.println(pageVoElement);weatherList.add(pageVo);}}).build();crawler.start(true);// 启动// excel工具包weatherList.remove(0);//把第一行表头移除掉ExcelUtil<PageVo> util = new ExcelUtil<PageVo>(PageVo.class);util.exportExcel(weatherList, year + "年" + month + "月天气情况表");System.out.println("finished...");
}

        这里需要注意的是,信息抓取器,每次得到的一个tbody中的一行,即tr的数据。我们需要将所有的数据解析完成之后,统一存放到一个List当中。实现月度的数据搜集,同时第一行是表头数据。需要剔除。因此,在写入到Excel之前,要将第一行删除,

weatherList.remove(0);//把第一行表头移除掉

三、信息抓取调试以及可能的问题

        这里分享实际的信息获取结果,对抓取的信息进行综合展示。同时这里简单分享在信息获取过程中可能遇到的问题和解决方案。

1、信息获取成果

        将上述代码运行后,可以在控制中看到以下输出信息:

http://www.tianqihoubao.com/lishi/changsha/month/202309.html
09:42:29.027 [main] INFO com.xuxueli.crawler.rundata.strategy.LocalRunData - >>>>>>>>>>> xxl-crawler addUrl success, link: http://www.tianqihoubao.com/lishi/changsha/month/202309.html
09:42:29.035 [main] INFO com.xuxueli.crawler.XxlCrawler - >>>>>>>>>>> xxl crawler start ...
09:42:29.038 [pool-1-thread-1] INFO com.xuxueli.crawler.thread.CrawlerThread - >>>>>>>>>>> xxl crawler, process link : http://www.tianqihoubao.com/lishi/changsha/month/202309.html
09:42:33.634 [pool-1-thread-1] INFO com.xuxueli.crawler.XxlCrawler - >>>>>>>>>>> xxl crawler is finished.
09:42:33.635 [pool-1-thread-2] INFO com.xuxueli.crawler.thread.CrawlerThread - >>>>>>>>>>> xxl crawler thread LocalRunData.getUrl interrupted.
09:42:33.635 [pool-1-thread-3] INFO com.xuxueli.crawler.thread.CrawlerThread - >>>>>>>>>>> xxl crawler thread LocalRunData.getUrl interrupted.
09:42:33.635 [pool-1-thread-1] INFO com.xuxueli.crawler.XxlCrawler - >>>>>>>>>>> xxl crawler stop.
09:42:33.636 [pool-1-thread-1] INFO com.xuxueli.crawler.thread.CrawlerThread - >>>>>>>>>>> xxl crawler thread LocalRunData.getUrl interrupted.
finished...

        这里提示,信息抓取完成,同时我们将数据写入到了Excel当中,找到目标文件夹,来看一下实际的效果。

日期天气状况最低气温/最高气温风力风向(夜间/白天)
2024年04月01日小雨 /大雨20℃ / 26℃东南风 1-3级 /南风 1-3级
2024年04月02日大雨 /小雨16℃ / 26℃西风 1-3级 /北风 1-3级
2024年04月03日中雨 /小雨15℃ / 18℃北风 1-3级 /北风 1-3级
2024年04月04日中雨 /小雨13℃ / 15℃西北风 1-3级 /北风 1-3级
2024年04月05日小雨 /小雨13℃ / 16℃西北风 1-3级 /北风 1-3级
2024年04月06日小雨 /小雨14℃ / 16℃北风 1-3级 /北风 1-3级
2024年04月07日小雨 /小雨14℃ / 19℃北风 1-3级 /西北风 1-3级
2024年04月08日多云 /多云15℃ / 24℃北风 1-3级 /北风 1-3级
2024年04月09日多云 /小雨15℃ / 23℃东北风 1-3级 /东风 1-3级
2024年04月10日多云 /小雨17℃ / 22℃东风 1-3级 /东北风 1-3级
2024年04月11日小雨 /小雨18℃ / 21℃北风 1-3级 /北风 1-3级
2024年04月12日阴 /小雨18℃ / 25℃东南风 1-3级 /东南风 1-3级
2024年04月13日中雨 /小雨20℃ / 26℃东南风 1-3级 /南风 1-3级
2024年04月14日小雨 /多云20℃ / 28℃东北风 1-3级 /东南风 1-3级
2024年04月15日小雨 /中雨21℃ / 31℃南风 1-3级 /东南风 1-3级
2024年04月16日暴雨 /中雨20℃ / 26℃西风 1-3级 /西风 1-3级
2024年04月17日小雨 /阴19℃ / 23℃西北风 1-3级 /北风 1-3级
2024年04月18日多云 /小雨19℃ / 27℃东南风 1-3级 /东南风 1-3级
2024年04月19日中雨 /阴18℃ / 24℃东南风 1-3级 /北风 1-3级
2024年04月20日小雨 /小雨19℃ / 24℃北风 1-3级 /西北风 1-3级
2024年04月21日阴 /多云17℃ / 24℃东风 1-3级 /北风 1-3级
2024年04月22日小雨 /阴19℃ / 24℃西北风 1-3级 /西北风 1-3级
2024年04月23日多云 /多云18℃ / 27℃北风 1-3级 /北风 1-3级
2024年04月24日多云 /小雨19℃ / 27℃东北风 1-3级 /东风 1-3级
2024年04月25日中雨 /多云19℃ / 25℃东风 1-3级 /东风 1-3级
2024年04月26日多云 /多云19℃ / 30℃西北风 1-3级 /东南风 1-3级
2024年04月27日中雨 /小雨20℃ / 28℃东北风 1-3级 /西南风 1-3级
2024年04月28日多云 /小雨20℃ / 29℃北风 1-3级 /东北风 1-3级
2024年04月29日中雨 /大雨18℃ / 25℃西风 1-3级 /西北风 1-3级
2024年04月30日小雨 /多云14℃ / 18℃北风 1-3级 /北风 1-3级

        大家可以对比原来的网页地址,可以看到表格获取的信息与网页一致。这里的实例仅提供一个例子,抛砖引玉,大家可以结合自己的实际工作。获取更多的天气信息。

2、关于超时的问题

        XxlCrawler的默认超时时间是5秒(5000ms),即5秒钟内数据没有返回则超时。其定义如下:

private volatile int timeoutMillis = XxlCrawlerConf.TIMEOUT_MILLIS_DEFAULT;     // 超时时间,毫秒// timeout default, ms
public static final int TIMEOUT_MILLIS_DEFAULT = 5*1000;

        在默认的情况下,页面经常超时,请求时会报以下的错误:

http://www.tianqihoubao.com/lishi/changsha/month/202404.html
11:03:27.685 [main] INFO com.xuxueli.crawler.rundata.strategy.LocalRunData - >>>>>>>>>>> xxl-crawler addUrl success, link: http://www.tianqihoubao.com/lishi/changsha/month/202404.html
11:03:27.693 [main] INFO com.xuxueli.crawler.XxlCrawler - >>>>>>>>>>> xxl crawler start ...
11:03:27.695 [pool-1-thread-2] INFO com.xuxueli.crawler.thread.CrawlerThread - >>>>>>>>>>> xxl crawler, process link : http://www.tianqihoubao.com/lishi/changsha/month/202404.html
11:03:32.697 [main] INFO com.xuxueli.crawler.XxlCrawler - >>>>>>>>>>> xxl crawler still running ...
11:03:33.456 [pool-1-thread-2] ERROR com.xuxueli.crawler.util.JsoupUtil - Read timeout
java.net.SocketTimeoutException: Read timeoutat org.jsoup.internal.ConstrainableInputStream.read(ConstrainableInputStream.java:58)at sun.nio.cs.StreamDecoder.readBytes(Unknown Source)at sun.nio.cs.StreamDecoder.implRead(Unknown Source)at sun.nio.cs.StreamDecoder.read(Unknown Source)at java.io.InputStreamReader.read(Unknown Source)at java.io.BufferedReader.fill(Unknown Source)at java.io.BufferedReader.read1(Unknown Source)at java.io.BufferedReader.read(Unknown Source)at org.jsoup.parser.CharacterReader.bufferUp(CharacterReader.java:87)at org.jsoup.parser.CharacterReader.current(CharacterReader.java:246)at org.jsoup.parser.TokeniserState$1.read(TokeniserState.java:12)at org.jsoup.parser.Tokeniser.read(Tokeniser.java:62)at org.jsoup.parser.TreeBuilder.runParser(TreeBuilder.java:86)at org.jsoup.parser.TreeBuilder.parse(TreeBuilder.java:61)at org.jsoup.parser.Parser.parseInput(Parser.java:51)at org.jsoup.helper.DataUtil.parseInputStream(DataUtil.java:218)at org.jsoup.helper.HttpConnection$Response.parse(HttpConnection.java:962)at org.jsoup.helper.HttpConnection.get(HttpConnection.java:355)at com.xuxueli.crawler.util.JsoupUtil.load(JsoupUtil.java:77)at com.xuxueli.crawler.loader.strategy.JsoupPageLoader.load(JsoupPageLoader.java:17)at com.xuxueli.crawler.thread.CrawlerThread.processPage(CrawlerThread.java:167)at com.xuxueli.crawler.thread.CrawlerThread.run(CrawlerThread.java:84)at java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source)at java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)at java.lang.Thread.run(Unknown Source)

        在网页中验证以下请求时间,请注意打开F12进行页面请求的时间跟踪:

        可以看到页面 ,页面加载大约花了11.93秒,接近12秒。因此其默认的5秒超时设置是不够的。具体的响应时间,请按照大家的实际情况合理设置。把超时时间延长后,就不会出现这个错误了。

四、总结

        以上就是本文的主要内容,本文主要讲解使用Java开发语言,使用XxlCrawler框架进行智能的某城市月度天气抓取实践开发。文章首先介绍目标网站的相关页面及目标数据的元素,然后讲解在信息获取过程的一些参数配置以及问题应对,最后结合实际代码实际抓取一个城市(以长沙为例)某月度天气数据。通过本文,您可以更加了解XxlCrawler的具体使用,知道如何解决页面返回慢的情况下如何通过超时参数来控制数据返回的问题,如果您是气象人,需要气象数据,则可以通过本文来获取想研究的地域的历史天气数据。行文仓促,定有不足之处,欢迎各位专家朋友在评论区中批评指正,万分荣幸。技术人通过自己的技术来解决一点生活问题,技术让生活更美好。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/841328.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

计算机基础概论:构筑数字社会的硬件基础与交互技术

&#x1f525; 个人主页&#xff1a;空白诗 文章目录 &#x1f3af; 引言&#x1f4bb; 什么是计算机&#xff1f;&#x1f331; 计算机的起源与发展&#x1f6e0;️ 电脑硬件的五大核心组件1. 中央处理器 (CPU) - 智慧的心脏2. 随机存取内存 (RAM) - 快速的记忆体3. 存储设备 …

安卓手机听书的各种免费方案

categories: Tips tags: Tips 写在前面 最近 Tencent 突然给微信读书上限制了, 普通用户一个月内仅能导入 3 本书, 这就让经常在 weread 上面听书入眠的我很无奈了. 折腾一下备选方案吧, 肯定是免费优先咯. 下面主要从支持 tts 的阅读器/ tts 免费中文引擎两个角度来讲. r…

Linux驱动(3)- LInux USB驱动层次

在Linux系统中&#xff0c;提供了主机侧和设备侧USB驱动框架。 从主机侧&#xff0c;需要编写USB驱动包括主机控制器驱动&#xff0c;设备驱动两类&#xff0c;USB 主机控制驱动程序控制插入其中的USB设备。 USB设备驱动程序控制该设备如何作为从设备与主机进行通信。 1.主机…

Attention相关问题笔试解析。

Attention相关问题笔试解析。 题目描述一&#xff1a;【选择】题目描述二&#xff1a;【简答】题目描述三&#xff1a;【代码】Scaled Dot-Product Attention&#xff1a;下面是用PyTorch实现的一个Attention机制的代码。这个实现包括一个简单的Scaled Dot-Product Attention机…

XX数字中台技术栈及能力

XX数字中台技术栈及能力 1 概述 XX数字中台面向数据开发者、数据管理者和数据应用者&#xff0c;提供数据汇聚、融合、治理、开发、挖掘、共享、可视化、智能化等能力&#xff0c;实现数据端到端的全生命周期管理&#xff0c;以共筑数字基础底座&#xff0c;共享数据服务能力…

Java核心: 脚本引擎和动态编译

静态语言和动态语言的在相互吸收对方的优秀特性&#xff0c;取人之长补己之短。脚本引擎和动态编译就是其中一个关键特性&#xff0c;扩展了Java的能力边界。这一篇我们主要讲两个东西: ScriptEngine&#xff0c;执行脚本语言代码&#xff0c;如JavaScript、Groovy JavaCompile…

插入排序(概述)

描述 插入排序为将一个数插入到以排序好的数组中 目录 描述 原理 特性 代码 原理 我们以升序为例 先将新数插入到数组的最后一位&#xff0c;记录下新数的值 从新数的位置开始往前遍历&#xff0c;如果前一位大于新数的值 则将当前位置修改为前一位的值 如果前一位小…

爬虫案例:有道翻译python逆向

pip install pip install requestspip install base64pip install pycrytodome tools 浏览器的开发者工具&#xff0c;重点使用断点&#xff0c;和调用堆栈 工具网站&#xff1a;https://curlconverter.com/ 简便请求发送信息 flow 根据网站信息&#xff0c;preview,respon…

php之sql代码审计

1 SQL注入代码审计流程 1.1 反向查找流程 通过可控变量(输入点)回溯危险函数 查找危险函数确定可控变量 传递的过程中触发漏洞 1.2 反向查找流程特点 暴力&#xff1a;全局搜索危险函数 简单&#xff1a;无需过多理解目标网站功能与架构 快速&#xff1a;适用于自动化代码审…

RK3588 opencv maliGPU图像拼接

1 左边图 图像大小:1920*1080 2右边图 图像大小:1920*1080 3拼接好的图像 图像大小&#xff1a;1920 *1080 4代码 #include <iostream> #include <opencv2/opencv.hpp> #include <opencv2/highgui.hpp>//图像融合 #include <opencv2/xfeatures2d.…

基于SpringBoot和Mybatis实现的留言板案例

目录 一、需求及界面展示 二、准备工作 引入依赖 .yml文件相关配置 数据库数据准备 三、编写后端代码 需求分析 代码结构 Model Mapper Service Controller 前端代码 四、测试 一、需求及界面展示 需求&#xff1a; 1. 输入留言信息&#xff0c;点击提交&…

qt-C++笔记之使用QtConcurrent异步地执行槽函数中的内容,使其不阻塞主界面

qt-C笔记之使用QtConcurrent异步地执行槽函数中的内容&#xff0c;使其不阻塞主界面 code review! 文章目录 qt-C笔记之使用QtConcurrent异步地执行槽函数中的内容&#xff0c;使其不阻塞主界面1.QtConcurrent::run基本用法基本用法启动一个全局函数或静态成员函数使用 Lambda…

iOS--锁的学习

iOS--锁的学习 锁的介绍线程安全 锁的分类自旋锁和互斥锁OSSpinLockos_unfair_lockpthread_mutexpthread_mutex的属性 NSLockNSRecursiveLockNSConditionNSConditionLockdispatch_semaphoredispatch_queuesynchronizedatomicpthread_rwlock&#xff1a;读写锁dispatch_barrier_…

摸鱼大数据——Hive基础理论知识——Hive基础架构

1、Hive和MapReduce的关系 1- 用户在Hive上编写数据分析的SQL语句&#xff0c;然后再通过Hive将SQL语句翻译成MapReduce程序代码&#xff0c;最后提交到Yarn集群上进行运行 2- 大家可以将Hive理解成有道词典&#xff0c;帮助你翻译英文 2、Hive架构 用户接口: 包括 CLI、JDBC/…

Java+Swing+Mysql实现飞机订票系统

一、系统介绍 1.开发环境 操作系统&#xff1a;Win10 开发工具 &#xff1a;Eclipse2021 JDK版本&#xff1a;jdk1.8 数据库&#xff1a;Mysql8.0 2.技术选型 JavaSwingMysql 3.功能模块 4.数据库设计 1.用户表&#xff08;users&#xff09; 字段名称 类型 记录内容…

脑机接口习题

9-12章习题 填空题 EEG电极分为 主动电极 和 被动电极 &#xff0c;其中 被动电极 直接与放大器连接&#xff0c; 主动电极 包含一个1~10倍的前置放大。除抗混淆滤波器&#xff0c;放大系统也包含由电阻器、电容器构成的模拟滤波器&#xff0c;把信号频率内容限制在一个特定的…

B树与B+树区别

B树和B树是常见的数据库索引结构&#xff0c;都具有相较于二叉树层级较少&#xff0c;查找效率高的特点&#xff0c;它们之间有以下几个主要区别&#xff1a; 1.节点存储数据的方式不同 B树的叶子结点和非叶子节点都会存储数据&#xff0c;指针和数据共同保存在同一节点中B树…

当标签中出现输入了字母或者数字直接在一行上,没有换行的 情况时怎么办

当标签块中输入的是包含字母或者数字的时候&#xff0c;他不会换行&#xff0c;在一行上显示滚动条的形式&#xff0c;而我们想让他走正常文档流&#xff0c;该换行的时候换行 想要的如下效果 给相应的元素块添加该代码即可 word-break: break-all; .card-content { …

酷开科技大屏营销,多元需求唤醒“客厅经济”

随着科技的发展和消费者习惯的变化&#xff0c;OTT大屏营销正逐渐成为客厅经济的新风向。OTT不仅改变了人们获取信息和娱乐的方式&#xff0c;也为品牌营销提供了新的机遇和挑战&#xff0c;OTT大屏营销已经成为客厅经济的重要组成部分。酷开科技通过其自主研发的智能电视操作系…