scrapy爬虫实战

scrapy爬虫实战

  • Scrapy 简介
    • 主要特性
    • 示例代码
  • 安装scrapy,并创建项目
  • 运行单个脚本
    • 代码示例
      • 配置
        • item
        • setting
      • 爬虫脚本
    • 代码解析
      • xpath基本语法:
      • 路径表达式示例:
      • 通配符和多路径:
      • 函数:
      • 示例:
  • 批量运行
  • 附录1,持久化存入数据库
  • 附录2,如何在本地启动数据库

Scrapy 简介

Scrapy 是一个强大的开源网络爬虫框架,用于从网站上提取数据。它以可扩展性和灵活性为特点,被广泛应用于数据挖掘、信息处理和历史数据抓取等领域。官网链接(外)

主要特性

  1. 模块化结构:Scrapy 的设计采用了模块化结构,包括引擎、调度器、下载器、爬虫和管道等组件。这使得用户能够根据需要选择性地使用或扩展不同的功能。

  2. 选择器:Scrapy 提供了灵活强大的选择器,可以通过 CSS 或 XPath 表达式轻松地提取网页中的数据。

  3. 中间件支持:用户可以通过中间件自定义处理请求和响应,例如修改请求头、实现代理、或者处理异常情况。

  4. 自动限速:Scrapy 具备自动限速功能,避免对目标网站造成过大的负担,同时支持自定义的下载延迟。

  5. 并发控制:支持异步处理和并发请求,提高爬取效率。

  6. 扩展性:Scrapy 提供了丰富的扩展接口,用户可以通过编写扩展插件实现定制化的功能。

  7. 数据存储:通过管道(Pipeline)机制,Scrapy 支持将抓取到的数据存储到多种格式,如 JSON、CSV、数据库等。

  8. 用户友好的命令行工具:Scrapy 提供了一套直观易用的命令行工具,方便用户创建、运行和管理爬虫项目。

示例代码

import scrapy

class MySpider(scrapy.Spider):
    name = 'my_spider' # 爬虫名字,后续是根据这个名字运行相关代码,而不是类名
    start_urls = ['http://example.com'] # 爬虫的入口网站

    def parse(self, response):
        # 使用选择器提取数据
        title = response.css('h1::text').get()
        body = response.css('p::text').get()

        # 返回抓取到的数据
        yield {
            'title': title,
            'body': body,
        }

这是一个简单的爬虫示例,通过定义爬虫类、指定起始 URL 和解析方法,用户可以快速创建一个基本的爬虫。

以上是 Scrapy 的简要介绍,它的灵活性和强大功能使其成为网络爬虫领域的瑞士军刀。

安装scrapy,并创建项目

使用python包管理工具pip安装scrapy

pip install scrapy

安装完成后使用scrapy创建项目

scrapy startproject sw

创建完成后,我的目录格式如下:

sw/
│
├── sw/
│   ├── __init__.py
│   ├── items.py
│   ├── middlewares.py
│   ├── pipelines.py
│   ├── settings.py
│   └── spiders/
│       └── __init__.py
│
├── scrapy.cfg
└── README.md

解释一下各个目录和文件的作用:

  • sw/sw/: 项目的 Python 模块,包含了爬虫项目的主要代码。

    • init.py: 空文件,用于指示该目录是一个 Python 包。
    • items.py: 定义用于存储爬取数据的数据模型。
    • middlewares.py: 包含自定义中间件的文件,用于处理请求和响应。
    • pipelines.py: 包含自定义管道的文件,用于处理抓取到的数据的存储和处理。
    • settings.py: 包含项目的设置和配置信息。(如果要链接数据库,记得在这个文件里填写相应信息)
    • spiders/: 存放爬虫代码的目录。
      • init.py: 空文件,用于指示该目录是一个 Python 包。
  • scrapy.cfg: Scrapy 项目的配置文件,包含有关项目的元数据和设置。

  • README.md: 项目的说明文档,可以包含有关项目的描述、使用说明等信息。

这是一个标准的 Scrapy 项目结构,您可以根据实际需求和项目规模进行调整和扩展。

运行单个脚本

代码示例

配置

先配置相关信息

item

item.py中的内容如下:

# Define here the models for your scraped items
#
# See documentation in:
# https://docs.scrapy.org/en/latest/topics/items.html

import scrapy

class SwItem(scrapy.Item):
    # define the fields for your item here like:
    # name = scrapy.Field()

    url = scrapy.Field()
    title = scrapy.Field()
    time = scrapy.Field()
    content = scrapy.Field()
    scrapy_time = scrapy.Field()

    trans_title = scrapy.Field()
    trans_content = scrapy.Field()
    
    org = scrapy.Field()
    trans_org = scrapy.Field()
setting

setting.py中的内容如下:

# Scrapy settings for sw project
#
# For simplicity, this file contains only settings considered important or
# commonly used. You can find more settings consulting the documentation:
#
#     https://docs.scrapy.org/en/latest/topics/settings.html
#     https://docs.scrapy.org/en/latest/topics/downloader-middleware.html
#     https://docs.scrapy.org/en/latest/topics/spider-middleware.html

BOT_NAME = "sw"

SPIDER_MODULES = ["sw.spiders"]
NEWSPIDER_MODULE = "sw.spiders"
DOWNLOAD_DELAY = 3
RANDOMIZE_DOWNLOAD_DELAY = True
USER_AGENT = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36'
COOKIES_ENABLED = True


# Crawl responsibly by identifying yourself (and your website) on the user-agent
#USER_AGENT = "sw (+http://www.yourdomain.com)"

# Obey robots.txt rules
ROBOTSTXT_OBEY = True

# Configure maximum concurrent requests performed by Scrapy (default: 16)
#CONCURRENT_REQUESTS = 32

# Configure a delay for requests for the same website (default: 0)
# See https://docs.scrapy.org/en/latest/topics/settings.html#download-delay
# See also autothrottle settings and docs
#DOWNLOAD_DELAY = 3
# The download delay setting will honor only one of:
#CONCURRENT_REQUESTS_PER_DOMAIN = 16
#CONCURRENT_REQUESTS_PER_IP = 16

# Disable cookies (enabled by default)
#COOKIES_ENABLED = False

# Disable Telnet Console (enabled by default)
#TELNETCONSOLE_ENABLED = False

# Override the default request headers:
#DEFAULT_REQUEST_HEADERS = {
#    "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8",
#    "Accept-Language": "en",
#}

# Enable or disable spider middlewares
# See https://docs.scrapy.org/en/latest/topics/spider-middleware.html
#SPIDER_MIDDLEWARES = {
#    "sw.middlewares.SwSpiderMiddleware": 543,
#}

# Enable or disable downloader middlewares
# See https://docs.scrapy.org/en/latest/topics/downloader-middleware.html
#DOWNLOADER_MIDDLEWARES = {
#    "sw.middlewares.SwDownloaderMiddleware": 543,
#}

# Enable or disable extensions
# See https://docs.scrapy.org/en/latest/topics/extensions.html
#EXTENSIONS = {
#    "scrapy.extensions.telnet.TelnetConsole": None,
#}

# Configure item pipelines
# See https://docs.scrapy.org/en/latest/topics/item-pipeline.html
#ITEM_PIPELINES = {
#    "sw.pipelines.SwPipeline": 300,
#}
# ITEM_PIPELINES = {
#    "sw.pipelines.SwPipeline": 300,
# }

# 数据库的相关配置
# DB_SETTINGS = {
#     'host': '127.0.0.1',
#     'port': 3306,
#     'user': 'root',
#     'password': '123456',
#     'db': 'scrapy_news_2024_01_08',
#     'charset': 'utf8mb4',
# }

# Enable and configure the AutoThrottle extension (disabled by default)
# See https://docs.scrapy.org/en/latest/topics/autothrottle.html
#AUTOTHROTTLE_ENABLED = True
# The initial download delay
#AUTOTHROTTLE_START_DELAY = 5
# The maximum download delay to be set in case of high latencies
#AUTOTHROTTLE_MAX_DELAY = 60
# The average number of requests Scrapy should be sending in parallel to
# each remote server
#AUTOTHROTTLE_TARGET_CONCURRENCY = 1.0
# Enable showing throttling stats for every response received:
#AUTOTHROTTLE_DEBUG = False

# Enable and configure HTTP caching (disabled by default)
# See https://docs.scrapy.org/en/latest/topics/downloader-middleware.html#httpcache-middleware-settings
#HTTPCACHE_ENABLED = True
#HTTPCACHE_EXPIRATION_SECS = 0
#HTTPCACHE_DIR = "httpcache"
#HTTPCACHE_IGNORE_HTTP_CODES = []
#HTTPCACHE_STORAGE = "scrapy.extensions.httpcache.FilesystemCacheStorage"

# Set settings whose default value is deprecated to a future-proof value
REQUEST_FINGERPRINTER_IMPLEMENTATION = "2.7"
TWISTED_REACTOR = "twisted.internet.asyncioreactor.AsyncioSelectorReactor"
FEED_EXPORT_ENCODING = "utf-8"
# REDIRECT_ENABLED = False

爬虫脚本

过程非常简单,只需要在spiders/目录下,创建自己的代码即可。示例代码p3_new_39.py (tips: 直接把这个代码放到spiders/目录下,在控制台中输入scrapy crawl p3_new_39 -o p3_new_39.csv即可运行!-o 后面接的是输出文件。) 如下:

"""
Created on 2024/01/06 14:00 by Fxy
"""
import scrapy
from sw.items import SwItem
import time
from datetime import datetime

class SWSpider(scrapy.Spider):
    '''
    scrapy变量
    '''
    # 爬虫名称(自己定义)
    name = "p3_new_39"
    # 允许爬取的域名
    allowed_domains = ["www.meduniwien.ac.at"]
    # 爬虫的起始链接
    start_urls = ["https://www.meduniwien.ac.at/web/en/about-us/news/"]
    # 创建一个VidoItem实例
    item = SwItem()
    '''
    自定义变量
    '''
    # 机构名称
    org = "奥地利维也纳医科大学病毒学中心"
    # 机构英文名称
    org_e = "Med Univ Vienna, Ctr Virol"
    # 日期格式
    site_date_format = '%Y-%m-%d %H:%M' # 网页的日期格式
    date_format = '%d.%m.%Y %H:%M:%S' # 目标日期格式
    # 网站语言格式
    language_type = "zh2zh"  # 中文到中文的语言代码, 调用翻译接口时,使用


    #爬虫的主入口,这里是获取所有的归档文章链接
    def parse(self,response): 
        achieve_links = response.xpath('//*[@id="c4345"]//div[@class="news-teaser__caption"]/h2/a/@href').extract()
        print("achieve_links",achieve_links)
        for achieve_link in achieve_links:
            if "http" in achieve_link:
                continue
            full_achieve_link = "https://www.meduniwien.ac.at" + achieve_link
            print("full_achieve_link", full_achieve_link)
            # 进入每个归档链接
            yield scrapy.Request(full_achieve_link, callback=self.parse_item, dont_filter=True)

        #翻页逻辑
        xpath_expression = f'//*[@id="c4345"]//ul[@class="pagination"]/li[@class="next"]/a/@href'
        next_page = response.xpath(xpath_expression).extract_first()
        print("next_page = ", next_page)

        # 翻页操作
        if next_page != None:
            print(next_page)
            print('next page')
            full_next_page = "https://www.meduniwien.ac.at" + next_page
            print("full_next_page",full_next_page)
            yield scrapy.Request(full_next_page, callback=self.parse, dont_filter=True)


    #获取每个文章的内容,并存入item
    def parse_item(self,response):
        source_url = response.url
        print("source_url:", source_url)
        title_o = response.xpath('//*[@id="main"]/header/div/div[2]/div[1]/h1/text()').extract_first().strip()
        # title_t = my_tools.get_trans(title_o, "de2zh") *[@id="c4342"]/div/div/div[2]/span
        print("title_o:", title_o) #//*[@id="c4342"]/div/div/div[2]/span
        year_string = response.xpath('//div[@class="news-detail__meta"]/span/@data-year').extract_first().strip()
        month_string = response.xpath('//div[@class="news-detail__meta"]/span/@data-month').extract_first().strip()
        day_string = response.xpath('//div[@class="news-detail__meta"]/span/@data-day').extract_first().strip()
        hour_string = response.xpath('//div[@class="news-detail__meta"]/span/@data-hour').extract_first().strip()
        minute_string = response.xpath('//div[@class="news-detail__meta"]/span/@data-minute').extract_first().strip()
        publish_time = f'{year_string}-{month_string}-{day_string} {hour_string}:{minute_string}'
        print("publish_time:", publish_time)
        date_object = datetime.strptime(publish_time, self.site_date_format) # 先读取成网页的日期格式
        date_object = date_object.strftime(self.date_format) # 转换成目标的日期字符串
        publish_time = datetime.strptime(date_object, self.date_format) # 从符合格式的字符串,转换成日期

        content_o = [content.strip() for content in response.xpath('//div[@class="content__block"]//text()').extract()]
        content_o = ' '.join(content_o) # 这个content_o提取出来是一个字符串数组,所以要拼接成字符串
        # content_t = my_tools.get_trans(content_o, "de2zh")

        print("source_url:", source_url)
        print("title_o:", title_o)
        # print("title_t:", title_t)
        print("publish_time:", publish_time) #15.01.2008
        print("content_o:", content_o)
        # print("content_t:", content_t)
        print("-" * 50)

        page_data = { 
            'source_url': source_url,
            'title_o': title_o,
            # 'title_t' : title_t,
            'publish_time': publish_time,
            'content_o': content_o,
            # 'content_t': content_t,
            'org' : self.org,
            'org_e' : self.org_e,
        }
        self.item['url'] = page_data['source_url']
        self.item['title'] = page_data['title_o']
        # self.item['title_t'] = page_data['title_t']
        self.item['time'] = page_data['publish_time']
        self.item['content'] = page_data['content_o']
        # self.item['content_t'] = page_data['content_t']
        # 获取当前时间
        current_time = datetime.now()
        # 格式化成字符串
        formatted_time = current_time.strftime(self.date_format)
        # 将字符串转换为 datetime 对象
        datetime_object = datetime.strptime(formatted_time, self.date_format)
        self.item['scrapy_time'] = datetime_object
        self.item['org'] = page_data['org']
        self.item['trans_org'] = page_data['org_e']

        yield self.item

在控制台中输入scrapy crawl p3_new_39 -o p3_new_39.csv即可运行!-o 后面接的是输出文件。

代码解析

接下来我们来分析,上面p3_new_39.py代码中的response.xpath()中的参数如何确定。
1、首先进入网页: https://www.meduniwien.ac.at/web/en/about-us/news/(外):
在这里插入图片描述
2、确定自己要爬取的数据,这里我假定为每一条新闻。
在这里插入图片描述
3、打开浏览器的调试工具(默认f12)找到跳转的链接。
在这里插入图片描述
4、右键元素,复制xpath即可。
在这里插入图片描述
我的复制结果如下://*[@id="c4345"]/div/div[1]/div/h2/a

xpath基本语法:

XPath(XML Path Language)是一种用于在 XML 文档中定位和选择节点的查询语言。它不仅可以用于 XML,还可以用于 HTML 和其他标记语言。以下是XPath的主要语法和一些常见用法:

  1. 节点选择

    • /: 从根节点开始选择。
    • //: 选择节点,不考虑它们的位置。
    • .: 选取当前节点。
    • ..: 选取当前节点的父节点。
  2. 节点名称

    • elementName: 选取所有名称为 elementName 的节点。
    • *: 选取所有子节点。
  3. 谓语

    • [condition]: 通过添加条件筛选节点。
      • 例如://div[@class='example'] 选取所有 class 属性为 ‘example’ 的 div 节点。

路径表达式示例:

  • /bookstore/book[1]: 选取第一个 <book> 元素。
  • /bookstore/book[last()]: 选取最后一个 <book> 元素。
  • /bookstore/book[position()<3]: 选取前两个 <book> 元素。
  • //title[@lang='en']: 选取所有带有 lang 属性为 ‘en’ 的 <title> 元素。
  • //title[@lang='en']/text(): 选取所有带有 lang 属性为 ‘en’ 的 <title> 元素的文本内容。
  • //title[not(@lang='en')]/text(): 选取所有 lang 属性为 ‘en’ 的 <title> 元素的文本内容。
  • //title[@lang='en' or @lang='zh']/text(): 选取所有带有 lang 属性为 ‘en’ ‘zh’ 的 <title> 元素的文本内容。
  • //title[contains(@lang, 'en')]/text() 选取所有带有 lang 属性包含 'en’子串 的 <title> 元素的文本内容。

通配符和多路径:

  • *: 通配符,匹配任何元素节点。
  • @*: 匹配任何属性节点。
  • //book/title | //book/price: 选取所有 <book> 元素的 <title><price> 子元素。

函数:

XPath 还支持一些内置函数,例如:

  • text(): 获取节点的文本内容。
  • contains(str1, str2): 判断一个字符串是否包含另一个字符串。

示例:

考虑以下 XML 结构:

<bookstore>
  <book>
    <title lang="en">Introduction to XPath</title>
    <price>29.95</price>
  </book>
  <book>
    <title lang="fr">XPath et ses applications</title>
    <price>39.99</price>
  </book>
</bookstore>

使用 XPath 可以选择如下:

  • /bookstore/book: 选取所有 <book> 元素。
  • /bookstore/book/title[@lang='en']: 选取所有带有 lang 属性为 ‘en’ 的 <title> 元素。

这是XPath的基本语法和用法示例,它允许您灵活而精确地定位和提取 XML 或 HTML 文档中的数据。

批量运行

sw项目目录下可以创建一个mian.py

from scrapy.crawler import CrawlerProcess
from scrapy.utils.project import get_project_settings

settings = get_project_settings()

crawler = CrawlerProcess(settings)

bot_list = ["p3_new_39"] # 把要运行的通通放进去

for bot in bot_list:
    crawler.crawl(bot)
    crawler.start()

附录1,持久化存入数据库

scrapy有个非常好的特点,就是支持自动存入数据库。我们只要将代码写好,然后每次scrapy都会自动调用该代码,不需要自己显示的调用,非常省心。我的piplines.py代码如下:

# Define your item pipelines here
#
# Don't forget to add your pipeline to the ITEM_PIPELINES setting
# See: https://docs.scrapy.org/en/latest/topics/item-pipeline.html


# useful for handling different item types with a single interface
from itemadapter import ItemAdapter
import pymysql


class SwPipeline:
    def __init__(self, db_settings):
        self.db_settings = db_settings

    @classmethod
    def from_crawler(cls, crawler):
        db_settings = crawler.settings.get("DB_SETTINGS")
        return cls(db_settings)

    def open_spider(self, spider):
        self.connection = pymysql.connect(**self.db_settings)
        self.cursor = self.connection.cursor()

    def close_spider(self, spider):
        self.connection.close()

    def process_item(self, item, spider):
        # Assuming your item keys match the column names in your database table
        keys = ', '.join(item.keys())
        values = ', '.join(['%s'] * len(item))
        query = f"INSERT INTO org_news ({keys}) VALUES ({values})" #这里记得确认我们item.py中定义的类型名字,是否和数据库中的一样,不一样,这个查询语句需要进行相应的修改,我这里就不一样,所以没法直接运行哦,我懒得改了!!!!哈哈哈
        
        # Check if the record already exists based on a combination of fields, 如果记录已经存在则取消插入,如果有键的话直接用键就行,我这里没有键
        unique_fields = ["title_o", "source_url"]  # Replace with the actual field names you want to use
        check_query = f"SELECT * FROM org_news WHERE {' AND '.join(f'{field} = %s' for field in unique_fields)}"
        check_values = tuple(item.get(field) for field in unique_fields)

        try:
            # Check if the record already exists
            self.cursor.execute(check_query, check_values)
            existing_record = self.cursor.fetchone()

            if existing_record:
                spider.logger.warning("Record already exists. Skipping insertion.")
            else:
                # If the record doesn't exist, insert it into the database
                self.cursor.execute(query, tuple(item.values()))
                self.connection.commit()

        except Exception as e:
            self.connection.rollback()
            spider.logger.error(f"Error processing item and inserting data into database: {e}")

        return item

我创建数据库的代码如下:

/*
 Navicat Premium Data Transfer

 Source Server         : 172.16.6.165
 Source Server Type    : MySQL
 Source Server Version : 80035
 Source Host           : 172.16.6.165:3306
 Source Schema         : swaq

 Target Server Type    : MySQL
 Target Server Version : 80035
 File Encoding         : 65001

 Date: 08/01/2024 10:01:57
*/

SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;

-- ----------------------------
-- Table structure for org_news
-- ----------------------------
DROP TABLE IF EXISTS `org_news`;
CREATE TABLE `org_news`  (
  `id` int(0) NOT NULL AUTO_INCREMENT,
  `title_t` varchar(1000) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '翻译标题名称',
  `title_o` varchar(1000) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '原消息标题',
  `content_t` longtext CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL COMMENT '翻译',
  `publish_time` datetime(0) NULL DEFAULT NULL COMMENT '发布时间',
  `content_o` longtext CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL COMMENT '原文',
  `site` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '新闻源',
  `tag` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '标签',
  `author` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '作者',
  `create_time` datetime(0) NULL DEFAULT NULL COMMENT '爬取时间',
  `source_url` varchar(1000) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT 'url',
  `country` varchar(100) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '国家/地区',
  `imgurl` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '图片存放地址',
  `org` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '机构名称',
  `org_e` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '机构英文名称',
  PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 314 CHARACTER SET = utf8mb3 COLLATE = utf8mb3_general_ci ROW_FORMAT = Dynamic;

SET FOREIGN_KEY_CHECKS = 1;

附录2,如何在本地启动数据库

1、先安装mysql
2、配置好?(我电脑的mysql几年前安装的,下载了一个navicat)
3、windows控制台输入mysqld --console应该就能启动了。
注意: mysqld 是服务端程序mysql是命令行客户端程序
4、然后应该就能够连接了

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

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

相关文章

自动化测试 - Web自动化测试原理

目前市面上有很多Web UI自动化测试框架&#xff0c;比如WatiN, Selinimu,WebDriver&#xff0c;还有VS2010中的Coded UI等等. 这些框架都可以操作Web中的控件&#xff0c;模拟用户输入&#xff0c;点击等操作&#xff0c;实现Web自动化测试。其实这些工具的原理都一样&#xff…

谷达冠楠:抖店新手小白适合卖什么

随着抖音平台的不断发展&#xff0c;越来越多的人开始尝试在抖音上开设自己的店铺&#xff0c;希望通过这个平台实现创业梦想。然而&#xff0c;对于新手小白来说&#xff0c;如何选择合适的商品进行销售是一个非常重要的问题。本文将为您介绍一些适合抖店新手小白销售的商品类…

若依框架实现排序【升序或降序】很简单

前端实现 1. 在表格上加监听函数sort-change。如下红框所示&#xff1a; 2. 在表行上加排序字:sort-orders&#xff0c;可排序字sortable。如下红框所示&#xff1a; 3. 添加监听函数实现。代码如下&#xff1a; handleSortChange(column) {this.queryParams.orderByColumn …

什么是云服务器ECS - 云服务器 ECS - 阿里云

阿里云服务器ECS英文全程Elastic Compute Service&#xff0c;云服务器ECS是一种安全可靠、弹性可伸缩的云计算服务&#xff0c;阿里云提供多种云服务器ECS实例规格&#xff0c;如经济型e实例、通用算力型u1、ECS计算型c7、通用型g7、GPU实例等&#xff0c;阿里云百科aliyunbai…

云渲染农场渲染和自己搭建农场渲染怎么选?哪个更划算?

&#xfeff;当我们面临繁重或紧急的渲染任务时&#xff0c;通常会选择云渲染的解决方案。可能很多人会问&#xff0c;我们是否能够自行建立一个小型的个人农场进行渲染呢&#xff1f;与云渲染农场相比&#xff0c;哪个更划算&#xff1f;更方便&#xff1f;接下来就带大家看看…

Yii实现邮件发送

一&#xff1a;yiisoft/yii2-swiftmailer拓展安装 composer require yiisoft/yii2-swiftmailer github地址&#xff1a;https://github.com/yiisoft/yii2-swiftmailer 文档地址&#xff1a;https://www.yiichina.com/doc/guide/2.0/tutorial-mailing 二&#xff1a;开启邮箱…

一刀切转为精细化,门店如何进行「体检式」巡查(一)

在品牌经营过程中&#xff0c;无论是直营店还是加盟商&#xff0c;都需要做好统一的品牌门店管理。比如总部对门店环境卫生、员工服务质量、货品质量等进行定期或不定期的巡检抽查&#xff0c;以确保各门店保持统一标准。 以往&#xff0c;传统巡店只能通过有纸质表格或微信汇报…

线程之间如何传递上下文信息

文章目录 源码解读1. 扩展ThreadPoolExecutor2. 扩展Runnable3. 整体流程 源于工作中一个业务场景的需求。 源码 话不多说&#xff0c;先贴完整的源码&#xff1a; public class ContextPassingBetweenThread {private static ThreadLocal<String> CONTEXT new Thread…

如何构建高质量,低成本的移动机器人(AGV/AMR)?

中国移动机器人行业规模的不断扩大&#xff0c;低成本无人化是现市场需求突出的特点之一。然而研发一套完整的移动机器人导航方案不仅需要耗费大量的人力成本&#xff0c;还要经过漫长的市场验证&#xff0c;这将滞后整个产业的发展&#xff0c;并有可能错失市场的抢占先机。 如…

coala,一个超级实用的 Python 库!

更多资料获取 &#x1f4da; 个人网站&#xff1a;ipengtao.com 大家好&#xff0c;今天为大家分享一个超级实用的 Python 库 - coala。 Github地址&#xff1a;https://github.com/coala/coala/ 在现代软件开发中&#xff0c;代码质量和一致性是非常重要的。然而&#xff0c…

多合一小程序商城系统源码:支持全平台端口 附带完整的搭建教程

现如今&#xff0c;随着移动互联网的飞速发展&#xff0c;小程序已经成为电商行业的新宠。罗峰给大家分享一款多合一小程序商城系统源码。该系统旨在为商家提供一个功能强大、易于搭建和管理的电商平台&#xff0c;帮助商家快速占领市场&#xff0c;提高品牌影响力。 以下是部…

springmvc内嵌tomcat、tomcat整合springmvc、自研国产web中间件

springmvc内嵌tomcat、tomcat整合springmvc、自研国产web中间件 这是由于公司老项目转化springboot存在太多坑&#xff0c;特别是hibernate事务一条就坑到跑路&#xff0c;你又不想搞没听说过的国产中间件兼容&#xff0c;又不想搞weblogic、WebSphere等中间件的适配&#xff…

Linux信号之信号的保存

(&#xff61;&#xff65;∀&#xff65;)&#xff89;&#xff9e;嗨&#xff01;你好这里是ky233的主页&#xff1a;这里是ky233的主页&#xff0c;欢迎光临~https://blog.csdn.net/ky233?typeblog 点个关注不迷路⌯▾⌯ 目录 一、阻塞信号 1.信号递达、未决、阻塞 2.内核…

flutter给组件设置背景图的操作

可以设置背景图的组件只有一个&#xff0c;那就是Container容器&#xff0c;要想设置背景图&#xff0c;可以使用网路图片&#xff0c;也可以使用本地图片&#xff0c;要是使用本地图片&#xff0c;需要在本地添加一个资源路径&#xff0c;用来管理这些文件&#xff0c;在本地项…

大量文件重命名数字排序有什么好方法?快来看这里

随着数字时代的到来&#xff0c;我们每天都会处理大量的文件&#xff0c;无论是工作还是生活。为了更好地管理和查找这些文件&#xff0c;我们通常会使用数字排序来对它们进行排列。那么&#xff0c;为什么要给大量文件添加数字排序呢&#xff1f; 首先&#xff0c;数字排序可以…

开关电源如何覆铜

开关电源如何覆铜 开关电源覆铜是一个很重要的技术方法&#xff0c;如果没有很好的覆铜&#xff0c;就有可能会造成开关电源芯片的损坏。先介绍常见的开关电源电路&#xff1a; 图 1开关电源电路 从左到右分别是非同步整流Buck电路和同步整流Buck电路&#xff0c;第二排从左到…

开发需求总结10-修改el-form-item的label,实现换行并且修改换行字体的样式

需求描述&#xff1a; 目录 需求描述&#xff1a; 相关代码&#xff1a; 额外拓展&#xff1a; 在form表单上&#xff0c;有个别label可能需要在下方有红色小字用来提示&#xff0c;这条数据的注意点&#xff0c;此时就需要实现label可以换行&#xff0c;并且给下面的小字设置…

C++力扣题目77--组合

给定两个整数 n 和 k&#xff0c;返回范围 [1, n] 中所有可能的 k 个数的组合。 你可以按 任何顺序 返回答案。 示例 1&#xff1a; 输入&#xff1a;n 4, k 2 输出&#xff1a; [[2,4],[3,4],[2,3],[1,2],[1,3],[1,4], ] 示例 2&#xff1a; 输入&#xff1a;n 1, k …

2024云渲染,渲染农场带给三维建模行业的影响

在电影和电视的CG特效制作中&#xff0c;三维建模技术是核心组成部分&#xff0c;因为它们能够创造出既细致又引人注目的场景和角色。三维建模和渲染软件等功能的也在日益强大&#xff0c;建模艺术家们可以创作出更加逼真的环境、栩栩如生的人物发丝、动人心弦的光照效果和栩栩…

Nginx设置域名转发到服务器指定的端口

&#x1f341; 作者&#xff1a;知识浅谈&#xff0c;CSDN签约讲师&#xff0c;CSDN博客专家&#xff0c;华为云云享专家&#xff0c;阿里云专家博主 &#x1f4cc; 擅长领域&#xff1a;全栈工程师、爬虫、ACM算法 &#x1f492; 公众号&#xff1a;知识浅谈 &#x1f525;网站…