python数据分析笔记

Pycharm的常用快捷键

•tab:代码自动补全

•Ctrl + D 复制选定的区域或行到后面或下一行

•Ctrl + Space 基本的代码完成(类、方法、属性)

•Ctrl + Alt + Space 快速导入任意类

•Ctrl+F 搜索

•Ctrl+R 替换

•Ctrl+G 寻找

•Ctrl + Shift + Enter 语句完成

•Ctrl + P 参数信息(在方法中调用参数)

•Ctrl + Q 快速查看文档

•Ctrl + 鼠标 简介

•Alt + Insert 自动生成代码

•Ctrl + W 选中增加的代码块

•Ctrl + Shift + W 回到之前状态

•Ctrl + Shift + ]/[ 选定代码块结束、开始

•Alt + Enter 快速修正

•Ctrl + Alt + L 代码格式化

•Shift + F10 运行

•Shift + F9 调试

•Ctrl + Alt + O 自动导入

•Ctrl + Alt + I 自动缩进

•Shift + F1 外部文档

•Ctrl + F1 显示错误描述或警告信息

Pycharm最全常用快捷键总结_pycharm便捷操作-CSDN博客

迭代器

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# 创建一个列表
my_list = [1, 2, 3, 4]

# 获取迭代器
my_iter = iter(my_list)

# 使用 next() 函数遍历元素
print(next(my_iter)) # 输出: 1
print(next(my_iter)) # 输出: 2
print(next(my_iter)) # 输出: 3
print(next(my_iter)) # 输出: 4

# 再次调用 next() 会引发 StopIteration 异常
# print(next(my_iter)) # 引发 StopIteration

for循环遍历

1
2
3
4
5
6
7
8
9
10
11
#!/usr/bin/python3

# 创建一个列表
list = [1, 2, 3, 4]

# 创建迭代器对象
it = iter(list)

# 使用 for 循环遍历迭代器
for x in it:
print(x, end=" ")

next函数

1
2
3
4
5
6
7
8
9
10
11
#!/usr/bin/python3
import sys # 引入 sys 模块

list = [1, 2, 3, 4]
it = iter(list) # 创建迭代器对象

while True:
try:
print(next(it))
except StopIteration:
sys.exit()

生成器

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# 定义一个生成器函数
def countdown(n):
while n > 0:
yield n
n -= 1

# 创建生成器对象
generator = countdown(5)

# 使用 next() 获取值
print(next(generator)) # 输出: 5
print(next(generator)) # 输出: 4
print(next(generator)) # 输出: 3

# 使用 for 循环遍历生成器
for value in generator:
print(value, end=" ") # 输出: 2 1

匿名函数lambda

1
lambda 参数1, 参数2, ... : 表达式
  • **lambda**:定义匿名函数的关键字。
  • 参数:可以有一个或多个参数,用逗号分隔。
  • 表达式:函数的返回值,只能是一个表达式,不能包含复杂的逻辑或多行代码。

基本用法

1
2
3
4
5
# 定义一个匿名函数,计算两个数的和
add = lambda x, y: x + y

# 调用匿名函数
print(add(3, 5)) # 输出: 8

网络协议基础

HTTP状态码

类别原因短语
1XXInformational(信息性状态码)接收的请求正在处理
2XXSuccess(成功状态码)请求正常处理完毕
3XXRedirection(重定向状态码)需要进行附加操作以完成请求
4XXClient Error(客户端错误状态码)服务器无法处理请求
5XXServerError(服务器错误状态码)服务器处理请求出错

URL(统一地址访问符)

•超文本传输协议(HTTP)的统一资源定位符将从因特网获取信息的五个基本元素包括在一个简单的地址中:

传送协议。 层级URL标记符号(为[//],固定不变) 访问资源需要的凭证信息(可省略) 服务器。(通常为域名,有时为IP地址)

端口号。(以数字方式表示,若为HTTP的默认值“:80”可省略) 路径。(以“/”字符区别路径中的每一个目录名称)

查询。(GET模式的窗体参数,以“?”字符为起点,每个参数以“&”隔开,再以“=”分开参数名称与数据,通常以UTF8的URL编码,避开字符冲突的问题)

片段。以“#”字符为起点

request

请求格式

requests.get/post(url,params,data,headers,timeout,verify,allow_redirects,cookies)
url:要下载的目标网页的URL
params:字典形式,设置uRL后面的参数,比如?id=123&name=xiaoming
data:字典或者字符串,一般用于pOST方法时提交数据
headers:设置user-agent、refer等请求头
timeout:超时时间,单位是秒
verify:True/False,否进行HTTPs证书验证,默认是,需要自已设置证书地址
allow_redirects:True/False是否让requests做重定向处理,默认是
cookies:附带本地的cookies数据

get返回网页内容

1
2
3
4
import requests
x = requests.get("https://www.runoob.com")
print(x.status_code)
print(x.text)

post() 发送 POST 请求到指定 url

requests.post(url, data={key: value}, json={key: value}, args)

•url 请求 url。

•data 参数为要发送到指定 url 的字典、元组列表、字节或文件对象。

•json 参数为要发送到指定 url 的 JSON 对象。

args 为其他参数,比如 cookies、headers、verify等

1
2
3
4
5
6
# 导入 requests 包
import requests
# 发送请求
x = requests.post('https://www.runoob.com/try/ajax/demo_post.php')
# 返回网页内容
print(x.text)

BeautifulSoup

创建 Beautiful Soup 对象

bs4 import BeautifulSoup
1
2
3
4
5
6
7
from bs4 import BeautifulSoup
#根据HTML网页字符串创建BeautifulSoup对象
soup = BeautifulSoup(
html_doc, #HTML文档字符串
'html.parser', #HTML解析器
from_encoding='utf8' #HTML文档的编码
)

访问节点信息

·通常是通过URL来定位节点并进行访问
得到节点:<a href='1.html'>Python</a>

1
2
3
4
5
6
#获取查找到的节点的标签名称
node.name
#获取查找到的a节点的href属性
node['href']
#获取查找到的a节点的链接文字
node.get_text()

对象

Tag:HTML 标签加上里面包括的内容就是 Tag
NavigableString:获取标签内部的文字

操作

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
from bs4 import BeautifulSoup
with open("./test.html") as fin:
html_doc=fin.read()

soup=BeautifulSoup(html_doc,"html.parser")

div_node=soup.find("div"id="content")
print(div_node)

print("#"*30)

links=div_node.find_all("a")
for link in links:
print(link.name,link["href"],link.get_textO)
img=div_node.find("img")

正则表达式

正则表达式(Regular Expression,简称 regexregexp)是一种用于匹配和处理文本的强大工具。它通过定义特定的模式,可以快速搜索、替换或提取字符串中的内容。正则表达式在文本处理、数据验证、日志分析等场景中非常常用。

1. 普通字符

普通字符(如字母、数字)会直接匹配自身。

  • 示例:
    • 正则表达式 hello 可以匹配字符串 "hello"

2. 元字符

元字符是正则表达式中具有特殊含义的字符。常见的元字符包括:

元字符 描述
. 匹配任意单个字符(除了换行符 \n)。
^ 匹配字符串的开头。
$ 匹配字符串的结尾。
* 匹配前面的字符 0 次或多次。
+ 匹配前面的字符 1 次或多次。
? 匹配前面的字符 0 次或 1 次。
\d 匹配数字(等价于 [0-9])。
\D 匹配非数字字符。
\w 匹配字母、数字或下划线(等价于 [a-zA-Z0-9_])。
\W 匹配非字母、数字或下划线的字符。
\s 匹配空白字符(包括空格、制表符、换行符等)。
\S 匹配非空白字符。
[] 匹配括号内的任意一个字符。例如 [abc] 匹配 abc
` `
() 分组,将多个字符作为一个整体进行处理。

3. 量词

量词用于指定字符的匹配次数。

量词 描述
{n} 匹配前面的字符恰好 n 次。
{n,} 匹配前面的字符至少 n 次。
{n,m} 匹配前面的字符 n 到 m 次。

4. 转义字符

如果需要匹配元字符本身,可以使用反斜杠 \ 进行转义。

  • 示例:
    • 匹配 . 字符:\.
    • 匹配 * 字符:\*

示例

1. 匹配邮箱地址
1
[\w\.-]+@[\w\.-]+\.\w+
  • 解释:
    • [\w\.-]+:匹配用户名部分(字母、数字、点、下划线、横线)。
    • @:匹配邮箱中的 @ 符号。
    • [\w\.-]+:匹配域名部分。
    • \.\w+:匹配顶级域名(如 .com.cn)。
2. 匹配手机号码
1
1[3-9]\d{9}
  • 解释:
    • 1:手机号码以 1 开头。
    • [3-9]:第二位是 3 到 9 之间的数字。
    • \d{9}:后面跟着 9 位数字。
3. 匹配 URL
1
https?://[\w\.-]+\.[a-zA-Z]+
  • 解释:
    • https?:匹配 httphttps
    • ://:匹配 ://
    • [\w\.-]+:匹配域名部分。
    • \.[a-zA-Z]+:匹配顶级域名。
4. 匹配日期(YYYY-MM-DD)
1
\d{4}-\d{2}-\d{2}
  • 解释:
    • \d{4}:匹配 4 位年份。
    • -:匹配分隔符 -
    • \d{2}:匹配 2 位月份和日期。

Python 中的正则表达式

Python 通过 re 模块支持正则表达式。以下是常用的方法:

1. re.match()

从字符串开头匹配正则表达式。

1
2
3
4
5
6
7
8
9
10
import re

pattern = r"hello"
text = "hello world"
result = re.match(pattern, text)

if result:
print("匹配成功:", result.group())
else:
print("匹配失败")

在字符串中搜索匹配正则表达式的第一个位置。

1
2
3
4
5
6
7
8
9
10
import re

pattern = r"world"
text = "hello world"
result = re.search(pattern, text)

if result:
print("匹配成功:", result.group())
else:
print("匹配失败")
3. re.findall()

返回所有匹配的结果列表。

re.findall(pattern, string, flags=0)
patten:匹配的正则表达式
string:要匹配的字符串。
flags:标志位,用于控制正则表达式的匹配方式,如:是否区分大小写,多行匹配等等。

flags可选值如下
re.l使匹配对大小写不敏感
re.L做本地化识别(locale-aware)匹配
re.M多行匹配,影响^和$
re.s使.匹配包括换行在内的所有字符
re.U根据Unicode字符集解析字符。这个标志影响\w,\W,\b,\B.
re.X该标志通过给予你更灵活的格式以便你将正则表达式写得更易于理解。

1
2
3
4
5
6
7
import re

pattern = r"\d+"
text = "我有 3 只猫和 5 只狗"
result = re.findall(pattern, text)

print("匹配结果:", result) # 输出: ['3', '5']

爬取代码示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
# -*- codeing = utf-8 -*-
from bs4 import BeautifulSoup # 网页解析,获取数据
import re # 正则表达式,进行文字匹配`
import urllib.request, urllib.error # 制定URL,获取网页数据
import xlwt # 进行excel操作
#import sqlite3 # 进行SQLite数据库操作

findLink = re.compile(r'<a href="(.*?)">') # 创建正则表达式对象,标售规则 影片详情链接的规则
findImgSrc = re.compile(r'<img.*src="(.*?)"', re.S)
findTitle = re.compile(r'<span class="title">(.*)</span>')
findRating = re.compile(r'<span class="rating_num" property="v:average">(.*)</span>')
findJudge = re.compile(r'<span>(\d*)人评价</span>')
findInq = re.compile(r'<span class="inq">(.*)</span>')
findBd = re.compile(r'<p class="">(.*?)</p>', re.S)

def main():
baseurl = "https://movie.douban.com/top250?start=" #要爬取的网页链接
# 1.爬取网页
datalist = getData(baseurl)
savepath = "豆瓣电影Top250.xls" #当前目录新建XLS,存储进去
# dbpath = "movie.db" #当前目录新建数据库,存储进去
# 3.保存数据
saveData(datalist,savepath) #2种存储方式可以只选择一种
# saveData2DB(datalist,dbpath)

# 爬取网页
def getData(baseurl):
datalist = [] #用来存储爬取的网页信息
for i in range(0, 10): # 调用获取页面信息的函数,10次
url = baseurl + str(i * 25)
html = askURL(url) # 保存获取到的网页源码
# 2.逐一解析数据
soup = BeautifulSoup(html, "html.parser")
for item in soup.find_all('div', class_="item"): # 查找符合要求的字符串
data = [] # 保存一部电影所有信息
item = str(item)
link = re.findall(findLink, item)[0] # 通过正则表达式查找
data.append(link)
imgSrc = re.findall(findImgSrc, item)[0]
data.append(imgSrc)
titles = re.findall(findTitle, item)
if (len(titles) == 2):
ctitle = titles[0]
data.append(ctitle)
otitle = titles[1].replace("/", "") #消除转义字符
data.append(otitle)
else:
data.append(titles[0])
data.append(' ')
rating = re.findall(findRating, item)[0]
data.append(rating)
judgeNum = re.findall(findJudge, item)[0]
data.append(judgeNum)
inq = re.findall(findInq, item)
if len(inq) != 0:
inq = inq[0].replace("。", "")
data.append(inq)
else:
data.append(" ")
bd = re.findall(findBd, item)[0]
bd = re.sub('<br(\s+)?/>(\s+)?', "", bd)
bd = re.sub('/', "", bd)
data.append(bd.strip())
datalist.append(data)

return datalist

# 得到指定一个URL的网页内容
def askURL(url):
head = { # 模拟浏览器头部信息,向豆瓣服务器发送消息
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/132.0.0.0 Safari/537.36 Edg/132.0.0.0"
}
# 用户代理,表示告诉豆瓣服务器,我们是什么类型的机器、浏览器(本质上是告诉浏览器,我们可以接收什么水平的文件内容)

request = urllib.request.Request(url, headers=head)
html = ""
try:
response = urllib.request.urlopen(request)
html = response.read().decode("utf-8")
except urllib.error.URLError as e:
if hasattr(e, "code"):
print(e.code)
if hasattr(e, "reason"):
print(e.reason)
return html


# 保存数据到表格
def saveData(datalist,savepath):
print("save.......")
book = xlwt.Workbook(encoding="utf-8",style_compression=0) #创建workbook对象
sheet = book.add_sheet('豆瓣电影Top250', cell_overwrite_ok=True) #创建工作表
col = ("电影详情链接","图片链接","影片中文名","影片外国名","评分","评价数","概况","相关信息")
for i in range(0,8):
sheet.write(0,i,col[i]) #列名
for i in range(0,250):
# print("第%d条" %(i+1)) #输出语句,用来测试
data = datalist[i]
for j in range(0,8):
sheet.write(i+1,j,data[j]) #数据
book.save(savepath) #保存

# def saveData2DB(datalist,dbpath):
# init_db(dbpath)
# conn = sqlite3.connect(dbpath)
# cur = conn.cursor()
# for data in datalist:
# for index in range(len(data)):
# if index == 4 or index == 5:
# continue
# data[index] = '"'+data[index]+'"'
# sql = '''
# insert into movie250(
# info_link,pic_link,cname,ename,score,rated,instroduction,info)
# values (%s)'''%",".join(data)
# # print(sql) #输出查询语句,用来测试
# cur.execute(sql)
# conn.commit()
# cur.close
# conn.close()


# def init_db(dbpath):
# sql = '''
# create table movie250(
# id integer primary key autoincrement,
# info_link text,
# pic_link text,
# cname varchar,
# ename varchar ,
# score numeric,
# rated numeric,
# instroduction text,
# info text
# )
#
#
# ''' #创建数据表
# conn = sqlite3.connect(dbpath)
# cursor = conn.cursor()
# cursor.execute(sql)
# conn.commit()
# conn.close()

# 保存数据到数据库
if __name__ == "__main__": # 当程序执行时
# 调用函数
main()
# init_db("movietest.db")
print("爬取完毕!")

URL管理器

定义两个集合放在类的初始化方法中,选择集合这个数据类型,是因为集合的天然去重性,在同一个集合中不会出现一样的数据。
未爬取的URL集合,已爬取的URL集合
用来存储没有爬取过数据的URL和已经爬取过数据的URL,为防止重复爬取同
一个URL的数据

1
2
3
def __init__(self):
self.new_urls = set() #未爬取的URL集合
self.old_urls = set() #已爬取的URL集合

获取未爬取URL集合的大小

1
2
3
def new_url_size(self):
return len(self.new_urls) # 返回未爬取的URL集合的大小

获取已爬取URL的大小

1
2
def old_url_size(self):
return len(self.old_urls) # 返回已爬取的URL集合的大小

判断是否有未爬取的URL

1
2
def has_new_url(self):
return self.new_url_size() != 0 # 返回判断后的真假

获取一个未爬取的URL

1
2
3
4
def get_new_url(self):
new_url = self.new_urls.pop() # 从未爬取的URL集合中获取一个URL并且从原集合中删除
self.old_urls.add(new_url) # 把这条URL放入已爬取的URL集合中
return new_url # 返回这条URL

将新的URL添加到未爬取的URL集合

1
2
3
4
5
def add_new_url(self,url):
if url is None:
return
if url not in self.new_urls and url not in self.old_urls: # 判断URL是否在未爬取的URL集合和已爬取的URL集合中
self.new_urls.add(url) # 若不在就加入未爬取的URL集合中

添加多个URL链接到未爬取的URL集合

1
2
3
4
5
def add_new_urls(self,urls):
if urls is None or len(urls) == 0:
return
for url in urls:
self.add_new_url(url) # 调用添加单个URL的方法

示例:爬取文字数据

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
import requests
import pandas as pd
from io import StringIO
url = 'https://tianqi.2345.com/Pc/GetHistory'

headers = {
"Referer": "https://tianqi.2345.com/wea_history/54511.htm",
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/132.0.0.0 Safari/537.36 Edg/132.0.0.0"
}

def crawler_table(year,month):
params = {
"areaInfo[areaId]": 54511,
"areaInfo[areaType]": 2,
"date[year]": year,
"date[month]": month
}
response = requests.get(url, params=params, headers=headers)

#print(response.status_code)
#print(response.text)
data = response.json()['data']

df = pd.read_html(StringIO(data))[0]

# print(df.head())
return df

df_list = []
for year in range(2011, 2022):
for month in range(1, 13):
df = crawler_table(year, month)
df_list.append(df)

pd.concat(df_list).to_excel('北京十年间的天气数据.xlsx', index=False)

爬取图片

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
import os
import re
import requests
# import pandas as pd
import bs4

url = "https://image.baidu.com/search/index?tn=baiduimage&ps=1&ct=201326592&lm=-1&cl=2&nc=1&ie=utf-8&dyTabStr=MCwxMiwzLDEsMiwxMyw3LDYsNSw5&word=%E5%B0%8F%E5%A7%90%E5%A7%90%E5%9B%BE%E7%89%87"

headers = {
"Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7",
"Referer": "https://www.baidu.com/",
"Accept-Encoding": "gzip, deflate, br, zstd",
"Accept-Language": "zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6,sl;q=0.5",
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.190 Safari/537.36'
}

response = requests.get(url, headers=headers, timeout=10)
# print(response.text)
response.encoding = "utf-8"
print(response.status_code)
# print(response.encoding)

html = response.text

bs = bs4.BeautifulSoup(html, "html.parser")
img_url_list = re.findall(r'"objURL":"(.*?)"', html)
# imgs = bs.find_all("img")
# print(imgs)
# for img in imgs:
# src = img["src"]
# # name = img["alt"]
# # print(name, src)
# # src = "https://www.sucai999.com" + src
# filename = os.path.basename(src)
# with open(f"图片/{filename}", 'wb')as f:
# resp_img = requests.get(src)
# f.write(resp_img.content)
img_path = "./图片/"
if not os.path.exists(img_path):
os.makedirs(img_path)

count = 0
for img_url in img_url_list:
try:
res = requests.get(img_url, headers=headers)
if res.status_code == 200:
count += 1
filename = os.path.join(img_path, f"图片{str(count)}.jpg")
with open(filename, "wb") as f:
f.write(res.content)
print(f"成功下载第{count}张图片", img_url)
except Exception as e:
pass

本站由 QD 使用 Stellar 1.29.1 主题创建。
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议,转载请注明出处。