python爬虫实战——小说爬取

news2024/11/25 12:01:33

python爬虫实战——小说爬取

基于requests库和lxml库编写的爬虫,目标小说网站域名http://www.365kk.cc/,类似的小说网站殊途同归,均可采用本文方法爬取。

目标网站:传送门

本文的目标书籍:《我的师兄实在太稳健了》

“渡劫只有九成八的把握,和送死有什么区别?”

基本思路

网络爬虫的工作实际上主要分为三个部分:

  • 获取网页内容,通过requests库实现;
  • 解析网页内容,得到其中我们想要的部分,通过lxml库实现;
  • 将解析出的内容储存到文本文档中;

接下来看看我们的需求是什么:

  • 获取目标书籍的基本信息,包括书籍的书名、作者、最近更新时间和简介——这些信息应该都在同一个页面中获取,即目标书籍的主页;

  • 获取目标书籍每一章节的标题和内容——不同章节在不同的页面,不同页面之间可以通过下一页按序跳转;

  • 正文部分的存储格式应便于阅读,不能把所有文字都堆积在一起,也不能包括除了正文之外的其他无关内容;

因此,我们首先尝试请求书籍的主页,获取基本信息,借此学习请求和解析网页内容的基本方法;紧接着再从书籍的第一章开始,不断地请求“下一页”,直到爬取所有内容,并将它们以合适的格式储存在文本文档中。


首页爬取与解析

首页链接:http://www.365kk.cc/255/255036/

目标内容在网页中的位置

首先,我们观察一下该网站不同的书籍主页:

可以看出:不同书籍的主页具有非常相似的结构——标题、作者、最近更新时间、最新章节和正文都在相同的位置上。

如何表征这一位置?这就需要借助python爬虫中常用的网页解析方法——XPath语法

以书名为例,在你的浏览器(以Google Chrome为例)中选中书名,点击右键 -> 检查:

可以看出,浏览器下方弹出了一个窗口,这里显示的就是该页面的源代码,我们选中的内容位于一个<h1>标签中。我们点击右键 -> 复制 -> 复制 XPath,即可得到书名的XPath路径,也就是书名在网页中的位置。

从书籍的首页中,我们需要获取的信息主要包括:

  • 书名
  • 作者
  • 最后更新时间
  • 简介

按照上述方法,分别获取它们的XPath路径,依次如下:

/html/body/div[4]/div[1]/div/div/div[2]/div[1]/h1/text()
/html/body/div[4]/div[1]/div/div/div[2]/div[1]/div/p[1]/text()
/html/body/div[4]/div[1]/div/div/div[2]/div[1]/div/p[5]/text()
/html/body/div[4]/div[1]/div/div/div[2]/div[2]/text()

/text() 表示获取文本

现在,我们得到了想要的内容在网页中的位置,只要请求到网页内容,就可以获取指定位置的内容了。


请求网页内容

我们使用比较基础的python爬虫网页请求方法:使用 requests 库直接请求。

这里涉及到了简单的反爬虫知识:在请求网页时,我们需要将我们的爬虫伪装成浏览器,具体通过添加请求头 headers 实现。

请求头以字典的形式创建,可以包括很多内容,这里只设置四个字段:User-Agent, Cookie, HostConection

headers= {
    'User-Agent': '...',  # 你的浏览器User-Agent
    'Cookie': '...',      # 你的浏览器Cookie
    'Host': 'www.365kk.cc',
    'Connection': 'keep-alive'
}

既然是为了伪装成浏览器,相关字段的内容当然要从浏览器中获取。

在刚才打开的页面中,我们点击 网络(英文版是Network),刷新页面,找到其中的第一个文件 255036/ ,打开 标头 -> 请求标头 ,即可得到我们想要的字段数据,如下图所示。

这里的文件255036/实际上就是小说主页的文件,可以看出,主页的链接为http://www.365kk.cc/255/255036/,链接后缀刚好与文件名一致。

使用 requests 库的 get 方法请求网站内容,将其解码为文本形式,输出结果验证,完整的代码如下:

import requests


# 请求头,添加你的浏览器信息后才可以正常运行
headers= {
    'User-Agent': '...',
    'Cookie': '...',
    'Host': 'www.365kk.cc',
    'Connection': 'keep-alive'
}

# 小说主页
main_url = "http://www.365kk.cc/255/255036/"

# 使用get方法请求网页
main_resp = requests.get(main_url, headers=headers)

# 将网页内容按utf-8规范解码为文本形式
main_text = main_resp.content.decode('utf-8')

print(main_text)

运行代码前,需要向 headers 中填入你自己浏览器的信息。

输出结果如下:

可以看出,我们成功请求到了网站内容,接下来只需对其进行解析,即可得到我们想要的部分。


解析网页内容

我们使用 lxml 库来解析网页内容,具体方法为将文本形式的网页内容创建为可解析的元素,再按照XPath路径访问其中的内容,代码如下:

import requests
from lxml import etree


# 请求头
headers= {
    'User-Agent': '...',
    'Cookie': '...',
    'Host': 'www.365kk.cc',
    'Connection': 'keep-alive'
}

# 小说主页
main_url = "http://www.365kk.cc/255/255036/"

# 使用get方法请求网页
main_resp = requests.get(main_url, headers=headers)

# 将网页内容按utf-8规范解码为文本形式
main_text = main_resp.content.decode('utf-8')

# 将文本内容创建为可解析元素
main_html = etree.HTML(main_text)

# 依次获取书籍的标题、作者、最近更新时间和简介
# main_html.xpath返回的是列表,因此需要加一个[0]来表示列表中的首个元素
bookTitle = main_html.xpath('/html/body/div[4]/div[1]/div/div/div[2]/div[1]/h1/text()')[0]
author = main_html.xpath('/html/body/div[4]/div[1]/div/div/div[2]/div[1]/div/p[1]/text()')[0]
update = main_html.xpath('/html/body/div[4]/div[1]/div/div/div[2]/div[1]/div/p[5]/text()')[0]
introduction = main_html.xpath('/html/body/div[4]/div[1]/div/div/div[2]/div[2]/text()')[0]

# 输出结果以验证
print(bookTitle)
print(author)
print(update)
print(introduction)

输出结果如下:

至此,我们已经学会了基本的网页请求方法,并学会了如何获取目标页面中的特定内容。


正文爬取与解析

接下来,我们开始爬取正文。首先尝试获取单个页面的数据,再尝试设计一个循环,依次获取所有正文数据。

单个页面数据的获取

以第一章为例,链接:http://www.365kk.cc/255/255036/4147599.html,获取章节标题和正文的XPath路径如下:

//*[@id="container"]/div/div/div[2]/h1/text()
//*[@id="content"]/text()

按照与上文一致的方法请求并解析网页内容,代码如下:

import requests
from lxml import etree


# 请求头
headers= {
    'User-Agent': '...',
    'Cookie': '...',
    'Host': 'www.365kk.cc',
    'Connection': 'keep-alive'
}

# ...
# 上一部分的代码
# ...

# 当前页面链接
url = 'http://www.365kk.cc/255/255036/4147599.html'

resp = requests.get(url, headers)
text = resp.content.decode('utf-8')
html = etree.HTML(text)

title = html.xpath('//*[@id="container"]/div/div/div[2]/h1/text()')[0]
contents = html.xpath('//*[@id="content"]/text()')

print(title)
for content in contents:
    print(content)

输出结果如下:

可以看出,我们成功获取了小说第一章第一页的标题和正文部分,接下来我们将它储存在一个txt文本文档中,文档命名为之前获取的书名 bookTitle.txt,完整的代码如下:

import requests
from lxml import etree


# 请求头
headers= {
    'User-Agent': '...',
    'Cookie': '...',
    'Host': 'www.365kk.cc',
    'Connection': 'keep-alive'
}

# 小说主页
main_url = "http://www.365kk.cc/255/255036/"

# 使用get方法请求网页
main_resp = requests.get(main_url, headers=headers)

# 将网页内容按utf-8规范解码为文本形式
main_text = main_resp.content.decode('utf-8')

# 将文本内容创建为可解析元素
main_html = etree.HTML(main_text)

bookTitle = main_html.xpath('/html/body/div[4]/div[1]/div/div/div[2]/div[1]/h1/text()')[0]
author = main_html.xpath('/html/body/div[4]/div[1]/div/div/div[2]/div[1]/div/p[1]/text()')[0]
update = main_html.xpath('/html/body/div[4]/div[1]/div/div/div[2]/div[1]/div/p[5]/text()')[0]
introduction = main_html.xpath('/html/body/div[4]/div[1]/div/div/div[2]/div[2]/text()')[0]

# 当前页面链接
url = 'http://www.365kk.cc/255/255036/4147599.html'

resp = requests.get(url, headers)
text = resp.content.decode('utf-8')
html = etree.HTML(text)

title = html.xpath('//*[@id="container"]/div/div/div[2]/h1/text()')[0]
contents = html.xpath('//*[@id="content"]/text()')

with open(bookTitle + '.txt', 'w', encoding='utf-8') as f:
    f.write(title)
    for content in contents:
        f.write(content)
    f.close()

运行结束后,可以看到在代码文件的同路径中,已经生成了一个文本文档:

打开该文档,可以看到储存好的内容:

储存好的内容中,大段的文字堆积在一起,而原文确实有着段落的区分,因此我们在储存文件时,每储存一段,就写入两个换行符 \n,使格式更便于阅读:

with open(bookTitle + '.txt', 'w', encoding='utf-8') as f:
    f.write(title)
    for content in contents:
        f.write(content)
        f.write('\n\n')
    f.close()

至此,我们已经完成了单个页面的数据爬取和存储,接下来只要设计循环,实现顺序爬取所有页面即可。

关于文件读取的类型

本文中,用到的文件读取类型主要有:

类型含义使用示例
'w'清空原文档,重新写入文档open(filename, 'w')
'r'仅读取文档,不改变其内容open(filename, 'r')
'a'在原文档之后追加内容open(filename, 'a')

顺序爬取所有页面

我们注意到,正文的每个页面底部,都有一个按钮下一页,其在网页中的结构为:

我们在XPath路径的末尾添加 @href 用于获取属性 href 的值:

//*[@id="container"]/div/div/div[2]/div[3]/a[3]/@href

这里有一个小细节需要注意!

我们获取到的属性值在不同页面可能是不一样的,比如:

  • 第一章第一页中,“下一页”指向的链接为/255/255036/4147599_2.html
  • 第一章第二页中,“下一页”指向的链接为4147600.html

观察不同页面的链接,可以看出前缀是一致的,区别仅在后缀上,比如第一章第一页和第一章第二页的链接分别为:

http://www.365kk.cc/255/255036/4147599.html
http://www.365kk.cc/255/255036/4147599_2.html

因此,我们只需要获取 {% kbd 下一页 %} 的链接后缀,再与前缀拼接,即可获得完整的访问链接。

编写一个函数 next_url() 实现上述功能:

# 获取下一页链接的函数
def next_url(next_url_element):
    nxturl = 'http://www.365kk.cc/255/255036/'
    # rfind('/') 获取最后一个'/'字符的索引
    index = next_url_element.rfind('/') + 1
    nxturl += next_url_element[index:]
    return nxturl


# 测试一下
url1 = '/255/255036/4147599_2.html'
url2 = '4147600.html'

print(next_url(url1))
print(next_url(url2))

输出如下所示:

在爬取某一页面的内容后,我们获取下一页的链接,并请求该链接指向的网页,重复这一过程直到全部爬取完毕为止,即可实现正文的爬取。

在这一过程中,需要注意的问题有:

  • 某一章节的内容可能分布在多个页面中,每个页面的章节标题是一致的,这一标题只需存储一次;
  • 请求网页内容的频率不宜过高,频繁地使用同一IP地址请求网页,会触发站点的反爬虫机制,禁止你的IP继续访问网站;
  • 爬取一次全文耗时较长,为了便于测试,我们需要先尝试爬取少量内容,代码调试完成后再爬取全文;
  • 爬取的起点为第一章第一页,爬取的终点可以自行设置;

按照上述思想,爬取前6个页面作为测试,完整的代码如下:

import requests
from lxml import etree
import time
import random


# 获取下一页链接的函数
def next_url(next_url_element):
    nxturl = 'http://www.365kk.cc/255/255036/'
    # rfind('/') 获取最后一个'/'字符的索引
    index = next_url_element.rfind('/') + 1
    nxturl += next_url_element[index:]
    return nxturl


# 请求头,需要添加你的浏览器信息才可以运行
headers= {
    'User-Agent': '...',
    'Cookie': '...',
    'Host': 'www.365kk.cc',
    'Connection': 'keep-alive'
}

# 小说主页
main_url = "http://www.365kk.cc/255/255036/"

# 使用get方法请求网页
main_resp = requests.get(main_url, headers=headers)

# 将网页内容按utf-8规范解码为文本形式
main_text = main_resp.content.decode('utf-8')

# 将文本内容创建为可解析元素
main_html = etree.HTML(main_text)

bookTitle = main_html.xpath('/html/body/div[4]/div[1]/div/div/div[2]/div[1]/h1/text()')[0]
author = main_html.xpath('/html/body/div[4]/div[1]/div/div/div[2]/div[1]/div/p[1]/text()')[0]
update = main_html.xpath('/html/body/div[4]/div[1]/div/div/div[2]/div[1]/div/p[5]/text()')[0]
introduction = main_html.xpath('/html/body/div[4]/div[1]/div/div/div[2]/div[2]/text()')[0]

# 调试期间仅爬取六个页面
maxPages = 6
cnt = 0

# 记录上一章节的标题
lastTitle = ''

# 爬取起点
url = 'http://www.365kk.cc/255/255036/4147599.html'

# 爬取终点
endurl = 'http://www.365kk.cc/255/255036/4148385.html'

while url != endurl:
    cnt += 1  # 记录当前爬取的页面
    if cnt > maxPages:
        break  # 当爬取的页面数超过maxPages时停止

    resp = requests.get(url, headers)
    text = resp.content.decode('utf-8')
    html = etree.HTML(text)
    title = html.xpath('//*[@class="title"]/text()')[0]
    contents = html.xpath('//*[@id="content"]/text()')

    # 输出爬取进度信息
    print("cnt: {}, title = {}, url = {}".format(cnt, title, url))

    with open(bookTitle + '.txt', 'a', encoding='utf-8') as f:
        if title != lastTitle:  # 章节标题改变
            f.write(title)      # 写入新的章节标题
            lastTitle = title   # 更新章节标题
        for content in contents:
            f.write(content)
            f.write('\n\n')
        f.close()

    # 获取"下一页"按钮指向的链接
    next_url_element = html.xpath('//*[@class="section-opt m-bottom-opt"]/a[3]/@href')[0]

    # 传入函数next_url得到下一页链接
    url = next_url(next_url_element)

    sleepTime = random.randint(2, 5)  # 产生一个2~5之间的随机数
    time.sleep(sleepTime)             # 暂停2~5之间随机的秒数

print("complete!")

运行结果如下:


数据清洗

观察我们得到的文本文档,可以发现如下问题:

  • 缺乏书籍信息,如之前获取的书名、作者、最后更新时间和简介;
  • 切换页面时,尤其是同一章节的不同页面之间空行过多

  • 每章节第一段缩进与其他段落不一致;

  • 不同章节之间缺乏显眼的分隔符

为了解决这些问题,我们编写一个函数 clean_data() 来实现数据清洗,代码如下:

def clean_data(filename, info):
    """
    :param filename: 原文档名
    :param info: [bookTitle, author, update, introduction]
    """

    print("\n==== 数据清洗开始 ====")

    # 新的文件名
    new_filename = 'new' + filename

    # 打开两个文本文档
    f_old = open(filename, 'r', encoding='utf-8')
    f_new = open(new_filename, 'w', encoding='utf-8')

    # 首先在新的文档中写入书籍信息
    f_new.write('==  《' + info[0] + '》\r\n')  # 标题
    f_new.write('==  ' + info[1] + '\r\n')     # 作者
    f_new.write('==  ' + info[2] + '\r\n')     # 最后更新时间
    f_new.write("=" * 10)
    f_new.write('\r\n')
    f_new.write('==  ' + info[3] + '\r\n')     # 简介
    f_new.write("=" * 10)
    f_new.write('\r\n')

    lines = f_old.readlines()  # 按行读取原文档中的内容
    empty_cnt = 0  # 用于记录连续的空行数

    # 遍历原文档中的每行
    for line in lines:
        if line == '\n':        # 如果当前是空行
            empty_cnt += 1      # 连续空行数+1
            if empty_cnt >= 2:  # 如果连续空行数不少于2
                continue        # 直接读取下一行,当前空行不写入
        else:                   # 如果当前不是空行
            empty_cnt = 0       # 连续空行数清零
        if line.startswith("\u3000\u3000"):  # 如果有段首缩进
            line = line[2:]                  # 删除段首缩进
            f_new.write(line)                # 写入当前行
        elif line.startswith("第"):          # 如果当前行是章节标题
            f_new.write("\r\n")              # 写入换行
            f_new.write("-" * 20)            # 写入20个'-'
            f_new.write("\r\n")              # 写入换行
            f_new.write(line)                # 写入章节标题
        else:                                # 如果当前行是未缩进的普通段落
            f_new.write(line)                # 保持原样写入

    f_old.close()  # 关闭原文档
    f_new.close()  # 关闭新文档

清洗后的文档中,每段段首无缩进,段与段之间仅空一行,不同章节之间插入20个字符 - 用以区分,上述问题得以解决。


完整的代码

需先填入自己浏览器的 headers 信息才可以直接运行!

import requests
from lxml import etree
import time
import random


# 获取下一页链接的函数
def next_url(next_url_element):
    nxturl = 'http://www.365kk.cc/255/255036/'
    # rfind('/') 获取最后一个'/'字符的索引
    index = next_url_element.rfind('/') + 1
    nxturl += next_url_element[index:]
    return nxturl


# 数据清洗函数
def clean_data(filename, info):
    """
    :param filename: 原文档名
    :param info: [bookTitle, author, update, introduction]
    """

    print("\n==== 数据清洗开始 ====")

    # 新的文件名
    new_filename = 'new' + filename

    # 打开两个文本文档
    f_old = open(filename, 'r', encoding='utf-8')
    f_new = open(new_filename, 'w', encoding='utf-8')

    # 首先在新的文档中写入书籍信息
    f_new.write('==  《' + info[0] + '》\r\n')  # 标题
    f_new.write('==  ' + info[1] + '\r\n')     # 作者
    f_new.write('==  ' + info[2] + '\r\n')     # 最后更新时间
    f_new.write("=" * 10)
    f_new.write('\r\n')
    f_new.write('==  ' + info[3] + '\r\n')     # 简介
    f_new.write("=" * 10)
    f_new.write('\r\n')

    lines = f_old.readlines()  # 按行读取原文档中的内容
    empty_cnt = 0  # 用于记录连续的空行数

    # 遍历原文档中的每行
    for line in lines:
        if line == '\n':        # 如果当前是空行
            empty_cnt += 1      # 连续空行数+1
            if empty_cnt >= 2:  # 如果连续空行数不少于2
                continue        # 直接读取下一行,当前空行不写入
        else:                   # 如果当前不是空行
            empty_cnt = 0       # 连续空行数清零
        if line.startswith("\u3000\u3000"):  # 如果有段首缩进
            line = line[2:]                  # 删除段首缩进
            f_new.write(line)                # 写入当前行
        elif line.startswith("第"):          # 如果当前行是章节标题
            f_new.write("\r\n")              # 写入换行
            f_new.write("-" * 20)            # 写入20个'-'
            f_new.write("\r\n")              # 写入换行
            f_new.write(line)                # 写入章节标题
        else:                                # 如果当前行是未缩进的普通段落
            f_new.write(line)                # 保持原样写入

    f_old.close()
    f_new.close()


# 请求头,使用前需填入自己浏览器的信息
headers= {
    'User-Agent': '...',
    'Cookie': '...',
    'Host': 'www.365kk.cc',
    'Connection': 'keep-alive'
}


# 小说主页
main_url = "http://www.365kk.cc/255/255036/"

# 使用get方法请求网页
main_resp = requests.get(main_url, headers=headers)

# 将网页内容按utf-8规范解码为文本形式
main_text = main_resp.content.decode('utf-8')

# 将文本内容创建为可解析元素
main_html = etree.HTML(main_text)

bookTitle = main_html.xpath('/html/body/div[4]/div[1]/div/div/div[2]/div[1]/h1/text()')[0]
author = main_html.xpath('/html/body/div[4]/div[1]/div/div/div[2]/div[1]/div/p[1]/text()')[0]
update = main_html.xpath('/html/body/div[4]/div[1]/div/div/div[2]/div[1]/div/p[5]/text()')[0]
introduction = main_html.xpath('/html/body/div[4]/div[1]/div/div/div[2]/div[2]/text()')[0]

# 调试期间仅爬取六个页面
maxPages = 6
cnt = 0

# 记录上一章节的标题
lastTitle = ''

# 爬取起点
url = 'http://www.365kk.cc/255/255036/4147599.html'

# 爬取终点
endurl = 'http://www.365kk.cc/255/255036/4148385.html'

while url != endurl:
    cnt += 1  # 记录当前爬取的页面
    # if cnt > maxPages:
    #     break  # 当爬取的页面数超过maxPages时停止
    
    resp = requests.get(url, headers)
    text = resp.content.decode('utf-8')
    html = etree.HTML(text)
    title = html.xpath('//*[@class="title"]/text()')[0]
    contents = html.xpath('//*[@id="content"]/text()')

    # 输出爬取进度信息
    print("cnt: {}, title = {}, url = {}".format(cnt, title, url))
    print(contents)

    with open(bookTitle + '.txt', 'a', encoding='utf-8') as f_new:
        if title != lastTitle:  # 章节标题改变
            f_new.write(title)      # 写入新的章节标题
            lastTitle = title   # 更新章节标题
        for content in contents:
            f_new.write(content)
            f_new.write('\n\n')
        f_new.close( )

    # 获取"下一页"按钮指向的链接
    next_url_element = html.xpath('//*[@class="section-opt m-bottom-opt"]/a[3]/@href')[0]

    # 传入函数next_url得到下一页链接
    url = next_url(next_url_element)

    sleepTime = random.randint(2, 5)  # 产生一个2~5之间的随机数
    time.sleep(sleepTime)             # 暂停2~5之间随机的秒数

    
clean_data(bookTitle + '.txt', [bookTitle, author, update, introduction])
print("complete!")

爬取过程如图:


封装整理

上述的开发流程基本上是想到哪写到哪,所有代码都堆在一个文件里,可读性较差

可以参考Scrapy框架的规则,将不同作用的变量和代码分配到不同的文件中,提高整个项目的可读性。

参考的文件结构如图所示:

其中:

  • output 用于存储爬虫输出的文本文档
  • clean.py 用于实现数据清洗
  • items.py 用于定义需要爬取的变量
  • main.py 是整个项目的主函数
  • settings.py 用于定义请求头、请求间隔、代理IP等
  • spider.py 用于实现爬虫的基本逻辑

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

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

相关文章

软件设计师第4题

首先&#xff0c;我是备考2023年上半年的考试。 一、历年考试题 历年的考题如下&#xff0c;从表中分析可以看出&#xff0c;动态规划法、排序算法、回溯法、分治法是很大概率考察的算法&#xff0c;尤其是动态规划法&#xff0c;本身其理解难度较高&#xff0c;且可以出的题型…

docker:容器的数据卷

1 数据卷概念及作用 1.1 什么是容器数据卷 先来看看Docker的理念&#xff1a; 将应用与运行的环境打包形成容器运行 &#xff0c;运行可以伴随着容器&#xff0c;但是我们对数据的要求希望是持久化的容器之间希望有可能共享数据 Docker容器产生的数据&#xff0c;如果不通过…

什么是人工智能的知识图谱?知识图谱的组成、构建、应用有哪些?

人工智能&#xff08;Artificial Intelligence&#xff0c;AI&#xff09;是一种通过计算机模拟人类智能的技术&#xff0c;其应用范围越来越广泛。知识图谱&#xff08;Knowledge Graph&#xff0c;KG&#xff09;则是人工智能技术中的重要组成部分&#xff0c;它是一种结构化…

Redis集群安装之主从集群

1.主从集群 Redis有三种集群模式&#xff0c;分别是&#xff1a;主从模式、哨兵模式、Cluster模式。Rdis最开始使用主从模式做集群&#xff0c;若master宕机需要手动配置slave转为master&#xff1b;后来为了高可用提出来哨兵模式&#xff0c;该模式下有一个哨兵监视master和s…

TCP实现HTTP服务

在之前的篇章中我们已经讲过七层参考模型了&#xff0c;今天我们从传输层实现应用层http服务 使用nodejs原生net模块就可以打通TCP传输层并且提供一个端口号进行监听 创建一个TCP服务 import net from netconst server net.createServer((socket) > {socket.on(data, (da…

【路径规划】基于人工蜂群算法的栅格法路径规划 机器人路径规划【Matlab代码#23】

文章目录 【可更换其他算法&#xff0c;获取资源请见文章第6节&#xff1a;资源获取】1. 原始ABC算法2. 机器人路径规划环境创建3. 路径规划模型建立4. 部分代码展示5. 仿真结果展示6. 资源获取 【可更换其他算法&#xff0c;获取资源请见文章第6节&#xff1a;资源获取】 1. 原…

【实时性】实时性优化的一些参数设置和心得

博主未授权任何人或组织机构转载博主任何原创文章&#xff0c;感谢各位对原创的支持&#xff01; 博主链接 本人就职于国际知名终端厂商&#xff0c;负责modem芯片研发。 在5G早期负责终端数据业务层、核心网相关的开发工作&#xff0c;目前牵头6G算力网络技术标准研究。 博客…

Deformable DETR 论文学习

1. 解决了什么问题&#xff1f; DETR 去除了目标检测算法中的人为设计&#xff0c;取得了不错的表现。但是其收敛速度很慢&#xff0c;对低分辨率特征识别效果差&#xff1a; 模型初始化时&#xff0c;注意力模块给特征图上所有的像素点分配的权重是均匀的&#xff0c;就需要…

chatgpt赋能Python-python5的阶乘

Python5的阶乘介绍 Python是一门广泛应用于编写脚本、自动化、爬虫、数据分析等方面的编程语言&#xff0c;也是很多科研领域使用的首选。Python的功能和灵活性可以帮助用户解决各种问题&#xff0c;而本文要介绍的是Python中计算阶乘的方法。 阶乘是数学中的一个概念&#x…

fullter 学习记录_01_插件整理

flutter学习记录第一节--搭建项目及路由的设置 1.轮播图: flutter_swiper1.1 用处1.2 导入flutter_swiper库1.3 导入库&#xff0c;运行后可能遇到的问题1.4 属性说明1.5 代码案例 2. flutter_screenutil2.1 用处2.2 引用2.3 使用说明2.4 代码实现按理2.5 ScreenUtl 的封装 1.轮…

UNIX环境高级编程——守护进程

13.1 引言 守护进程&#xff08;daemon&#xff09;是生存期长的一种进程。它们常常在系统引导装入时启动&#xff0c;仅在系统关闭时才终止。因为它们没有控制终端&#xff0c;所以说它们是在后台运行的。 13.2 守护进程的特征 系统进程依赖于操作系统实现。父进程ID为0的各…

xxs跨站之原理分类及攻击手法

xss跨站达到原理&#xff0c;危害和特点 他和语言没有太大关系&#xff0c;它大部分都是属于一个前端的漏洞&#xff0c;搭建一个简易的php网站存在xss跨站漏洞 访问这个网站&#xff0c;x1&#xff0c;就输出1&#xff0c; 如果我们把x<script>alert(1)</script&g…

系统分析师考试之论文框架

系统分析师考试之论文框架 系统分析师考试之论文框架

SpringBoot—常用注解

目录 一、注解(annotations)列表 二、注解(annotations)详解 三、JPA注解 四、springMVC相关注解 五、全局异常处理 一、注解(annotations)列表 SpringBootApplication&#xff1a; 包含了ComponentScan、Configuration和EnableAutoConfiguration注解。其中ComponentScan…

linux 读写锁 pthread_rwlock

专栏内容&#xff1a;linux下并发编程个人主页&#xff1a;我的主页座右铭&#xff1a;天行健&#xff0c;君子以自强不息&#xff1b;地势坤&#xff0c;君子以厚德载物&#xff0e; 目录 前言 概念介绍 应用场景 接口说明 头文件 rwlock定义 初始化/销毁 两种初始化方…

算法设计与智能计算 || 专题九: 基于拉普拉斯算子的谱聚类算法

谱聚类 文章目录 谱聚类1. 信息增益的度量2. 谱聚类: 寻找最优的函数向量 f \boldsymbol{f} f2.1 : 寻找一个最优的函数向量 f \boldsymbol{f} f2.2 寻找鲁棒性更强的多个函数向量2.3 谱聚类(spectral clustering)算法 小结 1. 信息增益的度量 由于数据集 X [ x 1 , x 2 ,…

自动化仓储管理系统(WMS)

仓储是现代物流的一个重要组成部分&#xff0c;在物流系统中起着至关重要的作用&#xff0c;是厂商研究和规划的重点。高效合理的仓储可以帮助厂商加快物资流动的速度&#xff0c;降低成本&#xff0c;保障生产的顺利进行&#xff0c;并可以实现对资源有效控制和管理。 随着我…

CVE-2023-27363 FOXIT PDF READER与EDITOR任意代码执行漏洞复现

目录 0x01 声明&#xff1a; 0x02 简介&#xff1a; 0x03 漏洞概述&#xff1a; 0x04 影响版本&#xff1a; 0x05 环境搭建&#xff1a; 文件下载&#xff1a; 0x06 漏洞复现&#xff1a; POC下载&#xff1a; 利用POC&#xff1a; RCE&#xff1a; 0x07 修复建议&a…

2023.5.21 第五十四次周报

目录 前言 文献阅读:跨多个时空尺度进行预测的时空 LSTM 模型 背景 本文思路 本文解决的问题 方法论 SPATIAL 自动机器学习模型 数据处理 模型性能 代码 用Python编写的LSTM多变量预测模型 总结 前言 This week, I studied an article that uses LSTM to solve p…

Kuberadm安装部署

目录 1、所需配置 2、准备环境 3、安装Docker 4、安装Kubeadm、Kubelet和Kuberctl 5、部署K8s集群 6、初始化kubeadm 7、设置kubecrl 8、部署网络插件flannel 测试 9、部署Dashboard 10、安装Harbor私有仓库 11、内核参数优化方案 1、所需配置 主机名系统要求IP地…