第三节Python数据结构操作
1.列表(List)
- 有序性:按照特定的顺序排列
可变性:可以修改、添加或删除,长度动态变化
元素多样性:任意数据类型
支持切片操作
示例
包含不同类型的列表
mixed_list=[1,"hello",3.14,True,[1,2,3]]添加元素
a=[1,2,3,4] a.append(5) print(a) >>>[1,2,3,4,5]切片
a=[1,2,3,4] print(a[:3]) >>>[1,2,3](1)创建列表
- 创建空列表
empty_list=[] print(empty_list) >>>[]
- 创建整数列表
integer_list=[1,2,3,4,5] print(integer_list) >>>[1,2,3,4,5]
(2)访问列表元素
fruits=['apple','banana','cherry','date'] first_fruits=fruits[0] print(first_fruit) >>>apple third_fruit=fruits[2] print(third_fruits) >>>cherry(3)修改列表元素
fruits=['apple','banana','cherry','date'] fruits=[1]='orange' print(fruits) >>>['apple','orange','cherry','date'](4)增删操作
- append()
- insert()
- remove()
- pop()
- del关键字
fruits=['a','b','c'] fruits.append('d') print(fruits) >>>['a','b','c','d'] fruits.insert(1,'f') print(fruits) >>>['a','f','b','c','d'] fruits.remove('b') print(fruits) >>>['a','f','c','d'] a=fruits.pop(1) print(a) >>>'f' print(fruits) >>>['a','c','d'] del fruits[1] print(fruits) >>>['c','d'](5)列表切片与遍历
a=[1,2,3,4,5] for i in a: print(i) >>>1 2 3 4 5 sliced_a=a[1:3] print(sliced_a) >>>[2,3] sliced_a_from_2=a[2:] print(sliced_a_from_2) >>>[3,4,5] sliced_a_jiange=a[::2] print(sliced_a_jiange) >>>[1,3,5] for i in sliced_a: print(i) >>>2 3 sliced_a[0]=0 print(sliced_a) >>>[0,3] print(a) >>>[1,2,3,4,5]2.元组(Tuple)
- 不可变性
- 元组是静态的,一旦创建不可更改
(1)创建与访问元组元素
student_info=("张三",20,90) name=student_info[0] age=student_info[1] score=student_info[2] print("姓名:"+name) print("年龄:+age) print("成绩:"+score) >>>姓名:张三 年龄:20 成绩:903.字典(Dictionary)
(1)创建字典
my_dict={ "name":"Alice", "age":30, "city":"New York" }(2)访问字典键值对
print(my_dict["name"]) print(my_dict["age"]) >>>Alice >>>30 print(my_dict.get("address","No address provided")) >>>No address provided(3)修改字典内容
my_dict["age"]=31 my_dict["country"]="USA" print(my_dict["age"]) >>>31 print(my_dict["country"]) >>>USA(4)删除字典元素
del my_dict["city"] value=my_dict.pop("age") print(value) >>>30(5)字典的遍历
for key in my_dict: print(key) >>>name age city for value in my_dict.values(): print(value) >>>Alice 30 New York for key,value in my_dict.items(): print(key,value) >>>name Alice age 30 city New York文件读写与异常处理
1.文件的基本操作
(1)打开文件
file=open('example','r') file=open('example','w') file=open('example','a')注意文件的编码方式,在open()函数,可以使用encoding参数来指定编码方式,如encoding='utf-8'
(2)读取文件内容
with open('example.txt','r')as file: content=file.read() print(content) with open('example.txt','r')as file: line=file.readline() print(line) with open('example.txt','r')as file: lines=file.readlines()(3)写入文件内容
with open('example.txt','w')as file: file.write('Hello,world!\n') file.write('This is a new line.\n')(4)关闭文件
file=open('example.txt','r') content=file.read() file.close()| 方法 | 描述 |
| open() | 打开文件并返回对象 |
| read() | 读取文件全部内容并返回字符串 |
| readline() | 读取文件的一行并返回字符串 |
| readlines() | 读取文件所有行并返回字符串列表 |
| write() | 将字符串写入文件 |
| close() | 关闭文件 |
2.异常处理
(1)try-except语句的使用
try: ..... except ExceptionType:(2)常见的文件操作异常及处理方法
| 异常类型 | 描述 | 触发条件 | 处理方法 |
| FileNotFoundError | 当尝试打开不存在的文件时触发 | 尝试访问的文件名或路径不正确;文件已被删除 | 检查文件名和路径是否正确;确认文件是否存在 |
| PermissionError | 当尝试执行没有足够权限的操作时是否触发,如读取或写入文件 | 文件或目录的权限设置不允许当前用户执行操作 | 检查文件或目录的权限设置;使用具有适当权限的用户执行操作 |
| IOError或OSError | 这是一个通用的输入/输出异常,涵盖了多种I/O相关的错误,包括文件操作错误。在Python3中,IOError已经被OSError取代 | 涉及输入/输出操作的多种错误,如设备错误、无效的打开模式等 | 检查代码中的文件操作逻辑;确保文件操作正确无误;捕获OSError或IOError并根据具体情况处理 |
| UnicodeDecodeError | 当尝试以错误的编码方式读取文件时触发 | 文件内容的编码方式与读取时使用的编码方式不匹配 | 确认文件的正确编码方式;在读取文件时指定正确的编码 |
| 异常类型 | 描述 |
| AttributeError | 当尝试访问对象不存在的属性时触发 |
| KeyError | 在字典操作中,当尝试访问不存在的键时触发 |
| IndexError | 在列表、元组或字符串等序列类型中,当尝试访问不存在的索引时触发 |
| TypeError | 当操作或函数应用于错误类型的对象时触发。例如,尝试将整数和字符串相加 |
| NameError | 当 Python 解释器遇到未定义的变量名时触发 |
| SyntaxError | 当 Python 解释器发现程序中有语法错误时触发 |
| ValueError | 当一个操作或函数接收到一个具有正确类型但值不合适的参数时触发。例如,将非数字字符串传递给需要整数的函数 |
| ZeroDivisionError | 当尝试除以零时触发 |
| StopIteration | 当迭代器没有更多的值可供迭代时触发,通常在使用 for 循环或 next() 函数时遇到 |
| EOFError | 当输入操作到达文件结束符(EOF)但没有更多的数据可读时触发 |
try: with open('example.txt''r')as file: content=file.read() except Fil eNotFoundError:#处理文件不存在的异常 print("文件不存在,请检查文件名和路径是否正确。) except UnicodeDe codeError:#处理编码错误 print("文件编码错误,请尝试使用正确的编码方式打开文件。) except PermissionE rror:#处理权限不足 print(文件权限不足”) except Exception as e:#处理所有异常 Print("发生了一个处理所有异常异常:(e}") >>>发生了一个处理所有异常异常:这是一个自定义错误,演示如何触发except Exception3.常用的数据处理库的使用
- 使用np.arayO 的数从 Python 列表或元组创建数组
- 使用np.zeros0函数创建指定大小的零数组
- 使用np.onesO函数创建指定大小的1数组
- 使用np.arange0的数创建指定范围的数组
- 使用np.random.rand0函数创建指定大小的随机数组
(1)创建Numpy数组
mport numpy as np arr= np.array([1,2, 3,4, 5J) print(arr) zeros arr= np. zeros(5) print(zeros arr) ones arr= np.ones((33)) print (ones_arr) random arr = np. random. rand(4 4) print(random arr) >>>[1234 5] >>>[0.0.0.0.0.}] >>>[[1.1.1.〕 [1. 1. 1.] [1.1. 1.]] >>>[0.92691172 0471985650.887010750.89931924] [0.93173798 0.911536060.076108490.21844905] [0.937607410.486040020.655788310.31877502] [0.862368870.055238760.606765960.90048091]](2)数组的基本运算
arrl= np.array([1, 2,3,4,5]) arr2= np.array([5,4,3, 2, 1]) #加法 add result= arr1 + arr2 print(add result) #减法 sub result=arrl - arr2 print(sub result) #乘法 mul result= arrl * arr2 print(mul result) #除法 div result = arrl/ arr2 print (div result) >>>[6 6 6 6 6] >>>[-4-2 024J >>>[5898 5] >>>[0.2 0.5 1. 2.5.](3)数组的形状变化
arr= np.arange(6) print("原始数组:", arr) reshaped arr = arr.reshape(2,3) >>>原始数组:[0 1 2 3 4 5] >>>改变形状后的数组: [[O 1 2] [3 4 5]](4)数组的统计与排序
| 函数 | 解析 |
| np.mean() | 计算数组中所有元素的平均值。 该函数接收一个数组作为输人,并返回该数组中所有元素的平均值。如果数组是多维的,并且没有指定axis参数,那么它将计算整个数组的平均值。如果指定了axis参数,那么它将沿着指定的轴计算平均值 |
| np.sum() | 计算数组中所有元素的和。 与mp.mean0类似,它也接收一个数组作为输入,并返回该数组中所有元素的和。同样,可以通过axis参数来沿着特定轴计算元素的和 |
| np.std() | 计算数组中所有元素的标准差。标准差是衡量数据集中数值分散程度的一个统计量。 该函数接收一个数组作为输人,并返回该数组中所有元素的标准差。默认情况下, ddof参数为1,意味着在计算标准差时,分母是 N-1(其中N是元素的数量)这是为了进行样本标准差的无偏估计。如果ddof设置为0,则分母为N,这对应于总体标准差。同样,可以通过axis参数来沿着特定轴计算标准差 |
| np.sort() | 对数组中的元素进行排序。 该函数接收一个数组作为输人并返回一个新的排序后的数组。默认情况下,排序是升序的。可以通过axis参数来沿着特定轴对多维数组进行排序。此外,kind参数允许用户选择不同的排序算法(如快速排序、归并排序、堆排序等),而order参数则用于指定当数组是结构化数组时,应该按照哪个字段进行排序 |
import numpy as np arr = np. array([3, 1,4, 1, 5, 9,2, 6,5,3, 5]) #求平均值 mean value= np.mean(arr) print(”平均值:”, mean value) #求和 sum value= np.sum(arr) Print("和:", sum value) #求标准差 std_ value=np.std(arr) print("标准差:", std value) #排序 sorted arr = np.sort (arr) Print("排序后的数组:“", sorted_arr) >>>平均值:4.0 >>>和:44 >>>标准差:2.256304299271065 >>>排序后的数组:[1 1 2 3 3 4 5 5 6 9](5)Numpy切片操作
arry[start:stop:step]arr_ la= np.array([0, 1,2,3,4,5,6,7,8,9]) slice1d = arr_1d[1:5] print(sliceLa_1d) slice ld step=arr_ld[::2] print(slice 1d step) >>>[1234] >>>[02468]使用copy方法创建切片的副本
slice 2d copy=slice_2d.copy() slice 2d copy[O,0]=200 print (slice2d_copy) print(arr 2d) >>>[[200 4] [ 6 7]] >>>[[0 1 2] [ 3 4 5] [6 7 8] [9 10 11]](6)省略切片索引
slice start omitted=arr 2d[1:,:] print (slice start omitted) slice end omitted一 arr 2d[::2] print (slice end omitted) slice step omitted= arr_2d[::] print (slice step omitted) >>>[[ 3 4 5] [67 8] [9 10 11]] >>>[[ 0 1] [ 3 4] [6 7] [9 10]] >>>[[0 1 2] [ 3 4 5] [6 7 8] [9 10 11]]2.读取Titanic数据集
titanic_df=pd.read_csv('titanic.csv') print(titanic_df.head())(1)数据分析
print(titanic_df.info())(2)描述性统计
print(titanic_df.describe())(3)唯一值
print(titanic_df['Sex'].unique())(4)处理缺失值
titanic_df_no_na=titanic_df.dropna() titanic_df['Age'].fillna(titanic_df['Age'].median(),inplace=True)(5)数据类型转换
titanic_df['Sex']=titanic_df['Sex'].astype('category')(7)数据筛选
female_passengers=titanic_df[titanic_df['Sex']=='female'] survived_passengers=titanic_df[titanic_df['Survived']==1](8)分组聚合
survival_by_sex=titanic_df.groupby('Sex')['Survived'].sum() print(survival_by_sex)(9)数据可视化
import matplotlib.pyplot as plt plt.figure (figsi ze=(10,8)) survival_by_sex.plot(kind='bar') plt.tit Le('Survival by Sex') plt.xlabel('Sex') plt ylabel('Number of Survived') plt.show()数据采集及存储
数据的存储
(1)文本文件读取
daa={ "id":"123456", "name":"张三", "age":2 } with open('data.txt','w',encodind='utf-8')as file: for key in data.key(): file.write(str(key)+":"+str(data[key])+'\n') with open('data.txt','r',encoding='utf-8')as file: lines=file.readline() for line in lines: print(liine.strip())CSV文件读写
import csv data = [ ["张三", "14 岁", "男"], ["李四", "15 岁", "男"], ["王一", "16 岁", "女"] ] with open('user_data.csv', 'w', newline='', encoding='utf-8') as file: writer = csv.writer(file) writer.writerow(["姓名", "年龄", "性别"]) writer.writerows(data) with open('user_data.csv', 'r', encoding='utf-8') as file: reader = csv.reader(file) for row in reader: print(row)JSON文件
import json data = [ {"name": "张三", "age": "14", "sex": "男"}, {"name": "李四", "age": "15", "sex": "男"}, {"name": "王一", "age": "14", "sex": "女"} ] with open('data.json', 'w', encoding='utf-8') as file: json.dump(data, file, ensure_ascii=False, indent=4) with open('data.json', 'r', encoding='utf-8') as file: data = json.load(file) for item in data: print(item)数据库的连接和使用
- 开源
- 跨平台
- 高性能
- 安全性
- 可扩展性
(1)基本操作
CREATE DATABASE my_database; SHOW DATABASES; USE my_database; DROP DATABASE my_database; CREATE TABLE news ( id INT AUTO_INCREMENT PRIMARY KEY, title VARCHAR(255) NOT NULL, link VARCHAR(255) NOT NULL, date DATE NOT NULL ); DESCRIBE news; ALTER TABLE news ADD author VARCHAR(255); DROP TABLE news; INSERT INTO news (title, link, date) VALUES ('新闻标题 1', 'http://example.com/1', '2024-06-08'); SELECT * FROM news WHERE date = '2024-06-07'; UPDATE news SET title = '更新后的新闻标题 1' WHERE id = 1; DELETE FROM news WHERE id = 2;(2)连接MySQL数据库
imprort mysql.connector conn =mysql.connector.connect( host='localhost', user='root', password='123456', database='news' ) cursor=conn.cursor()(3)执行SQL操作
cursor.execute("CREATE DATABASE IF NOT EXISTS my_database") cursor.execute("USE my_database") cursor.execute(''' CREATE TABLE IF NOT EXISTS news ( id INT AUTO_INCREMENT PRIMARY KEY, title VARCHAR(255) NOT NULL, link VARCHAR(255) NOT NULL, date DATE NOT NULL ) ''') #插入数据 insert_query = ''' INSERT INTO news (title, link, date) VALUES (%s, %s, %s) ''' data = [ ("新闻标题 1", "http://example.com/1", "2024-06-08"), ("新闻标题 2", "http://example.com/2", "2024-06-07"), ("新闻标题 3", "http://example.com/3", "2024-06-06") ] cursor.executemany(insert_query, data) conn.commit() #查询数据 cursor.execute("SELECT * FROM news") rows = cursor.fetchall() for row in rows: print(row) #更新数据 update_query = ''' UPDATE news SET title = %s WHERE id = %s ''' cursor.execute(update_query, ("更新后的新闻标题1", 1)) conn.commit() 删除数据 delete_query = ''' DELETE FROM news WHERE id = %s ''' cursor.execute(delete_query, (2,)) conn.commit() 删除表 cursor.execute("DROP TABLE IF EXISTS news") 关闭游标和连接 cursor.close() conn.close()Python爬虫和数据采集技术
(1)分类
- 通用爬虫
- 聚焦爬虫
- 增量爬虫
- 深度爬虫
(2)网络爬虫基本流程
- URL种子
- 发送请求
- 解析响应
- 提取数据
- 存储数据
- 发现新链接
- 重复上述步骤
requests
| 方 法 | 说 明 |
| requests.request() | 构造一个请求,支撑以下各方法的基础方法 |
| requests.get() | 获取 HTML 网页的主要方法,对应于 HTTP 的 get |
| requests.head() | 获取 HTML 网页头信息的方法,对应于 HTTP 的 head |
| requests.post() | 向 HTML 网页提交 post 请求的方法,对应于 HTTP 的 post |
| requests.put() | 向 HTML 网页提交 put 请求的方法,对应于 HTTP 的 put |
| requests.patch() | 向 HTML 网页提交局部修改请求,对应于 HTTP 的 patch |
| requests.delete() | 向 HTML 页面提交删除请求,对应于 HTTP 的 delete |
| 属 性 | 说 明 |
| r.status_code | HTTP 请求的返回状态,200 表示连接成功,404 表示失败 |
| r.text | HTTP 响应内容的字符串形式,即 url 对应的页面内容 |
| r.renoding | 从 HTTP header 中猜测的响应内容编码方式 |
| r.apparent_encoding | 从内容中分析出的响应内容编码方式(备选编码方式) |
| r.content | HTTP 响应内容的二进制形式 |
import requests def getHtml(): url = 'https://www.ynjtc.edu.cn' # 网页链接 r = requests.get(url) #status_code 为 200 表示请求成功 if r.status_code == 200: content = r.content.decode(); print(content) else: print(f"获取信息失败:{r.status_code}") #调用方法执行请求 if __name__ == '__main__': getHtml()BeautifulSoup解析工具
| 解析器 | 使用方法 | 优点 | 劣势 |
| Python 标准库 | BeautifulSoup(markup, "html.parser") | Python 的内置标准库、执行速度适中、文档容错能力强 | Python 2.7.3 及 Python 3.2.2 之前的版本文档容错能力差 |
| lxml HTML 解析器 | BeautifulSoup(markup, "lxml") | 速度快、文档容错能力强 | 需要安装 C 语言库 |
| lxml XML 解析器 | BeautifulSoup(markup, "xml") | 速度快、唯一支持 XML 的解析器 | 需要安装 C 语言库 |
| html5lib | BeautifulSoup(markup, "html5lib") | 最好的容错性、以浏览器的方式解析文档、生成 HTML5 格式的文档 | 速度慢、不依赖外部扩展 |
创建BeautifulSoup对象
from bs4 import Beautifulsoup html=""<ulclass-"clearfix lavalamp"> <div class=" lavalamp-object"id="nav"></div> <liid-"first"class="navitem-index Current"><ahref="/index" class=red>首页</a ></1i> <liclass="lavalamp-i tem"<a href=" ">国内</a ></(Ii> <liclass=" lavalamp-item"><ahref=" guoji">国际</a ><(1i> <1iclass="1avalamp-item"<a href=/mil">军事</a ></1i> <liclass="lavalamp-item"><a href="/finance">财经< a></li> <liclass="l avalamp-item"<a href=="/ent">娱乐</a ></1i> <1iclass-"lavalamp-item"><a href="/internet">互联网</a ></1i> </u]>"#” #解析并获取 Beautifulsoup 对象 soup-Beauti fulSoup(html,"1xml")| 基本元素 | 描述 |
| Tag | 标签,最基本的信息组织单元,分别用<>和</>标明开头和结尾 |
| Name | 标签的名字,<p>...</p>的名字是'p',格式:<tag>.name |
| Attributes | 标签的属性,字典形式组织,格式:<tag>.attrs |
| NavigableString | 标签内非属性字符串,<>...</>中字符串,格式:<tag>.string |
| Comment | 标签内字符串的注释部分,一种特殊的 Comment 类型 |
选择首页的li标签
# 选择 li 标签 print(soup.li) # 输出结果 <li class="navitem-index current"><a class="red" href=" "> 首页 </a ></li> # 如果想要获取此标签的内容,可以使用 soup.li.string print(soup.li.string) # 输出结果 首页 # 如果想要获取首页 li 标签中的 a 标签属性,可以使用 soup.li.a.attrs print(soup.li.a.attrs) # 输出结果 {'href': '/index', 'class': ['red']} # 如果想要获取如果想要获取首页 li 标签中的 a 标签属性中的 href 属性 # 可以使用 soup.li.a.attrs['href'] print(soup.li.a.attrs['href']) # 输出结果 /index| 属性名 | 值 |
| contents | 获取所有的子节点,返回的是一个列表 |
| children | 获取所有的子节点,返回的是一个生成器类型 |
| descendants | 获取所有的子孙节点 |
| parent | 获取某个元素的父节点 |
| parents | 获取所有的祖节点,返回的是一个生成器类型 |
| next_sibling | 获取节点的下一个兄弟节点 |
| previous_sibling | 获取节点的上一个兄弟节点 |
| next_siblings | 获取节点后所有的兄弟节点,返回类型是生产器 |
| previous_siblings | 获取节点前所有的兄弟节点,返回类型是生产器 |
常用方法选择函数
| 方 法 | 描 述 |
| find_all() | 返回所有符合条件的元素 |
| find() | 返回第一个匹配的元素 |
| find_parents()/find_parent() | 返回所有祖先节点 / 返回直接的父节点 |
| find_next_siblings()/find_next_sibling() | 返回后面所有的兄弟节点 / 返回后面第一个兄弟节点 |
| find_previous_siblings()/find_previous_sibling() | 返回前面所有的兄弟节点 / 返回前面第一个兄弟节点 |
| find_all_next()/find_next() | 返回节点后所有符合条件节点 / 返回第一个符合条件节点 |
scrapy框架
from itemadapter import ItemAdapter import pymysql class MyprojectPipeline: def open_spider(self, spider): # 设置数据库连接 self.connection = pymysql.connect( host='localhost', port=3306, user='root', password='123456', db='news', charset='utf8mb4', cursorclass=pymysql.cursors.DictCursor ) self.cursor = self.connection.cursor() def close_spider(self, spider): self.connection.close() def process_item(self, item, spider): # 将数据插入到数据库中 self.cursor.execute( "INSERT INTO t_news (title, url, date) VALUES (%s, %s, %s)", (item['title'], item['url'], item['date']) ) self.connection.commit() return item