当前位置: 首页 > news >正文

Ajax数据爬取

有时我们用requests 抓取页面得到的结果,可能和在浏览器中看到的不一样:在浏览器中可以看到正常显示的页面数据,而使用requests 得到的结果中并没有这些数据。这是因为 requests 获取的都是原始 HTML 文档,而浏览器中的页面是JavaScript 处理数据后生成的结果,这些数据有多种来源:可能是通过 Ajax 加载的,可能是包含在 HTML文档中的,也可能是经过 JavaScript 和特定算法计算后生成的。

对于第一种来源,数据加载是一种异步加载方式,原始页面最初不会包含某些数据,当原始页面加载完后,会再向服务器请求某个接口获取数据,然后数据才会经过处理从而呈现在网页上,这其实是发送了一个 Ajax 请求。

按照 Web 的发展趋势来看,这种形式的页面越来越多。甚至网页的原始 HTML 文档不会包含任何数据,数据都是通过 Ajax 统一加载后呈现出来的,这样使得 Web 开发可以做到前后端分离,减小服务器直接渲染页面带来的压力。

所以如果遇到这样的页面,直接利用requests等库来抓取原始 HTML文档,是无法获取有效数据的,这时需要分析网页后台向接口发送的 Aiax 请求。如果可以用 requests 模拟 Aiax 请求,就可以成功抓取页面数据了。

所以,本章我们的主要目的是了解什么是 Ajax,以及如何分析和抓取 Ajax 请求。

什么是Ajax

Ajax,全称为 Asynchronous JavaScript and XML,即异步的 JavaScript 和 XML。它不是一门编程语言,而是利用 JavaScript 在保证页面不被刷新、页面链接不改变的情况下与服务器交换数据并更新部分网页内容的技术。

对于传统的网页,如果想更新其内容,就必须刷新整个页面,但有了Aiax,可以在页面不被全部刷新的情况下更新。这个过程实际上是页面在后台与服务器进行了数据交互,获取数据之后,再利用JavaScript 改变网页,这样网页内容就会更新了。

可以到 W3School上体验几个实例感受一下:https://www.w3school.com.cn/js/js_ajax_http_send.asp

  1. 实例引入

浏览网页的时候,我们会发现很多网页都有“下滑查看更多”的选项。拿微博来说,可以登录https://m.weibo.cn/为例,一直下滑,可以发现下滑几条微博之后,再向下就没有了,转而会出现一个加载的动画,不一会儿下方就继续出现了新的微博内容,这个过程其实就是 Ajax 加载的过程,如下图所示。

在这里插入图片描述
能够看出,页面其实并没有整个刷新这意味着页面的链接没有变化,但是网页中却多了新内容,也就是后面刷出来的新微博。这就是通过 Ajax 获取新数据并呈现的过程。

  1. 基本原理

初步了解了 Ajax之后,我们接下来详细了解它的基本原理。从发送 Aiax 请求到网页更新的这个过程可以简单分为以下3步–发送请求、解析内容、渲染网页。下面分别详细介绍一下这几个过程。

  • 发送请求

我们知道JavaScript可以实现页面的各种交互功能,Ajax也不例外,它也是由JavaScript实现的,实现代码如下:

var xmlhttp;if(window.XMLHttpRequest){xmlhttp=new XMLHttpRequest();
}else{//code for IE6、 IE5xmlhttp=new ActiveXObject("Microsoft.XMLHTTP");
}
xmlhttp.onreadystatechange-function(){if(xmlhttp.readyState==4&&xmlhttp.status==200{document.getElementById("myDiv").innerHTML=xmlhttp.responseText;}
}
xmlhttp.open("POST","/ajax/",true);
xmlhttp.send();

这是 JavaScript 对 Ajax 最底层的实现,实际上就是先新建一个 XMLHttpRequest 对象 xmlhttp,然后调用 onreadvstatechange属性设置监听,最后调用 open和 send方法向某个链接(也就是服务器)发送请求。前面用 Python 实现请求发送之后,可以得到响应结果,但这里的请求发送由 JavaScript 完成。由于设置了监听,所以当服务器返回响应时,onreadystatechange 对应的方法便会被触发,然后在这个方法里面解析响应内容即可。

  • 解析内容

服务器返回响应之后,onreadystatechange 属性对应的方法就被触发了,此时利用 xmlhttp 的responseText属性便可得到响应内容。这类似于Python 中利用requests 向服务器发起请求,然后得到响应的过程。返回内容可能是 HTML,可能是 JSON,接下来只需要在方法中用 JavaScript 进一步处理即可。如果是 JSON 的话,可以进行解析和转化。

  • 渲染网页

JavaScript有改变网页内容的能力,因此解析完响应内容之后,就可以调用JavaScript 来基于解析完的内容对网页进行下一步处理了。例如,通过 document.getElementBvId().innerHTML操作,可以更改某个元素内的源代码,这样网页显示的内容就改变了。这种操作也被称作 DOM 操作,即对网页文档进行操作,如更改、删除等。

上面“发送请求”部分,代码里的 document.getElementById(“myDiv”).innerHTML=xmlhttp.responseText便是将 ID 为 myDiv 的节点内部的 HTML 代码更改为了服务器返回的内容,这样 myDiv 元素内部便会呈现服务器返回的新数据,对应的网页内容看上去就更新了。

我们观察到,网页更新的3个步骤其实都是由 JavaScript 完成的,它完成了整个请求、解析和渲染的过程。

再回想微博的下拉刷新,其实就是 JavaScript 向服务器发送了一个 Ajax 请求,然后获取新的微博数据,对其做解析,并渲染在网页中。

因此我们知道,真实的网页数据其实是一次次向服务器发送 Ajax 请求得到的,要想抓取这些数据,需要知道 Ajax 请求到底是怎么发送的、发往哪里、发了哪些参数。我们知道这些以后,不就可以用 Python 模拟发送操作,并获取返回数据了吗?

Ajax分析方法

这里还以之前的微博为例,我们知道下拉刷新的网页内容由 Aiax 加载而得,而且页面的链接没有发生变化,那么应该到哪里去查看这些Ajax请求呢?

  1. 分析案例
    此处还需要借助浏览器的开发者工具,下面以Chrome浏览器为例来介绍。

首先,用 Chrome 浏览器打开微博链接 https://m.weibo.cn可以登录自己的微博,然后在页面中单击鼠标右键,从弹出的快捷菜单中选择“检查”选项,此时便会弹出开发者工具,如下图所示。

在这里插入图片描述
前面也提到过,这里展示的就是页面加载过程中,浏览器与服务器之间发送请求和接收响应的所有记录。

事实上,Ajax有其特殊的请求类型,叫作xhr。在下图中,我们可以发现一个名称以 getindex 开头的请求,其 Type 就为 xhr,意味着这就是一个 Ajax 请求。用鼠标单击这个请求,可以查看其详细信息。
在这里插入图片描述

从上图的右侧可以观察这个 Ajax 请求的 Request Headers、URL和 Response Headers 等信息。其中 Request Headers 中有一个信息为 X-Requested-With:XMLHttpRequest,这就标记了此请求是 Ajax 请求,如下图所示。
在这里插入图片描述
随后单击一下 Preview,就能看到响应的内容,如下图所示。这些内容是 JSON 格式的,这里Chrome为我们自动做了解析,单击左侧箭头即可展开和收起相应内容。
在这里插入图片描述
JavaScript接收到这些数据之后,再执行相应的渲染方法,整个页面就渲染出来了。

另外,也可以切换到 Response 选项卡,从中观察真实的返回数据,如下图所示:
在这里插入图片描述
接下来,切回第一个请求,观察一下它的 Response 是什么,如下图所示。

在这里插入图片描述

这是最原始的链接返回的结果,其代码只有不到 50 行,结构也非常简单,只是执行了一些 JavaScript 语句。

所以说,微博页面呈现给我们的真实数据并不是最原始的页面返回的,而是执行JavaScript 后再次向后台发送 Ajax请求,浏览器拿到服务器返回的数据后进一步渲染得到的。

  1. 过滤请求

利用 Chrome 开发者工具的筛选功能能够筛选出所有 Ajax请求。在请求的上方有一层筛选栏,直接单击 XHR,之后下方显示的所有请求便都是 Ajax 请求了,如下图所示。

在这里插入图片描述
接下来,不断向上滑动微博页面,可以看到页面底部有一条条新的微博被刷出,开发者工具下方也出现了一个个新的 Ajax 请求,这样我们就可以捕获所有的 Ajax 请求了。

随意点开其中一个条目,都可以清楚地看到其Request URL、Request Headers、Response Headers、Response Body 等内容,此时想要模拟 Ajax 请求的发送和数据的提取就非常简单了。

下图展示的内容便是我的某一页微博的列表信息

在这里插入图片描述

到现在为止,我们已经可以得到 Aiax 请求的详细信息了,接下来只需要用程序模拟这些 Ajax 请求,就可以轻松提取我们所需的信息。

Ajax分析与爬虫实战

本节我们会结合一个实际的案例,来看一下 Ajax 分析和爬取页面的具体实现。

  1. 准备工作

开始分析之前,需要做好如下准备工作。

  • 安装好 Python 3(最低为 3.6 版本 ),并成功运行 Python 3 程序。
    -了解 Python HTTP 请求库 requests 的基本用法。
  • 了解 Ajax 基础知识和分析 Ajax 的基本方法。

以上内容在前面的博客中均有讲解,如尚未准备好,建议先熟悉一下这些内容。

  1. 爬取目标

本节我们以一个示例网站来试验一下 Ajax的爬取,其链接为:https://spa1.scrape.center/,该示例网站的数据请求是通过 Ajax完成的,页面的内容是通过JavaScript 渲染出来的,页面如下图所示。
在这里插入图片描述

此时我们需要爬取的数据,包括电影的名称、封面、类别、上映日期、评分剧情简介等信息。
本节我们需要完成的目标如下

  • 分析页面数据的加载逻辑。
  • 用 requests 实现 Ajax 数据的爬取。
  • 将每部电影的数据分别保存到 MongoDB 数据库。
    由于本节主要讲解 Ajax,所以数据存储和加速部分就不再展开详细实现了,主要是讲解 Ajax 分析和爬取的实现。
    好,现在就开始吧。
  1. 初步探索

我们先尝试用之前的 requests 直接提取页面,看看会得到怎样的结果。用最简单的代码实现一下requests 获取网站首页源码的过程,代码如下:

import requestsurl = 'https://spa1.scrape.center/'
html = requests.get(url).text
print(html)

运行结果如下:

<!DOCTYPE html><html lang=en><head><meta charset=utf-8><meta http-equiv=X-UA-Compatible 
content="IE=edge"><meta name=viewport content="width=device-width,initial-scale=1">
<link rel=icon href=/favicon.ico><title>Scrape | Movie</title><link href=/css/chunk-
700f70e1.1126d090.css rel=prefetch><link href=/css/chunk-d1db5eda.0ff76b36.cssrel=prefetch><link href=/js/chunk-700f70e1.0548e2b4.js rel=prefetch><linkhref=/js/chunk-d1db5eda.b564504d.js rel=prefetch><link href=/css/app.ea9d802a.cssrel=preload as=style><link href=/js/app.17b3aaa5.js rel=preload as=script><linkhref=/js/chunk-vendors.683ca77c.js rel=preload as=script><linkhref=/css/app.ea9d802a.css rel=stylesheet></head><body><noscript><strong>We'resorry but portal doesn't work properly without JavaScript enabled. Please enableit to continue.</strong></noscript><div id=app></div><script src=/js/chunk-vendors.683ca77c.js></script><script src=/js/app.17b3aaa5.js></script></body></html>

可以看到,爬取结果就只有这么一点HTML内容,而我们在浏览器中打开这个网站,却能看到如下图所示的页面。
在这里插入图片描述
在 HTML中,我们只能看到源码引用的一些JavaScript和CSS 文件,并没有观察到任何电影数据信息。

遇到这样的情况,说明我们看到的整个页面都是JavaScript渲染得到的,浏览器执行了HTML中引用的 JavaScript 文件,JavaScript 通过调用一些数据加载和页面渲染方法,才最终呈现了上图展示的结果。这些电影数据一般是通过 Aiax加载的,JavaScript在后台调用 Aiax数据接口,得到数据之后,再对数据进行解析并渲染呈现出来,得到最终的页面。所以要想爬取这个页面,直接爬取 Ajax 接口,再获取数据就好了

上面我们已经了解了 Ajax 分析的基本方法,下面一起分析一下 Ajax 接口的逻辑并实现数据爬取吧。

  1. 爬取列表页

首先分析列表页的 Ajax 接口逻辑,打开浏览器开发者工具,切换到Network面板,勾选 PreserveLog 并切换到 XHR 选项卡,如下图所示。
在这里插入图片描述

接着重新刷新页面,再单击第2页、第3页、第4页的按钮,这时可以观察到不仅页面上的数据发生了变化,开发者工具下方也监听到了几个 Ajax 请求,如下图所示。
在这里插入图片描述

我们切换了4页,每次翻页也出现了对应的 Aiax 请求。可以点击査看其请求详情,观察请求 URL、参数和响应内容是怎样的,如下图所示。

在这里插入图片描述
这里我点开了最后一个结果,观察到其Ajax接口的请求 URL为 https://spa1.scrape.center/api/movie?limit=10&ofset=40,这里有两个参数:一个是limit,这里是10;一个是 offset,这里是 40。

观察多个 Ajax 接口的参数,我们可以总结出这么一个规律:limit 一直为10,正好对应每页 10条数据;offset 在依次变大,页数每加1,offset 就加10,因此其代表页面的数据偏移量。例如第2页的 offset 为 10 就代表跳过 10 条数据,返回从 11 条数据开始的内容,再加上 limit 的限制,最终页面呈现的就是第 11条至第 20 条数据。

接着我们再观察一下响应内容,切换到Preview 选项卡,结果如下图所示。

在这里插入图片描述
可以看到,结果就是一些 JSON 数据,其中有一个 results 字段,是一个列表,列表中每一个元素都是一个字典。观察一下字典的内容,里面正好可以看到对应电影数据的字段,如 name、alias、cover、categories。对比一下浏览器页面中的真实数据,会发现各项内容完全一致,而且这些数据已经非常结构化了,完全就是我们想要爬取的数据,真的是得来全不费工夫。

这样的话,我们只需要构造出所有页面的 Ajax接口,就可以轻松获取所有列表页的数据了先定义一些准备工作,导人一些所需的库并定义一些配置,代码如下:

import requests
import logginglogging.basicConfig(level=logging.INFO, format='%(asctime)s-%(levelname)s:%(message)s')
INDEX_URl = 'https://spa1.scrape.center/api/movie/?limit={limit}&offset-{offset}'

这里我们引人了 requests 和 logging 库,并定义了 logging 的基本配置。接着定义了 INDEX URL,这里把 limit 和 offset 预留出来变成占位符,可以动态传人参数构造一个完整的列表页 URL。

下面我们实现一下详情页的爬取。还是和原来一样,我们先定义一个通用的爬取方法,其代码如下:

def scrape_api(url):logging.info('scraping %s...', url)try:response = requests.get(url)if response.status_code == 200:return response.json()logging.error('get invalid status code %s while scraping %s', response.status_code, url)except requests.RequestException:logging.error('error occurred while scraping %s', url, exc_info=True)

这里我们定义了一个 scrape api方法,和之前不同的是,这个方法专门用来处理 JSON接口。最后的 response 调用的是 json 方法,它可以解析响应内容并将其转化成 JSON 字符串。

接着在这个基础之上,定义一个爬取列表页的方法,其代码如下:

def scrape_index(page):url = INDEX_URL.format(limit=LIMIT, offset=LIMIT * (page - 1))return scrape_api(url)

这里我们定义了一个 scrape index方法,它接收一个参数 page,该参数代表列表页的页码。scrape_index方法中,先构造了一个url,通过字符串的 format方法,传入 limit 和 offset 的值。这里 limit 就直接使用了全局变量 LIMIT 的值;offset 则是动态计算的,计算方法是页码数减一再乘以 limit,例如第1页的 offset 就是0,第2页的 offset 就是 10,以此类推。构造好 url后,直接调用 scrape_api 方法并返回结果即可。

这样我们就完成了列表页的爬取,每次发送 Ajax请求都会得到 10部电影的数据信息。

由于这时爬取到的数据已经是 JSON 类型了,所以无须像之前那样去解析 HTML 代码来提取数爬到的数据已经是我们想要的结构化数据,因此解析这一步可以直接省略啦。

到此为止,我们能成功爬取列表页并提取电影列表信息了。

  1. 爬取详情页

虽然我们已经可以拿到每一页的电影数据,但是这些数据实际上还缺少一些我们想要的信息,如剧情简介等信息,所以需要进一步进入详情页来获取这些内容。

单击任意一部电影,如《教父》,进入其详情页,可以发现此时的页面 URL已经变成了 https://spa1scrape.center/detail/40,页面也成功展示了《教父》详情页的信息,如下图所示。
在这里插入图片描述
另外,我们也可以观察到开发者工具中又出现了一个 Ajax请求,其 URL为 https://spa1.scrape.
center/api/movie/40/,通过 Preview 选项卡也能看到 Ajax 请求对应的响应信息,如下图所示。
在这里插入图片描述
稍加观察就可以发现,Ajax 请求的 URL后面有一个参数是可变的,这个参数是电影的id,这里是 40,对应《教父》这部电影。

如果我们想要获取 id为 50的电影,只需要把 URL最后的参数改成 50 即可,即 https://spa1.scrape.
center/api/movie/50/,请求这个新的 URL便能获取 id 为 50 的电影对应的数据了。

同样,响应结果也是结构化的JSON 数据,其字段也非常规整,我们直接爬取即可。

现在,详情页的数据提取逻辑分析完了,怎么和列表页关联起来呢?电影 id从哪里来呢?我们回过头看看列表页的接口返回数据,如下图所示。

在这里插入图片描述
可以看到,列表页原本的返回数据中就带有id这个字段,所以只需要拿列表页结果中的 id 来构造详情页的 Aiax 请求的 URL 就好了。

接着,我们就先定义一个详情页的爬取逻辑,代码如下:

DETAIL_URL = 'https://spa1.scrape.center/api/movie/{id}'def scrape_detail(id):url = DETAIL_URL.format(id=id)return scrape_api(url)

这里定义了一个 scrape_detail方法,它接收一个参数 id。这里的实现也非常简单,先根据定义好的 DETAIL_URL 加 id 构造一个真实的详情页 Ajax 请求的 URL,再直接调用 scrape_api 方法传人这个 url即可。

最后,我们定义一个总的调用方法,对以上方法串联调用,代码如下:

def main():for page in range(1, TOTAL_PAGE + 1):index_data = scrape_index(page)for item in index_data.get('results'):id = item.get('id')detail_data = scrape_detail(id)logging.info('detail data %s', detail_data)if __name__ == '__main__':main()

我们定义了一个 main 方法,该方法首先遍历获取页码 page,然后把 page 当作参数传递给scrape_index方法,得到列表页的数据。接着遍历每个列表页的每个结果,获取每部电影的 id。之后把 id 当作参数传递给 scrape_detail方法来爬取每部电影的详情数据,并将此数据赋值为detail_data,最后输出 detail_data 即可。

运行结果如下:
在这里插入图片描述
由于内容较多,这里省略了部分内容。

可以看到,整个爬取工作已经完成了,这里会依次爬取每一个列表页的 Ajax 接口,然后依次爬取每部电影的详情页 Ajax 接口,并打印出每部电影的 Ajax 接口响应数据,而且都是 JSON 格式。至此,所有电影的详情数据,我们都爬取到啦。

全部代码

import requests
import logginglogging.basicConfig(level=logging.INFO, format='%(asctime)s-%(levelname)s:%(message)s')
INDEX_URL = 'https://spa1.scrape.center/api/movie/?limit={limit}&offset-{offset}'def scrape_api(url):logging.info('scraping %s...', url)try:response = requests.get(url)if response.status_code == 200:return response.json()logging.error('get invalid status code %s while scraping %s', response.status_code, url)except requests.RequestException:logging.error('error occurred while scraping %s', url, exc_info=True)LIMIT = 10def scrape_index(page):url = INDEX_URL.format(limit=LIMIT, offset=LIMIT * (page - 1))return scrape_api(url)DETAIL_URL = 'https://spa1.scrape.center/api/movie/{id}'def scrape_detail(id):url = DETAIL_URL.format(id=id)return scrape_api(url)TOTAL_PAGE = 10def main():for page in range(1, TOTAL_PAGE + 1):index_data = scrape_index(page)for item in index_data.get('results'):id = item.get('id')detail_data = scrape_detail(id)logging.info('detail data %s', detail_data)if __name__ == '__main__':main()

相关文章:

Ajax数据爬取

有时我们用requests 抓取页面得到的结果&#xff0c;可能和在浏览器中看到的不一样:在浏览器中可以看到正常显示的页面数据&#xff0c;而使用requests 得到的结果中并没有这些数据。这是因为 requests 获取的都是原始 HTML 文档&#xff0c;而浏览器中的页面是JavaScript 处理…...

快速上手大模型的对话生成

本项目使用0.5B小模型&#xff0c;结构和大模型别无二致&#xff0c;以方便在如CPU设备上快速学习和上手大模型的对话上传 #mermaid-svg-Z86hUiQZ0hg9BVji {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-Z86hUiQZ0h…...

DateTimeExtensions:一个轻量C#的开源DateTime扩展方法库

推荐一个专门为System.DateTime编写的扩展方法库。 01 项目简介 该项目主要是为System.DateTime和System.DateTimeOffset的编写的扩展方法&#xff0c;包括自然日期差值的文本表示&#xff08;精确和人性化四舍五入&#xff09;、多个时区的节假日和工作日计算。 核心扩展方…...

题解:监控屏幕调整问题

问题描述 Reca 公司生产高端显示器&#xff0c;其中最受欢迎的型号是 AB999。屏幕尺寸为 $x \times y$ 的比例。由于某些生产特性&#xff0c;屏幕参数总是整数。最终&#xff0c;屏幕边长比例 $x:y$ 需要适应用户的需求。 为了满足用户需求&#xff0c;公司需要调整屏幕尺寸…...

C语言----指针

目录 1.概念 2.格式 3.指针操作符 4.初始化 1. 将普通变量的地址赋值给指针变量 a. 将数组的首地址赋值给指针变量 b. 将指针变量里面保存的地址赋值给另一个指针变量 5.指针运算 5.1算术运算 5.2 关系运算 指针的大小 总结&#xff1a; 段错误 指针修饰 1. con…...

树莓派之旅-在wsl-x86-64 上进行树莓派的交叉编译

前情提要&#xff1a; 想把自己花里胡哨的终端丢到树莓派上去&#xff0c;可是树莓派算力不够&#xff0c;编译时间过于漫长 交叉编译 定义网上有&#xff0c;懒得复制了&#xff0c;大概就是在本机电脑上编译目标平台的可执行文件 这里的目标平台是树莓派 使用 uname -m …...

nature reviews genetics | 需要更多的针对不同种族的癌症基因组图谱研究,促进精准治疗和维护治疗公平权益

–https://doi.org/10.1038/s41576-024-00796-w Genomic landscape of cancer in racially and ethnically diverse populations 研究团队和单位 Ulrike Peters–Public Health Sciences Division, Fred Hutchinson Cancer Center Claire E. Thomas–Public Health Scienc…...

代码随想录算法训练营day18

代码随想录算法训练营 —day18 文章目录 代码随想录算法训练营前言一、530.二叉搜索树的最小绝对差递归法迭代法 二、501.二叉搜索树中的众数普通二叉树的方法递归法中序迭代法 三、 236. 二叉树的最近公共祖先递归法 总结 前言 今天是算法营的第18天&#xff0c;希望自己能够…...

Kafka安全优化文档:漏洞修复到安全加固

文章目录 1.1.漏洞修复1.1.1.Apache Kafka反序列化漏洞1.1.2.pm2-kafka代码执行漏洞1.1.3.Apache Kafka安全绕过漏洞1.1.4.Apache Kafka Distribution - Schema Repository跨站请求伪造漏洞1.1.5.Apache Kafka输入验证错误漏洞的补丁1.1.6.Apache Kafka信息泄露漏洞1.1.7.Apach…...

Markdown如何添加任务列表-复选框的添加

Markdown如何添加任务列表-复选框的添加 前言语法讲解使用场景及应用实例代码整和渲染结果小结其他文章快来试试吧☺️ Markdown如何添加任务列表-复选框的添加&#x1f448;点击这里也可查看 前言 To-do任务列表是一种很常见的时间管理工具&#xff0c;它适用于工作计划&…...

基于下垂控制的构网变换器功率控制【微电网变流器】【Simulink】

目录 主要内容 理论研究 整体模型 PQ计算模块 功率控制模块 PWM反馈模块 结果一览 下载链接 主要内容 该仿真针对微电网中分布式电源接入后产生的谐波影响&#xff0c;除了污染网络外&#xff0c;还会恶化微电网变流器输出电流&#xff0c;为了消除谐波影响&a…...

AI定义汽车/跨域融合/整车智能,汽车智能化2.0时代新机会来了

汽车智能化2.0&#xff0c;产业正在发生深度变革。 一方面&#xff0c;AI大模型开始在多个域同步赋能智能汽车&#xff0c;从智能座舱到智能驾驶&#xff0c;再到底盘域&#xff0c;AI大模型正在快速推动汽车变革为超级智能体&#xff0c;AI定义汽车时代开始来临。 另一方面&…...

(leetcode算法题)10. 正则表达式匹配

10. 正则表达式匹配 - 力扣&#xff08;LeetCode&#xff09; 此题的要求一个字符串 s 和一个字符规律 p之间支持 . 和 * 的正则表达式匹配 . 匹配任意单个字符 * 匹配零个或多个前面的那一个元素 所谓匹配&#xff0c;是要涵盖 整个 字符串 s 的&#xff0c;而不是部分字符串…...

SpringCloudAlibaba实战入门之Sentinel服务降级和服务熔断(十五)

一、Sentinel概述 1、Sentinel是什么 随着微服务的流行,服务和服务之间的稳定性变得越来越重要。Sentinel 以流量为切入点,从流量控制、熔断降级、系统负载保护等多个维度保护服务的稳定性。 一句话概括:sentinel即Hystrix的替代品,官网: https://sentinelguard.io/zh…...

使用爬虫技术获取网页中的半结构化数据

目录 前言1. 半结构化数据与爬虫技术简介1.1 半结构化数据的定义与特性1.2 爬虫技术的基本原理 2. 爬取半结构化数据的实现过程2.1 明确目标与准备2.2 发送HTTP请求2.3 解析网页内容2.4 动态内容的处理2.5 数据存储与清洗 3. 技术挑战与应对策略3.1 处理反爬机制3.2 提高爬取效…...

2025/1/1 路由期末复习作业二

呼呼呼祝大家元旦节快乐啦&#xff01;&#xff08;我顶着我超重的黑眼圈说&#xff09; 昨天一个人在寝室一边吃泡面&#xff0c;一边看步步惊心&#xff0c;一边吃一边哭呜呜呜呜呜若曦为什么不和八爷在一起好好爱&#xff0c;就因为他不当皇帝蛮&#xff01;难测最是帝王心…...

OpenCV-Python实战(13)——图像轮廓

一、找轮廓 cv2.findContours() contours,hierarchy cv2.findContours(image*,mode*,method*) contours&#xff1a;找到的所有轮廓数组&#xff0c;数组内的元素为轮廓像素点坐标。 hierarchy&#xff1a;轮廓间的层次关系。 image&#xff1a;二值图像&#xff08;cv2.t…...

javascript变量

变量 命名规范 以 字母、数字、下划线、美元符号 $ 组成、不能以 数字开头、且不能使用 js 中的关键字。 命名规范推荐采用小驼峰 命名法 。类名 采用 大驼峰命名。 var 声明变量的特点 在 script 上下文中定义的是 全局变量&#xff0c;全局变量会自动称为 window的属性。 在…...

在K8S中,如何查看kubelet组件的日志?

在kubernetes中&#xff0c;查看Kubelet组件的日志可以通过几种不同的方法。以下是详细的步骤&#xff1a; 1. 使用journalctl命令&#xff1a; 如果kubelet是通过systemd方式部署&#xff0c;你可以使用journalctl命令来查看其日志。执行journalctl -u kubelet将显示Kubelet…...

android studio android sdk下载地址

android studio安装后&#xff0c;因为公司网络原因&#xff0c;一直无法安装android sdk 后经过手机网络&#xff0c;安装android sdk成功如下&#xff0c;也可以手动下载后指定android sdk本地目录 https://dl.google.com/android/repository/source-35_r01.zip https://dl…...

Fetch处理大模型流式数据请求与解析

为什么有的大模型可以一次返回多个 data&#xff1f; Server-Sent Events (SSE)&#xff1a;允许服务器连续发送多个 data: 行&#xff0c;每个代表一个独立的数据块。 流式响应&#xff1a;大模型服务通常以流式响应方式返回数据&#xff0c;提高响应速度。 批量处理&#x…...

FPGA自学之路:到底有多崎岖?

FPGA&#xff0c;即现场可编程门阵列&#xff0c;被誉为硬件世界的“瑞士军刀”&#xff0c;其灵活性和可编程性让无数开发者为之倾倒。但谈及FPGA的学习难度&#xff0c;不少人望而却步。那么&#xff0c;FPGA自学之路到底有多崎岖呢&#xff1f; 几座大山那么高&#xff1f;…...

从0到机器视觉工程师(二):封装调用静态库和动态库

目录 静态库 编写静态库 使用静态库 方案一 方案二 动态库 编写动态库 使用动态库 方案一 方案二 方案三 总结 静态库 静态库是在编译时将库的代码合并到最终可执行程序中的库。静态库的优势是在编译时将所有代码包含在程序中&#xff0c;可以使程序独立运行&…...

[极客大挑战 2019]Knife1

这里很显然&#xff0c;根据提示可以猜测&#xff0c;已经有一句话木马上传了&#xff0c;但是路径这里不是很清楚&#xff0c;不知道路径在哪里&#xff0c;不过还是用菜刀连一下试试&#xff1a; 连接成功&#xff0c;在根目录下发现flag。不过如果不用菜刀&#xff0c;可以用…...

【在Python中生成随机字符串】

在Python中生成随机字符串&#xff0c;你可以结合使用random模块和字符串操作。以下是一个常用的方法&#xff0c;通过从预定义的字符集中随机选择字符来构建字符串&#xff1a; import random import stringdef generate_random_string(length):# 定义字符集&#xff1a;可以…...

【three.js】场景搭建

three.js由场景、相机、渲染器、灯光、控制器等几个要素组成。每个要素都有不同的类型&#xff0c;例如光照有太阳光、环境光、半球光等等。每种光照都有不同的属性可以进行配置。 场景 场景&#xff08;scene&#xff09;&#xff1a;场景是所有物体的容器&#xff0c;如果要…...

Singleton: WebRTC中ThreadManager中的单例模式

1. 什么是单例模式&#xff1a; 旨在确保一个类只有一个实例&#xff0c;并提供全局访问点。 应用场景&#xff1a;需要一个全局唯一的实例&#xff0c;避免资源浪费。 2. 单例模式的实现&#xff1a; Lazy Initialization&#xff08;懒汉式&#xff09;&#xff08;延迟初…...

MySQL数据库笔记——多版本并发控制MVCC

大家好&#xff0c;这里是Good Note&#xff0c;关注 公主号&#xff1a;Goodnote&#xff0c;本文详细介绍MySQL的并发控制&#xff1a;多版本并发控制MVCC。 文章目录 背景介绍数据库并发控制——锁机制悲观锁和乐观锁悲观锁乐观锁 数据库并发控制——MVCC 的引入MVCC 和锁机…...

【0x0037】HCI_Write_Link_Supervision_Timeout命令详解

目录 一、命令概述 二、命令格式及参数说明 2.1. HCI_Write_Link_Supervision_Timeout 命令格式 2.2. Handle 2.3. Link_Supervision_Timeout 三、生成事件及参数 3.1. HCI_Command_Complete 事件 3.2. Status 3.3. Handle 四、命令执行流程 4.1. 命令准备阶段 4.…...

Linux下如何进行内存泄漏分析

前言 正文 一、环境的安装 1、tar –xf valgrind-3.17.0.tar.bz2 2、cd valgrind-3.17.0 3、./configure // 运行配置脚本生成makefile文件&#xff0c;可以--help查看配置项&#xff0c;自行按需配置&#xff0c;比如修改编译工具、修改安装路径等 4、make 5、make…...