Python爬虫之文件存储#5

爬虫专栏:http://t.csdnimg.cn/WfCSx

文件存储形式多种多样,比如可以保存成 TXT 纯文本形式,也可以保存为 JSON 格式、CSV 格式等,本节就来了解一下文本文件的存储方式。

TXT 文本存储

将数据保存到 TXT 文本的操作非常简单,而且 TXT 文本几乎兼容任何平台,但是这有个缺点,那就是不利于检索。所以如果对检索和数据结构要求不高,追求方便第一的话,可以采用 TXT 文本存储。本节中,我们就来看下如何利用 Python 保存 TXT 文本文件。

1. 本节目标

本节中,我们要保存知乎上 “发现” 页面的 “热门话题” 部分,将其问题和答案统一保存成文本形式。

2. 基本实例

首先,可以用 requests 将网页源代码获取下来,然后使用 pyquery 解析库解析,接下来将提取的标题、回答者、回答保存到文本,代码如下:

import requests
from pyquery import PyQuery as pq
​
url = 'https://www.zhihu.com/explore'
headers = {'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.36'
}
html = requests.get(url, headers=headers).text
doc = pq(html)
items = doc('.explore-tab .feed-item').items()
for item in items:question = item.find('h2').text()author = item.find('.author-link-line').text()answer = pq(item.find('.content').html()).text()file = open('explore.txt', 'a', encoding='utf-8')file.write('\n'.join([question, author, answer]))file.write('\n' + '=' * 50 + '\n')file.close()

这里主要是为了演示文件保存的方式,因此 requests 异常处理部分在此省去。首先,用 requests 提取知乎的 “发现” 页面,然后将热门话题的问题、回答者、答案全文提取出来,然后利用 Python 提供的 open 方法打开一个文本文件,获取一个文件操作对象,这里赋值为 file,接着利用 file 对象的 write 方法将提取的内容写入文件,最后调用 close 方法将其关闭,这样抓取的内容即可成功写入文本中了。

运行程序,可以发现在本地生成了一个 explore.txt 文件,其内容如图所示。

这样热门问答的内容就被保存成文本形式了。

这里 open 方法的第一个参数即要保存的目标文件名称,第二个参数为 a,代表以追加方式写入到文本。另外,我们还指定了文件的编码为 utf-8。最后,写入完成后,还需要调用 close 方法来关闭文件对象。

3. 打开方式

在刚才的实例中,open 方法的第二个参数设置成了 a,这样在每次写入文本时不会清空源文件,而是在文件末尾写入新的内容,这是一种文件打开方式。关于文件的打开方式,其实还有其他几种,这里简要介绍一下。

  • r:以只读方式打开文件。文件的指针将会放在文件的开头。这是默认模式。

  • rb:以二进制只读方式打开一个文件。文件指针将会放在文件的开头。

  • r+:以读写方式打开一个文件。文件指针将会放在文件的开头。

  • rb+:以二进制读写方式打开一个文件。文件指针将会放在文件的开头。

  • w:以写入方式打开一个文件。如果该文件已存在,则将其覆盖。如果该文件不存在,则创建新文件。

  • wb:以二进制写入方式打开一个文件。如果该文件已存在,则将其覆盖。如果该文件不存在,则创建新文件。

  • w+:以读写方式打开一个文件。如果该文件已存在,则将其覆盖。如果该文件不存在,则创建新文件。

  • wb+:以二进制读写格式打开一个文件。如果该文件已存在,则将其覆盖。如果该文件不存在,则创建新文件。

  • a:以追加方式打开一个文件。如果该文件已存在,文件指针将会放在文件结尾。也就是说,新的内容将会被写入到已有内容之后。如果该文件不存在,则创建新文件来写入。

  • ab:以二进制追加方式打开一个文件。如果该文件已存在,则文件指针将会放在文件结尾。也就是说,新的内容将会被写入到已有内容之后。如果该文件不存在,则创建新文件来写入。

  • a+:以读写方式打开一个文件。如果该文件已存在,文件指针将会放在文件的结尾。文件打开时会是追加模式。如果该文件不存在,则创建新文件来读写。

  • ab+:以二进制追加方式打开一个文件。如果该文件已存在,则文件指针将会放在文件结尾。如果该文件不存在,则创建新文件用于读写。

4. 简化写法

另外,文件写入还有一种简写方法,那就是使用 with as 语法。在 with 控制块结束时,文件会自动关闭,所以就不需要再调用 close 方法了。这种保存方式可以简写如下:

with open('explore.txt', 'a', encoding='utf-8') as file:file.write('\n'.join([question, author, answer]))file.write('\n' + '=' * 50 + '\n')

如果想保存时将原文清空,那么可以将第二个参数改写为 w,代码如下:

with open('explore.txt', 'w', encoding='utf-8') as file:file.write('\n'.join([question, author, answer]))file.write('\n' + '=' * 50 + '\n')

上面便是利用 Python 将结果保存为 TXT 文件的方法,这种方法简单易用,操作高效,是一种最基本的保存数据的方法。

JSON 文件存储

JSON,全称为 JavaScript Object Notation, 也就是 JavaScript 对象标记,它通过对象和数组的组合来表示数据,构造简洁但是结构化程度非常高,是一种轻量级的数据交换格式。本节中,我们就来了解如何利用 Python 保存数据到 JSON 文件。

1. 对象和数组

在 JavaScript 语言中,一切都是对象。因此,任何支持的类型都可以通过 JSON 来表示,例如字符串、数字、对象、数组等,但是对象和数组是比较特殊且常用的两种类型,下面简要介绍一下它们。

对象:它在 JavaScript 中是使用花括号 {} 包裹起来的内容,数据结构为 {key1:value1, key2:value2, ...} 的键值对结构。在面向对象的语言中,key 为对象的属性,value 为对应的值。键名可以使用整数和字符串来表示。值的类型可以是任意类型。

数组:数组在 JavaScript 中是方括号 [] 包裹起来的内容,数据结构为 ["java", "javascript", "vb", ...] 的索引结构。在 JavaScript 中,数组是一种比较特殊的数据类型,它也可以像对象那样使用键值对,但还是索引用得多。同样,值的类型可以是任意类型。

所以,一个 JSON 对象可以写为如下形式:

[{"name": "Bob","gender": "male","birthday": "1992-10-18"
}, {"name": "Selina","gender": "female","birthday": "1995-10-18"
}]

由中括号包围的就相当于列表类型,列表中的每个元素可以是任意类型,这个示例中它是字典类型,由大括号包围。

JSON 可以由以上两种形式自由组合而成,可以无限次嵌套,结构清晰,是数据交换的极佳方式。

2. 读取 JSON

Python 为我们提供了简单易用的 JSON 库来实现 JSON 文件的读写操作,我们可以调用 JSON 库的 loads 方法将 JSON 文本字符串转为 JSON 对象,可以通过 dumps() 方法将 JSON 对象转为文本字符串。

例如,这里有一段 JSON 形式的字符串,它是 str 类型,我们用 Python 将其转换为可操作的数据结构,如列表或字典:

import json
​
str = '''
[{"name": "Bob","gender": "male","birthday": "1992-10-18"
}, {"name": "Selina","gender": "female","birthday": "1995-10-18"
}]
'''
print(type(str))
data = json.loads(str)
print(data)
print(type(data))

运行结果如下:

<class'str'>
[{'name': 'Bob', 'gender': 'male', 'birthday': '1992-10-18'}, {'name': 'Selina', 'gender': 'female', 'birthday': '1995-10-18'}]
<class 'list'>

这里使用 loads 方法将字符串转为 JSON 对象。由于最外层是中括号,所以最终的类型是列表类型。

这样一来,我们就可以用索引来获取对应的内容了。例如,如果想取第一个元素里的 name 属性,就可以使用如下方式:

data[0]['name']
data[0].get('name')

得到的结果都是:

Bob

通过中括号加 0 索引,可以得到第一个字典元素,然后再调用其键名即可得到相应的键值。获取键值时有两种方式,一种是中括号加键名,另一种是通过 get 方法传入键名。这里推荐使用 get 方法,这样如果键名不存在,则不会报错,会返回 None。另外,get 方法还可以传入第二个参数(即默认值),示例如下:

data[0].get('age')
data[0].get('age', 25)

运行结果如下:

None
25

这里我们尝试获取年龄 age,其实在原字典中该键名不存在,此时默认会返回 None。如果传入第二个参数(即默认值),那么在不存在的情况下返回该默认值。

值得注意的是,JSON 的数据需要用双引号来包围,不能使用单引号。例如,若使用如下形式表示,则会出现错误:

import json
​
str = '''
[{'name': 'Bob','gender': 'male','birthday': '1992-10-18'
}]
'''
data = json.loads(str)

运行结果如下:

json.decoder.JSONDecodeError: Expecting property name enclosed in double quotes: line 3 column 5 (char 8)

这里会出现 JSON 解析错误的提示。这是因为这里数据用单引号来包围,请千万注意 JSON 字符串的表示需要用双引号,否则 loads 方法会解析失败。

如果从 JSON 文本中读取内容,例如这里有一个 data.json 文本文件,其内容是刚才定义的 JSON 字符串,我们可以先将文本文件内容读出,然后再利用 loads 方法转化:

import json
​
with open('data.json', 'r') as file:str = file.read()data = json.loads(str)print(data)

运行结果如下:

[{'name': 'Bob', 'gender': 'male', 'birthday': '1992-10-18'}, {'name': 'Selina', 'gender': 'female', 'birthday': '1995-10-18'}]
3. 输出 JSON

另外,我们还可以调用 dumps 方法将 JSON 对象转化为字符串。例如,将上例中的列表重新写入文本:

import json
​
data = [{'name': 'Bob','gender': 'male','birthday': '1992-10-18'
}]
with open('data.json', 'w') as file:file.write(json.dumps(data))

利用 dumps 方法,我们可以将 JSON 对象转为字符串,然后再调用文件的 write 方法写入文本,结果如图所示。

另外,如果想保存 JSON 的格式,可以再加一个参数 indent,代表缩进字符个数。示例如下:

with open('data.json', 'w') as file:file.write(json.dumps(data, indent=2))

此时写入结果如图所示。

这样得到的内容会自动带缩进,格式会更加清晰。

另外,如果 JSON 中包含中文字符,会怎么样呢?例如,我们将之前的 JSON 的部分值改为中文,再用之前的方法写入到文本:

import json
​
data = [{'name': ' 王伟 ','gender': ' 男 ','birthday': '1992-10-18'
}]
with open('data.json', 'w') as file:file.write(json.dumps(data, indent=2))

写入结果如图所示。

可以看到,中文字符都变成了 Unicode 字符,这并不是我们想要的结果。

为了输出中文,还需要指定参数 ensure_ascii 为 False,另外还要规定文件输出的编码:

with open('data.json', 'w', encoding='utf-8') as file:file.write(json.dumps(data, indent=2, ensure_ascii=False))

写入结果如图所示。

可以发现,这样就可以输出 JSON 为中文了。

本节中,我们了解了用 Python 进行 JSON 文件读写的方法,后面做数据解析时经常会用到,建议熟练掌握。

CSV 文件存储

CSV,全称为 Comma-Separated Values,中文可以叫作逗号分隔值或字符分隔值,其文件以纯文本形式存储表格数据。该文件是一个字符序列,可以由任意数目的记录组成,记录间以某种换行符分隔。每条记录由字段组成,字段间的分隔符是其他字符或字符串,最常见的是逗号或制表符。不过所有记录都有完全相同的字段序列,相当于一个结构化表的纯文本形式。它比 Excel 文件更加简洁,XLS 文本是电子表格,它包含了文本、数值、公式和格式等内容,而 CSV 中不包含这些内容,就是特定字符分隔的纯文本,结构简单清晰。所以,有时候用 CSV 来保存数据是比较方便的。本节中,我们来讲解 Python 读取和写入 CSV 文件的过程。

1. 写入

这里先看一个最简单的例子:

import csv
​
with open('data.csv', 'w') as csvfile:writer = csv.writer(csvfile)writer.writerow(['id', 'name', 'age'])writer.writerow(['10001', 'Mike', 20])writer.writerow(['10002', 'Bob', 22])writer.writerow(['10003', 'Jordan', 21])

首先,打开 data.csv 文件,然后指定打开的模式为 w(即写入),获得文件句柄,随后调用 csv 库的 writer 方法初始化写入对象,传入该句柄,然后调用 writerow 方法传入每行的数据即可完成写入。

运行结束后,会生成一个名为 data.csv 的文件,此时数据就成功写入了。直接以文本形式打开的话,其内容如下:

id,name,age
10001,Mike,20
10002,Bob,22
10003,Jordan,21

可以看到,写入的文本默认以逗号分隔,调用一次 writerow 方法即可写入一行数据。用 Excel 打开的结果如图所示。

如果想修改列与列之间的分隔符,可以传入 delimiter 参数,其代码如下:

import csv
​
with open('data.csv', 'w') as csvfile:writer = csv.writer(csvfile, delimiter=' ')writer.writerow(['id', 'name', 'age'])writer.writerow(['10001', 'Mike', 20])writer.writerow(['10002', 'Bob', 22])writer.writerow(['10003', 'Jordan', 21])

这里在初始化写入对象时传入 delimiter 为空格,此时输出结果的每一列就是以空格分隔了,内容如下:

id name age
10001 Mike 20
10002 Bob 22
10003 Jordan 21

另外,我们也可以调用 writerows 方法同时写入多行,此时参数就需要为二维列表,例如:

import csv
​
with open('data.csv', 'w') as csvfile:writer = csv.writer(csvfile)writer.writerow(['id', 'name', 'age'])writer.writerows([['10001', 'Mike', 20], ['10002', 'Bob', 22], ['10003', 'Jordan', 21]])

输出效果是相同的,内容如下:

id,name,age
10001,Mike,20
10002,Bob,22
10003,Jordan,21

但是一般情况下,爬虫爬取的都是结构化数据,我们一般会用字典来表示。在 csv 库中也提供了字典的写入方式,示例如下:

import csv
​
with open('data.csv', 'w') as csvfile:fieldnames = ['id', 'name', 'age']writer = csv.DictWriter(csvfile, fieldnames=fieldnames)writer.writeheader()writer.writerow({'id': '10001', 'name': 'Mike', 'age': 20})writer.writerow({'id': '10002', 'name': 'Bob', 'age': 22})writer.writerow({'id': '10003', 'name': 'Jordan', 'age': 21})

这里先定义 3 个字段,用 fieldnames 表示,然后将其传给 DictWriter 来初始化一个字典写入对象,接着可以调用 writeheader 方法先写入头信息,然后再调用 writerow 方法传入相应字典即可。最终写入的结果是完全相同的,内容如下:

id,name,age  
10001,Mike,20  
10002,Bob,22  
10003,Jordan,21

这样就可以完成字典到 CSV 文件的写入了。

另外,如果想追加写入的话,可以修改文件的打开模式,即将 open 函数的第二个参数改成 a,代码如下:

import csv  
​
with open('data.csv', 'a') as csvfile:  fieldnames = ['id', 'name', 'age']  writer = csv.DictWriter(csvfile, fieldnames=fieldnames)  writer.writerow({'id': '10004', 'name': 'Durant', 'age': 22})

这样在上面的基础上再执行这段代码,文件内容便会变成:

id,name,age  
10001,Mike,20  
10002,Bob,22  
10003,Jordan,21  
10004,Durant,22

可见,数据被追加写入到文件中。

如果要写入中文内容的话,可能会遇到字符编码的问题,此时需要给 open 参数指定编码格式。比如,这里再写入一行包含中文的数据,代码需要改写如下:

import csv
​
with open('data.csv', 'a') as csvfile:fieldnames = ['id', 'name', 'age']writer = csv.DictWriter(csvfile, fieldnames=fieldnames)writer.writerow({'id': '10004', 'name': 'Durant', 'age': 22})

这里需要给 open 函数指定编码,否则可能发生编码错误。

另外,如果接触过 pandas 等库的话,可以调用 DataFrame 对象的 to_csv 方法来将数据写入 CSV 文件中。

2. 读取

我们同样可以使用 csv 库来读取 CSV 文件。例如,将刚才写入的文件内容读取出来,相关代码如下:

import csv  
​
with open('data.csv', 'r', encoding='utf-8') as csvfile:  reader = csv.reader(csvfile)  for row in reader:  print(row)

运行结果如下:

['id', 'name', 'age']  
['10001', 'Mike', '20']  
['10002', 'Bob', '22']  
['10003', 'Jordan', '21']  
['10004', 'Durant', '22']  
['10005', ' 王伟 ', '22']

这里我们构造的是 Reader 对象,通过遍历输出了每行的内容,每一行都是一个列表形式。注意,如果 CSV 文件中包含中文的话,还需要指定文件编码。

另外,如果接触过 pandas 的话,可以利用 read_csv 方法将数据从 CSV 中读取出来,例如:

import pandas as pd  
​
df = pd.read_csv('data.csv')  
print(df)

运行结果如下:

      id    name  age  
0  10001    Mike   20  
1  10002     Bob   22  
2  10003  Jordan   21  
3  10004  Durant   22  
4  10005    王伟   22

在做数据分析的时候,此种方法用得比较多,也是一种比较方便地读取 CSV 文件的方法。

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

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

相关文章

Python基于大数据的电影预测分析系统

博主介绍&#xff1a;✌程序员徐师兄、7年大厂程序员经历。全网粉丝30W、csdn博客专家、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战✌ &#x1f345;文末获取源码联系&#x1f345; &#x1f447;&#x1f3fb; 精彩专栏推荐订阅&#x1f447;…

多尺度神经网络新一代创新!精度与速度完美平衡,实现多领域应用落地

多尺度神经网络的设计通常基于对频率原则的理解&#xff0c;目的是为了解决高频成分学习慢的问题。这些网络通过特殊设计&#xff0c;比如给高频成分加更多的权重或者将高频成分平移到低频&#xff0c;来提高学习效率。 为了满足在不同层次上理解和处理数据的需求&#xff0c;…

【Java程序设计】【C00254】基于Springboot的java学习平台(有论文)

基于Springboot的java学习平台&#xff08;有论文&#xff09;&#xff09; 项目简介项目获取开发环境项目技术运行截图 项目简介 这是一个基于Springboot的学习平台 本系统分为系统功能模块、管理员功能模块、教师功能模块以及学生功能模块。 系统功能模块&#xff1a;在平台…

GEE:梯度提升树(Gradient Boosting Tree)回归教程(样本点、特征添加、训练、精度、参数优化)

作者:CSDN @ _养乐多_ 对于分类问题,这个输出通常是一个类别标签 ,而对于回归问题,输出通常是一个连续的数值。回归可以应用于多种场景,包括预测土壤PH值、土壤有机碳、土壤水分、碳密度、生物量、气温、海冰厚度、不透水面积百分比、植被覆盖度等。 本文将介绍在Google…

【Linux学习】线程互斥与同步

目录 二十.线程互斥 20.1 什么是线程互斥&#xff1f; 20.2 为什么需要线程互斥? 20.3 互斥锁mutex 20.4 互斥量的接口 20.4.1 互斥量初始 20.4.2 互斥量销毁 20.4.3 互斥量加锁 20.4.4 互斥量解锁 20.4.5 互斥量的基本原理 20.4.6 带上互斥锁后的抢票程序 20.5 死锁问题 死锁…

React18原理: 核心包结构与两大工作循环

React核心包结构 1 ) react react基础包&#xff0c;只提供定义 react组件(ReactElement)的必要函数一般来说需要和渲染器(react-dom,react-native)一同使用在编写react应用的代码时, 大部分都是调用此包的api比如, 我们定义组件的时候&#xff0c;就是它提供的class Demo ext…

[VulnHub靶机渗透] Nyx

&#x1f36c; 博主介绍&#x1f468;‍&#x1f393; 博主介绍&#xff1a;大家好&#xff0c;我是 hacker-routing &#xff0c;很高兴认识大家~ ✨主攻领域&#xff1a;【渗透领域】【应急响应】 【python】 【VulnHub靶场复现】【面试分析】 &#x1f389;点赞➕评论➕收藏…

2月3日作业

1.编程实现单向循环链表的头插&#xff0c;头删、尾插、尾删 尾插/头插&#xff0c;头删&#xff0c;尾删&#xff1a; 头文件&#xff1a; #ifndef __HEAD_H_ #define __HEAD_H_#include<stdio.h> #include<string.h> #include<stdlib.h>enum {FALSE-1,SU…

Spring Cloud Gateway 网关路由

一、路由断言 路由断言就是判断路由转发的规则 二、路由过滤器 1. 路由过滤器可以实现对网关请求的处理&#xff0c;可以使用 Gateway 提供的&#xff0c;也可以自定义过滤器 2. 路由过滤器 GatewayFilter&#xff08;默认不生效&#xff0c;只有配置到路由后才会生效&#x…

浅谈进制的转换

本文创作灵感来自CSDN咸鱼WCY 的 咸鱼小白学嵌入式之C语言&#xff08;2.进制&#xff09; 博主更完就没更了&#xff0c;决定书接上回&#xff08;喜 进制是个啥 要理解进制&#xff0c;首先哈&#xff0c;咱得知道不同进制的含义 说到底&#xff0c;各个进制其实有点像在…

学生公寓|基于Springboot的学生公寓管理系统设计与实现(源码+数据库+文档)

学生公寓管理系统目录 目录 基于Springboot的学生公寓管理系统设计与实现 一、前言 二、系统功能设计 三、系统实现 1、宿舍列表 2、宿舍公告信息管理 3、宿舍公告类型管理 四、数据库设计 1、实体ER图 五、核心代码 六、论文参考 七、最新计算机毕设选题推荐 八…

学生成绩管理系统|基于Springboot的学生成绩管理系统设计与实现(源码+数据库+文档)

学生成绩管理系统目录 目录 基于Springboot的学生成绩管理系统设计与实现 一、前言 二、系统功能设计 三、系统实现 1、管理员功能模块 2、学生功能模块 3、教师功能模块 四、数据库设计 1、实体ER图 五、核心代码 六、论文参考 七、最新计算机毕设选题推荐 八、源…

AI引领低代码革命:未来应用开发的新主流

距离ChatGPT发布已经过去快一年时间。 在这一年里&#xff0c;以ChatGPT为代表的自然语言处理领域的重大进步&#xff0c;为我们的对话系统和语言交流提供了更加智能和自然的体验。随着ChatGPT的应用不断扩大&#xff0c;人们开始认识到人工智能&#xff08;AI&#xff09;技术…

elasticsearch增删改查

一、数据类型 1、字符串类型 &#xff08;1&#xff09;text &#xff08;2&#xff09;keyword 2、数值类型 &#xff08;1&#xff09;long、integer、short、byte、float、double 3、日期类型 &#xff08;1&#xff09;date 4、布尔类型 &#xff08;1&#xff0…

【AI绘图】初见·小白入门stable diffusion的初体验

首先&#xff0c;感谢赛博菩萨秋葉aaaki的整合包 上手 stable diffusion还是挺好上手的&#xff08;如果使用整合包的话&#xff09;&#xff0c;看看界面功能介绍简单写几个prompt就能生成图片了。 尝试 我在网上找了一张赛博朋克边缘行者Lucy的cos图&#xff0c;可能会侵…

开发自定义标记应用程序

开发自定义标记应用程序 问题陈述 Larry Williams 是ABC Inc.公司的CEO,他希望公司能够拥有一个交互式网站以向访问网站的用户表示问候并显示当前时间。他还希望最终用户能够指定主页的背景颜色。您是公司的网站管理员。Larry要您修改网站的主页,以便向最终用户显示自定义问…

鸿蒙小案例-你画我猜

鸿蒙小案例-你画我猜 1.准备组件(组件布局) 2.实现跟随鼠标画笔画出图案功能 3.实现复制上面的画笔的图案功能 4.其他小功能1.组件的准备 画布的组件官方给的API是Canvas&#xff0c;需要传递一个参数CanvasRenderingContext2D 直接搜索API 使用官方案例 private settings: …

【蓝桥杯Python】试题 算法训练 藏匿的刺客

资源限制 内存限制&#xff1a;256.0MB C/C时间限制&#xff1a;1.0s Java时间限制&#xff1a;3.0s Python时间限制&#xff1a;5.0s 问题描述 强大的kAc建立了强大的帝国&#xff0c;但人民深受其学霸及23文化的压迫&#xff0c;于是勇敢的鹏决心反抗。   kAc帝国防守…

书生谱语-基于 InternLM 和 LangChain 搭建知识库

大语言模型与外挂知识库&#xff08;RAG&#xff09;的优缺点 RAG方案构建与优化 作业 在创建web_demo时&#xff0c;需要根据教程将服务器端口映射到本地端口&#xff0c;另外需要将链接的demo从服务器中复制出来&#xff0c;不要直接从服务器打开demo页面&#xff0c;不然会…

分布式事务详解

概述 随着互联网的发展&#xff0c;软件系统由原来的单体应用转变为分布式应用。分布式系统把一个单体应用拆分为可独立部署的多个服务&#xff0c;因此需要服务与服务之间远程协作才能完成事务操作。这种分布式系统下不同服务之间通过远程协作完成的事务称之为分布式事务&…