如何使用Scrapy和Python 3爬取网页

简介

网络爬虫,通常称为网络爬行或网络蜘蛛,是以编程方式浏览一系列网页并提取数据的行为,是处理网络数据的强大工具。

通过使用网络爬虫,您可以挖掘有关一组产品的数据,获取大量文本或定量数据以进行分析,从没有官方 API 的网站检索数据,或者只是满足您自己的个人好奇心。

在本教程中,您将学习有关爬取和蜘蛛过程的基础知识,同时探索一个有趣的数据集。我们将使用Quotes to Scrape,这是一个托管在专门用于测试网络蜘蛛的网站上的引用数据库。通过本教程结束时,您将拥有一个完全功能的 Python 网络爬虫,它可以浏览包含引用的一系列页面,并在屏幕上显示它们。

该爬虫将很容易扩展,因此您可以对其进行调整,并将其用作从网络上爬取数据的自己项目的基础。

先决条件

要完成本教程,您需要一个用于 Python 3 的本地开发环境。您可以按照《如何安装和设置 Python 3 的本地编程环境》中的说明配置所需的一切。

步骤 1 —— 创建基本爬虫

爬取是一个两步过程:

  1. 系统地查找并下载网页。
  2. 从下载的页面中提取信息。

这两个步骤可以用许多语言的许多方式来实现。

您可以使用编程语言提供的模块或库从头开始构建一个爬虫,但随着爬虫变得更加复杂,您可能会遇到一些潜在的问题。例如,您需要处理并发性,以便可以同时爬取多个页面。您可能希望找出如何将爬取的数据转换为不同的格式,如 CSV、XML 或 JSON。有时您还必须处理需要特定设置和访问模式的网站。

如果您构建的爬虫基于一个已存在的库,该库可以为您处理这些问题,那么您将会更加顺利。在本教程中,我们将使用 Python 和 Scrapy 来构建我们的爬虫。

Scrapy 是最流行和强大的 Python 爬取库之一;它采用“电池包含”方法来进行爬取,这意味着它处理了所有爬虫都需要的常见功能,因此开发人员不必每次都重新发明轮子。

Scrapy,像大多数 Python 包一样,位于 PyPI(也称为 pip)上。PyPI 是所有已发布的 Python 软件的社区拥有的存储库。

如果您的 Python 安装与本教程的先决条件中概述的一样,那么您的机器上已经安装了 pip,因此您可以使用以下命令安装 Scrapy:

pip install scrapy

如果您在安装过程中遇到任何问题,或者您想要在不使用 pip 的情况下安装 Scrapy,请查看官方安装文档。

安装了 Scrapy 后,为我们的项目创建一个新文件夹。您可以在终端中运行以下命令来执行此操作:

mkdir quote-scraper

现在,进入您刚刚创建的新目录:

cd quote-scraper

然后创建一个名为 scraper.py 的新 Python 文件,用于我们的爬虫。在本教程中,我们将把所有代码放在这个文件中。您可以使用您选择的编辑软件创建此文件。

通过创建一个以 Scrapy 为基础的非常基本的爬虫来开始项目。为此,您需要创建一个 Python 类,它是 scrapy.Spider 的子类,这是 Scrapy 提供的一个基本蜘蛛类。该类将具有两个必需的属性:

  • name —— 蜘蛛的名称。
  • start_urls —— 从中开始爬取的 URL 列表。我们将从一个 URL 开始。

在您的文本编辑器中打开 scrapy.py 文件,并添加以下代码以创建基本蜘蛛:

import scrapy


class QuoteSpider(scrapy.Spider):
    name = 'quote-spdier'
    start_urls = ['https://quotes.toscrape.com']

让我们逐行分解这段代码:

首先,我们导入 scrapy,以便可以使用该软件包提供的类。

接下来,我们使用 Scrapy 提供的 Spider 类,并将其作为 BrickSetSpider子类。将子类视为其父类的更专业化形式。Spider 类具有定义如何跟踪 URL 并从找到的页面中提取数据的方法和行为,但它不知道要查找的位置或要查找的数据。通过对其进行子类化,我们可以提供这些信息。

最后,我们将类命名为 quote-spider,并为我们的爬虫指定一个起始 URL:https://quotes.toscrape.com。如果您在浏览器中打开该 URL,它将带您到一个搜索结果页面,显示许多著名引语的第一页。

现在,测试一下爬虫。通常,Python 文件是通过类似 python path/to/file.py 的命令运行的。但是,Scrapy 配备了自己的命令行界面,以简化启动爬虫的过程。使用以下命令启动您的爬虫:

scrapy runspider scraper.py

该命令将输出类似以下内容:

2022-12-02 10:30:08 [scrapy.utils.log] DEBUG: Using reactor: twisted.internet.epollreactor.EPollReactor
2022-12-02 10:30:08 [scrapy.extensions.telnet] INFO: Telnet Password: b4d94e3a8d22ede1
2022-12-02 10:30:08 [scrapy.middleware] INFO: Enabled extensions:
['scrapy.extensions.corestats.CoreStats',
 ...
 'scrapy.extensions.logstats.LogStats']
2022-12-02 10:30:08 [scrapy.middleware] INFO: Enabled downloader middlewares:
['scrapy.downloadermiddlewares.httpauth.HttpAuthMiddleware',
 ...
 'scrapy.downloadermiddlewares.stats.DownloaderStats']
2022-12-02 10:30:08 [scrapy.middleware] INFO: Enabled spider middlewares:
['scrapy.spidermiddlewares.httperror.HttpErrorMiddleware',
 ...
 'scrapy.spidermiddlewares.depth.DepthMiddleware']
2022-12-02 10:30:08 [scrapy.middleware] INFO: Enabled item pipelines:
[]
2022-12-02 10:30:08 [scrapy.core.engine] INFO: Spider opened
2022-12-02 10:30:08 [scrapy.extensions.logstats] INFO: Crawled 0 pages (at 0 pages/min), scraped 0 items (at 0 items/min)
2022-12-02 10:30:08 [scrapy.extensions.telnet] INFO: Telnet console listening on 127.0.0.1:6023
2022-12-02 10:49:32 [scrapy.core.engine] DEBUG: Crawled (200) <GET https://quotes.toscrape.com> (referer: None)
2022-12-02 10:30:08 [scrapy.core.engine] INFO: Closing spider (finished)
2022-12-02 10:30:08 [scrapy.statscollectors] INFO: Dumping Scrapy stats:
{'downloader/request_bytes': 226,
 ...
 'start_time': datetime.datetime(2022, 12, 2, 18, 30, 8, 492403)}
2022-12-02 10:30:08 [scrapy.core.engine] INFO: Spider closed (finished)

这是大量的输出,让我们逐一解释一下。

  • 爬虫初始化并加载了所需的其他组件和扩展,以处理从 URL 读取数据。
  • 它使用我们在 start_urls 列表中提供的 URL,并获取了 HTML,就像您的网络浏览器一样。
  • 它将该 HTML 传递给 parse 方法,该方法默认情况下不执行任何操作。由于我们从未编写过自己的 parse 方法,因此蜘蛛在不执行任何工作的情况下就完成了。

现在让我们从页面中提取一些数据。

第二步 — 从页面中提取数据

我们已经创建了一个非常基本的程序,用于下载页面,但它还没有进行任何爬取或蜘蛛行为。让我们给它一些要提取的数据。

如果你查看我们要爬取的页面,你会发现它具有以下结构:

  • 每个页面都有一个标题。
  • 有一个登录链接。
  • 然后是引语本身,显示在一个类似表格或有序列表的结构中。每个引语都有类似的格式。

在编写爬虫时,你需要查看 HTML 文件的源代码,并熟悉其结构。以下是源代码,为了可读性,已删除了与我们目标无关的标签:

[secondary_label quotes.toscrape.com]
<body>
...
    <div class="quote" itemscope itemtype="http://schema.org/CreativeWork">
        <span class="text" itemprop="text">“I have not failed. I&#39;ve just found 10,000 ways that won&#39;t work.”</span>
        <span>by <small class="author" itemprop="author">Thomas A. Edison</small>
        <a href="/author/Thomas-A-Edison">(about)</a>
        </span>
        <div class="tags">
            Tags:
            <meta class="keywords" itemprop="keywords" content="edison,failure,inspirational,paraphrased" /    > 
            
            <a class="tag" href="/tag/edison/page/1/">edison</a>
            
            <a class="tag" href="/tag/failure/page/1/">failure</a>
            
            <a class="tag" href="/tag/inspirational/page/1/">inspirational</a>
            
            <a class="tag" href="/tag/paraphrased/page/1/">paraphrased</a>
            
        </div>
    </div>
...    
</body>

爬取这个页面是一个两步过程:

  1. 首先,通过查找页面上具有我们想要的数据的部分来获取每个引语。
  2. 然后,对于每个引语,通过从 HTML 标签中提取数据来获取我们想要的数据。

scrapy 根据你提供的 选择器 来获取数据。选择器是我们可以使用的模式,以便找到页面上的一个或多个元素,以便我们可以处理元素内的数据。scrapy 支持 CSS 选择器或 XPath 选择器。

我们现在将使用 CSS 选择器,因为 CSS 完美适用于查找页面上的所有集合。如果你查看 HTML,你会发现每个引语都是用类 quote 指定的。由于我们正在寻找一个类,我们将使用 .quote 作为我们的 CSS 选择器。选择器的 . 部分搜索元素上的 class 属性。我们只需在我们的类中创建一个名为 parse 的新方法,并将该选择器传递到 response 对象中,如下所示:

class QuoteSpider(scrapy.Spider):
    name = 'quote-spdier'
    start_urls = ['https://quotes.toscrape.com']

    def parse(self, response):
        QUOTE_SELECTOR = '.quote'
        TEXT_SELECTOR = '.text::text'
        AUTHOR_SELECTOR = '.author::text'
        
        for quote in response.css(QUOTE_SELECTOR):
            pass

这段代码获取页面上的所有集合,并循环遍历它们以提取数据。现在让我们提取这些引语的数据,以便我们可以显示它。

再次查看我们要解析的页面的源代码,告诉我们每个引语的文本存储在具有 text 类的 span 中,引语的作者存储在具有 author 类的 <small> 标签中:

[secondary_label quotes.toscrape.com]
        ...
        <span class="text" itemprop="text">“I have not failed. I&#39;ve just found 10,000 ways that won&#39;t work.”</span>
        <span>by <small class="author" itemprop="author">Thomas A. Edison</small>
        ...

我们正在循环遍历的 quote 对象有其自己的 css 方法,因此我们可以传入一个选择器来定位子元素。修改你的代码如下,以查找集合的名称并显示它:

class QuoteSpider(scrapy.Spider):
    name = 'quote-spdier'
    start_urls = ['https://quotes.toscrape.com']

    def parse(self, response):
        QUOTE_SELECTOR = '.quote'
        TEXT_SELECTOR = '.text::text'
        AUTHOR_SELECTOR = '.author::text'
        
        for quote in response.css(QUOTE_SELECTOR):
            yield {
                'text': quote.css(TEXT_SELECTOR).extract_first(),
                'author': quote.css(AUTHOR_SELECTOR).extract_first(),
            }

在这段代码中,你会注意到两件事情:

  • 我们在引语和作者的选择器后附加了 ::text。这是一个 CSS 伪选择器,它获取标签内的文本,而不是标签本身。
  • 我们对 quote.css(TEXT_SELECTOR) 返回的对象调用了 extract_first(),因为我们只想要匹配选择器的第一个元素。这给我们一个字符串,而不是元素的列表。

保存文件并再次运行爬虫:

scrapy runspider scraper.py

这次输出将包含引语及其作者:

...
2022-12-02 11:00:53 [scrapy.core.scraper] DEBUG: Scraped from <200 https://quotes.toscrape.com>
{'text': '“There are only two ways to live your life. One is as though nothing is a miracle. The other is as though everything is a miracle.”', 'author': 'Albert Einstein'}
2022-12-02 11:00:53 [scrapy.core.scraper] DEBUG: Scraped from <200 https://quotes.toscrape.com>
{'text': '“The person, be it gentleman or lady, who has not pleasure in a good novel, must be intolerably stupid.”', 'author': 'Jane Austen'}
2022-12-02 11:00:53 [scrapy.core.scraper] DEBUG: Scraped from <200 https://quotes.toscrape.com>
{'text': "“Imperfection is beauty, madness is genius and it's better to be absolutely ridiculous than absolutely boring.”", 'author': 'Marilyn Monroe'}
...

让我们继续扩展这个功能,通过添加新的选择器来获取关于作者的页面链接和引语标签的链接。通过调查每个引语的 HTML,我们发现:

  • 存储作者 about 页面的链接是在其名称后面紧跟的一个链接中。
  • 标签存储为一组 a 标签,每个都有 tag 类,存储在具有 tags 类的 div 元素内。

因此,让我们修改爬虫以获取这些新信息:

class QuoteSpider(scrapy.Spider):
    name = 'quote-spdier'
    start_urls = ['https://quotes.toscrape.com']

    def parse(self, response):
        QUOTE_SELECTOR = '.quote'
        TEXT_SELECTOR = '.text::text'
        AUTHOR_SELECTOR = '.author::text'
        ABOUT_SELECTOR = '.author + a::attr("href")'
        TAGS_SELECTOR = '.tags > .tag::text'

        for quote in response.css(QUOTE_SELECTOR):
            yield {
                'text': quote.css(TEXT_SELECTOR).extract_first(),
                'author': quote.css(AUTHOR_SELECTOR).extract_first(),
                'about': 'https://quotes.toscrape.com' + 
                        quote.css(ABOUT_SELECTOR).extract_first(),
                'tags': quote.css(TAGS_SELECTOR).extract(),
            }

保存你的更改并再次运行爬虫:

scrapy runspider scraper.py

现在输出将包含新的数据:

2022-12-02 11:14:28 [scrapy.core.scraper] DEBUG: Scraped from <200 https://quotes.toscrape.com>
{'text': '“There are only two ways to live your life. One is as though nothing is a miracle. The other is as though everything is a miracle.”', 'author': 'Albert Einstein', 'about': 'https://quotes.toscrape.com/author/Albert-Einstein', 'tags': ['inspirational', 'life', 'live', 'miracle', 'miracles']}
2022-12-02 11:14:28 [scrapy.core.scraper] DEBUG: Scraped from <200 https://quotes.toscrape.com>
{'text': '“The person, be it gentleman or lady, who has not pleasure in a good novel, must be intolerably stupid.”', 'author': 'Jane Austen', 'about': 'https://quotes.toscrape.com/author/Jane-Austen', 'tags': ['aliteracy', 'books', 'classic', 'humor']}
2022-12-02 11:14:28 [scrapy.core.scraper] DEBUG: Scraped from <200 https://quotes.toscrape.com>
{'text': "“Imperfection is beauty, madness is genius and it's better to be absolutely ridiculous than absolutely boring.”", 'author': 'Marilyn Monroe', 'about': 'https://quotes.toscrape.com/author/Marilyn-Monroe', 'tags': ['be-yourself', 'inspirational']}

现在让我们将这个爬虫转变为一个可以跟踪链接的蜘蛛。

步骤 3 —— 爬取多个页面

你已经成功地从初始页面提取了数据,但我们并没有继续查看其余的结果。爬虫的整个目的是检测和遍历到其他页面的链接,并从这些页面中获取数据。

你会注意到每个页面的顶部和底部都有一个小右尖括号(>),它链接到下一页的结果。以下是该部分的 HTML 代码:

[secondary_label quotes.toscrape.com]
...
    <nav>
        <ul class="pager">
            
            
            <li class="next">
                <a href="/page/2/">Next <span aria-hidden="true">&rarr;</span></a>
            </li>
            
        </ul>
    </nav>
...

在源代码中,你会找到一个带有 next 类的 li 标签,以及在该标签内部的一个指向下一页的 a 标签。我们所要做的就是告诉爬虫,如果存在下一页,就跟随该链接。

按照以下方式修改你的代码:

class QuoteSpider(scrapy.Spider):
    name = 'quote-spdier'
    start_urls = ['https://quotes.toscrape.com']

    def parse(self, response):
        QUOTE_SELECTOR = '.quote'
        TEXT_SELECTOR = '.text::text'
        AUTHOR_SELECTOR = '.author::text'
        ABOUT_SELECTOR = '.author + a::attr("href")'
        TAGS_SELECTOR = '.tags > .tag::text'
        NEXT_SELECTOR = '.next a::attr("href")'

        for quote in response.css(QUOTE_SELECTOR):
            yield {
                'text': quote.css(TEXT_SELECTOR).extract_first(),
                'author': quote.css(AUTHOR_SELECTOR).extract_first(),
                'about': 'https://quotes.toscrape.com' + 
                        quote.css(ABOUT_SELECTOR).extract_first(),
                'tags': quote.css(TAGS_SELECTOR).extract(),
            }

        next_page = response.css(NEXT_SELECTOR).extract_first()
        if next_page:
            yield scrapy.Request(response.urljoin(next_page))

首先,我们定义了一个用于“下一页”链接的选择器,提取第一个匹配项,并检查其是否存在。scrapy.Request 是一个新的请求对象,Scrapy 知道这意味着它应该获取并解析下一页。

这意味着一旦我们转到下一页,我们将在那一页上寻找下一页的链接,在该页面上我们将寻找下一页的链接,依此类推,直到我们找不到下一页的链接为止。这是网页抓取的关键部分:查找和跟随链接。在这个例子中,它非常线性;一个页面有一个链接到下一页,直到我们到达最后一页。但你也可以跟随标签、或其他搜索结果的链接,或者任何你想要的 URL。

现在,如果你保存你的代码并再次运行爬虫,你会发现它不仅仅在迭代完第一页的结果后停止。它会继续遍历所有 10 页上的 100 条引语。在整个过程中,这并不是一个巨大的数据块,但现在你知道了自动查找新页面进行抓取的过程。

以下是本教程的完整代码:

import scrapy


class QuoteSpider(scrapy.Spider):
    name = 'quote-spdier'
    start_urls = ['https://quotes.toscrape.com']

    def parse(self, response):
        QUOTE_SELECTOR = '.quote'
        TEXT_SELECTOR = '.text::text'
        AUTHOR_SELECTOR = '.author::text'
        ABOUT_SELECTOR = '.author + a::attr("href")'
        TAGS_SELECTOR = '.tags > .tag::text'
        NEXT_SELECTOR = '.next a::attr("href")'

        for quote in response.css(QUOTE_SELECTOR):
            yield {
                'text': quote.css(TEXT_SELECTOR).extract_first(),
                'author': quote.css(AUTHOR_SELECTOR).extract_first(),
                'about': 'https://quotes.toscrape.com' + 
                        quote.css(ABOUT_SELECTOR).extract_first(),
                'tags': quote.css(TAGS_SELECTOR).extract(),
            }

        next_page = response.css(NEXT_SELECTOR).extract_first()
        if next_page:
            yield scrapy.Request(
                response.urljoin(next_page),
            )

结论

在本教程中,你构建了一个完全功能的爬虫,可以在不到三十行的代码中从网页中提取数据。这是一个很好的开始,但你可以用这个爬虫做很多有趣的事情。这应该足够让你思考和实验。如果你需要更多关于 Scrapy 的信息,请查看 Scrapy 的官方文档。关于从网页中提取数据的更多信息,请参阅我们的“如何使用 Beautiful Soup 和 Python 3 抓取网页”的教程。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Springboot+Vue项目-基于Java+MySQL的入校申报审批系统(附源码+演示视频+LW)

大家好&#xff01;我是程序猿老A&#xff0c;感谢您阅读本文&#xff0c;欢迎一键三连哦。 &#x1f49e;当前专栏&#xff1a;Java毕业设计 精彩专栏推荐&#x1f447;&#x1f3fb;&#x1f447;&#x1f3fb;&#x1f447;&#x1f3fb; &#x1f380; Python毕业设计 &…

从MySQL+MyCAT架构升级为分布式数据库,百丽应用OceanBase 4.2的感受分享

本文来自OceanBase的客户&#xff0c;百丽时尚的使用和测试分享 业务背景 百丽时尚集团&#xff0c;作为国内大型时尚鞋服集团&#xff0c;在中国超过300个城市设有直营门店&#xff0c;数量超过9,000家。集团构建了以消费者需求为核心的垂直一体化业务模式&#xff0c;涵盖了…

Nginx实现端口转发与负载均衡配置

前言&#xff1a;当我们的软件体系结构较为庞大的时候&#xff0c;访问量往往是巨大的&#xff0c;所以我们这里可以使用nginx的均衡负载 一、配置nginx实现端口转发 本地tomcat服务端口为8082 本地nginx端口为8080 目的&#xff1a;将nginx的8080转发到tomcat的8082端口上…

SpringCloud学习笔记(二)Ribbon负载均衡、Nacos注册中心、Nacos与Eureka的区别

文章目录 4 Ribbon负载均衡4.1 负载均衡原理4.2 源码解读4.3 负载均衡策略4.3.1 内置的负载均衡策略4.3.2 自定义负载均衡策略4.3.2.1 方式一&#xff1a;定义IRule4.3.2.2 方式二&#xff1a;配置文件 4.4 饥饿加载 5 Nacos注册中心5.1 认识和安装Nacos5.2 服务注册到Nacos5.3…

Bert基础(二十一)--Bert实战:文本摘要

一、介绍 1.1 文本摘要简介 文本摘要&#xff08;Text Summarization&#xff09;&#xff0c;作为自然语言处理&#xff08;NLP&#xff09;领域的一个分支&#xff0c;其核心目标是从长篇文档中提取关键信息&#xff0c;并生成简短的摘要&#xff0c;以提供对原始内容的高度…

【算法基础实验】图论-最小生成树Prim的延迟实现

最小生成树-Prim的延迟实现 理论基础 树的基本性质 用一条边连接树中的任意两个顶点都会产生一个新的环&#xff1b; 从树中删去一条边将会得到两棵独立的树。 切分定理的定义 定义。图的一种切分是将图的所有顶点分为两个非空且不重叠的两个集合。横切边 是一条连接两个属…

【全网首发】2024五一数学建模ABC题保奖思路(后续会更新)

一定要点击文末的卡片哦&#xff01; 1&#xff09;常见模型分类 机理分析类&#xff1a;来源于实际问题&#xff0c;需要了解一定的物理机理&#xff0c;转化为优化问题。 运筹优化类&#xff1a;旨在找到使某个目标函数取得最大或最小值的最优解,对于机理要求要求不高&…

kube-prometheus部署到 k8s 集群

文章目录 **修改镜像地址****访问配置****修改 Prometheus 的 service****修改 Grafana 的 service****修改 Alertmanager 的 service****安装****Prometheus验证****Alertmanager验证****Grafana验证****卸载****Grafana显示时间问题** 或者配置ingress添加ingress访问grafana…

SQL 基础 | BETWEEN 的常见用法

在SQL中&#xff0c;BETWEEN是一个操作符&#xff0c;用于选取介于两个值之间的数据。 它包含这两个边界值。BETWEEN操作符常用于WHERE子句中&#xff0c;以便选取某个范围内的值。 以下是BETWEEN的一些常见用法&#xff1a; 选取介于两个值之间的值&#xff1a; 使用 BETWEEN来…

数据结构可视化(适合考研党)

废话不多说传送门 还在疑惑平衡二叉树、红黑树、B树、B树怎么插入构建的吗&#xff0c;不要慌张&#xff0c;这个网站会一步一步来演示.&#xff0c;听了咸鱼的课还不够&#xff0c;需要自己动手模拟一下各种数据结构的CRUD&#xff01;&#xff01;

VTK —— 二、教程五 - 通过鼠标事件与渲染交互(附完整源码)

代码效果 本代码编译运行均在如下链接文章生成的库执行成功&#xff0c;若无VTK库则请先参考如下链接编译vtk源码&#xff1a; VTK —— 一、Windows10下编译VTK源码&#xff0c;并用Vs2017代码测试&#xff08;附编译流程、附编译好的库、vtk测试源码&#xff09; 教程描述 本…

本地构建编译Apache-Seatunnel2.3.5适配Web1.0.0运行实现Mysql-CDC示例

本地构建编译Apache-Seatunnel2.3.5适配Web1.0.0运行实现Mysql-CDC示例 文章目录 1.前言2.编译2.1版本说明2.2 seatunnel2.3.4-release分支配置2.3maven调优配置 3.web1.0.0适配3.1配置文件修改和新增文件3.2手动拷贝jar修改依赖3.3修改web不兼容的代码3.4 web编译打包 4.运行m…

PHP源码_在线艺术字体在线生成转换设计网站源码

最全的字体转换器在线转换、艺术字体在线生成器和字体下载&#xff0c;包括书法字体在线转换、毛笔字在线生成器&#xff0c;更有草书字体、篆体字、连笔字、POP字体转换器等中文和英文字体。 支持自己添加字体&#xff0c;在线艺术字体转换器&#xff0c;织梦内核艺术字体在线…

百川crm系统 教育crm系统 一款高效的培训机构管理系统

在教育培训行业日益竞争激烈的今天&#xff0c;如何精准把握客户需求、提升服务质量、实现客户价值最大化&#xff0c;成为了每一家教育培训机构都必须面对的问题。为此&#xff0c;一款高效、智能的CRM客户管理系统成为了教育培训机构不可或缺的得力助手。本文将为您详细介绍这…

在Linux操作系统中的磁盘分区管理案例

1.在硬盘sdb上创建不同的分区实例练习 Linux操作系统是安装在硬盘sda硬盘中&#xff0c;所以不要轻易动硬盘sda中的文件信息 有如下需求 创建主分区 500M 文件系统 ext4 挂载点 /web 创建主分区 500M 文件系统 ext4 挂载点 /nginx 创建逻辑分区 500M 文件系…

【消息队列】RabbitMQ五种消息模式

RabbitMQ RabbitMQRabbitMQ安装 常见的消息模型基本消息队列SpringAMQPWorkQueue消息预取发布订阅模式Fanout ExchangeDirectExchangeTopicExchange 消息转换器 RabbitMQ RabbitMQ是基于Erlang语言开发的开源消息通信中间件 官网地址&#xff1a;https://www.rabbitmq.com/ R…

java技术栈快速复习04_javaweb基础总结

javaweb概述 JDBC JDBC&#xff08;Java DataBase Connectivity&#xff0c;Java数据库连接&#xff09;是一种用于执行SQL语句的Java API&#xff0c;可以为多种关系数据库提供统一访问。简单说就是用Java语言来操作数据库。 jdbc原理 早期SUN公司的天才们想编写一套可以连接…

C++ ─── 内存管理

1 . C / C内存分布 我们先看下面的一段代码和相关问题 int globalVar 1;static int staticGlobalVar 1;void Test(){static int staticVar 1;int localVar 1;int num1[10] {1, 2, 3, 4};char char2[] "abcd";char* pChar3 "abcd";int* ptr1 (int…

Postgresql源码(127)投影ExecProject的表达式执行分析

无论是投影还是别的计算&#xff0c;表达式执行的入口和计算逻辑都是统一的&#xff0c;这里已投影为分析表达式执行的流程。 1 投影函数 用例 create table t1(i int primary key, j int, k int); insert into t1 select i, i % 10, i % 100 from generate_series(1,1000000…

JeeSite框架安装部署

下载JeeSite框架。 依次执行两个sql文件。 如果是mysql8.0&#xff0c;则create_user.sql需要改成下面的内容&#xff1a; -- 打开 my.ini 给 [mysqld] 增加如下配置&#xff1a; -- sql_modeONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREAT…
最新文章