一.Web服务器
二.一些原理
三.Redis
四.爬虫
五.数据分析
一.Web服务器
1.HTTP和TCP
TCP协议对应于传输层,而HTTP协议对应于应用层,从本质上来说,二者没有可比性。Http协议是建立在TCP协议基础之上的,当浏览器需要从服务器获取网页数据的时候,会发出一次Http请求。Http会通过TCP建立起一个到服务器的连接通道,当本次请求需要的数据完毕后,Http会立即将TCP连接断开,这个过程是很短的。所以Http连接是一种短连接,是一种无状态的连接。所谓的无状态,是指浏览器每次向服务器发起请求的时候,不是通过一个连接,而是每次都建立一个新的连接。如果是一个连接的话,服务器进程中就能保持住这个连接并且在内存中记住一些信息状态。而每次请求结束后,连接就关闭,相关的内容就释放了,所以记不住任何状态,成为无状态连接。
随着时间的推移,html页面变得复杂了,里面可能嵌入了很多图片,这时候每次访问图片都需要建立一次TCP连接就显得低效了。因此Keep-Alive被提出用来解决效率低的问题。从HTTP/1.1起,默认都开启了Keep-Alive,保持连接特性,简单地说,当一个网页打开完成后,客户端和服务器之间用于传输HTTP数据的TCP连接不会关闭,如果客户端再次访问这个服务器上的网页,会继续使用这一条已经建立的连接Keep-Alive不会永久保持连接,它有一个保持时间,可以在不同的服务器软件(如Apache)中设定这个时间。虽然这里使用TCP连接保持了一段时间,但是这个时间是有限范围的,到了时间点依然是会关闭的,所以我们还把其看做是每次连接完成后就会关闭。后来,通过Session, Cookie等相关技术,也能保持一些用户的状态。但是还是每次都使用一个连接,依然是无状态连接。
以前有个概念很容忍搞不清楚。就是为什么HTTP是无状态的短连接,而TCP是有状态的长连接?HTTP不是建立在TCP的基础上吗,为什么还能是短连接?现在明白了,HTTP就是在每次请求完成后就把TCP连接关了,所以是短连接。而我们直接通过Socket编程使用TCP协议的时候,因为我们自己可以通过代码区控制什么时候打开连接什么时候关闭连接,只要我们不通过代码把连接关闭,这个连接就会在客户端和服务端的进程中一直存在,相关状态数据会一直保存着。
2.TCP连接
客户端和服务器端建立连接是端到端的管道,之前在网络编程中知道,每个客户端socket连接到服务器会产生一个socket为该客户端服务;
一发一收确认一端连接。
- 简单理解TCP连接三次握手和四次挥手的过程:
三次握手:
客户端发送给服务器端连接请求(tcpclient_socket.connect((127.0.0.1,9999))),(1);
服务器端收到客户端请求之后,告诉客户端收到连接请求(2),此时客户端确认和服务器端建立连接;
服务器端发送和客户端连接请求(3),客服端接收到服务器端消息发送反馈给服务器端(4),此时服务器确认和客户端建立连接。
(2),(3)对于服务器端可以合并成一个请求,所以三次握手确保连接建立。
四次挥手:
客户端告诉服务器端关闭连接(tcpclient_socket.close()),(1);
服务器端收到客户端请求关闭后,告诉客户端收到关闭请求,(2);
服务器端告诉客户端关闭服务器端连接(tcpservice_socket.close()),(3);
客户端收到关闭服务器端消息后,给服务器端发送收到请求(4),此时服务器确认和客户端断开连接。
(2),(3)不能合并成一个请求是因为服务器端调用close是一个不确定是否会被调用的操作。
服务器端发送关闭服务器连接请求后(3),如果没有收到客户端回应,会再次发送关闭请求。
客户端最后一个发送请求之后(4),会等待2MSL(2倍最大报文生存时间)才真正关闭socket,因为这次消息很可能由于网络延迟或者意外而没有被服务器收到,如果马上关闭socket就无法再接收到服务器端发送的超时连接请求。
3.TCP/IP
TCP/IP 是供已连接因特网的计算机进行通信的通信协议。
TCP/IP 指传输控制协议(传输层)/网际协议(网络层)
TCP/IP 定义了电子设备(比如计算机)如何连入因特网,以及数据如何在它们之间传输的标准。
TCP/IP传输数据相关概念:
- 子网掩码:规定IP地址哪部分是网络地址和主机地址。
https://baijiahao.baidu.com/s?id=1606474671793061553&wfr=spider&for=pc - 路由器(网关):是用于连接多个逻辑上分开的网络,当数据从一个子网传输到另一个子网时,可通过路由器的路由功能来完成。
- ARP协议:是根据IP地址获取物理地址(网卡地址)的一个TCP/IP协议。
- NAT协议:NAT网络地址转换(Network Address Translation)属接入广域网(WAN)技术,是一种将私有(保留)地址转化为合法IP地址的转换技术,它被广泛应用于各种类型Internet接入方式和各种类型的网络中。原因很简单,NAT不仅完美地解决了lP地址不足的问题,而且还能够有效地避免来自网络外部的攻击,隐藏并保护网络内部的计算机。
- 交换机:局域网交换机指的是用在交换式局域网内进行数据交换的设备。
eg:一台普通的内网主机浏览器输入www.baidu.com的过程:
浏览器(客户端)发起请求,www.baidu.com通过DNS服务器解析出IP地址,加上浏览器的端口号8080,作为目的地址(服务器端)地址;
发起请求的主机向局域网交换机请求数据,此时目的MAC地址是交换机的MAC地址,因为并不知道baidu服务器的MAC地址。
(如果请求数据是局域网内部的主机,则此时通过交换机就可以找到目的主机的MAC地址)
交换机再去公网网关路由器请求数据,此时的目的MAC地址被交换机修改为默认网关的MAC地址,通过路由算法,逐步交换找到baidu网关的MAC地址,然后通过交换机的MAC交换找到服务器主机MAC地址才真正建立起连接;
(找到后会在客户端主机做该IP地址的MAC缓存)
传输层建立TCP连接,三次握手;
baidu发送HTTP协议规定的数据格式给客户端浏览器,浏览器按照HTTP规范解析数据展示;
传输层TCP四次挥手断开连接。
二.一些原理
1.闭包
1.闭包是由函数及其相关的引用环境组合而成的实体(即:闭包=函数+引用环境)(想想Erlang的外层函数传入一个参数a, 内层函数
依旧传入一个参数b, 内层函数使用a和b, 最后返回内层函数)
2.函数嵌套并且函数的返回值为内部函数返回值函数时,可以成为闭包。
#函数名其实就是一个指针变量,可以作为返回值和参数
"""
函数作为返回值
"""
def func():
def innerfunc():
print("innerfunc")
return innerfunc
f=func()
f() #innerfunc
"""
函数作为参数
"""
def paramfunc():
print("paramfunc")
def func(f):
f()
func(paramfunc) #paramfunc
"""
闭包的基本使用:
内部函数使用外部函数的参数
"""
def func(x):
def innerfunc():
print(x*10)
return innerfunc
f=func(10)
f() #20
"""
闭包内部函数修改外部函数的值是需要使用nonlocal修饰,
否则使用赋值运算相当于直接定义一个内部函数的同名变量
"""
def func(x):
def innerfunc():
#nonlocal x
x=2
print("innerfunc-x=%d"%x)
innerfunc()
print("func-x=%d"%x)
return innerfunc
func(10)
#innerfunc-x=2
#func-x=10
def func(list):
def innerfunc():
list.append(3)
print("innerfunc-x=%s"%list)
innerfunc()
print("func-x=%s"%list)
return innerfunc
func([1,2])
#innerfunc-x=[1, 2, 3]
#func-x=[1, 2, 3]
"""
还得注意一个点就是python的函数只有在执行时,才会去找函数体里的变量的值
"""
flist = []
for i in range(3):
def foo(x):
print(x+i)
flist.append(foo)
for f in flist:
f(2) #4,4,4
flist2 = []
for j in range(3):
def foo(x,y=j):
print(x+y)
flist2.append(foo)
for f in flist2:
f(2) #2,3,4
闭包内部函数可以独享外部函数传递的数据,并做处理,这个地方比全局变量更有优势,全局变量可以被外部函数使用和修改
2.装饰器
装饰器是 Python 的一个重要部分。简单地说:他们是利用闭包特性修改其他函数的功能的函数。
"""
装饰器原理:使用decf函数强行修改fc指向,给fc函数添加处理
"""
def decf(f):
def nn():
print("decf")
f()
return nn
def fc():
print("fc")
#修改fc的指向
fc=decf(fc)
fc()
decf
fc
"""
装饰器基本使用
"""
def decfunc(func):
print("start dec")
def noname():
print("decfunc")
func()
return noname
"""
1.相当于 orifunc=decfunc(orifunc),修改函数指向
2.编译时装饰,而不是调用时装饰
"""
@decfunc
def orifunc():
print("orifunc")
orifunc()
start dec
decfunc
orifunc
"""
对有参函数加装饰器
"""
def decfunc(func):
def noname(n):
print("decfunc")
func(n)
return noname
@decfunc
def orifunc(num):
print("orifunc:%d"%num)
orifunc(10)
decfunc
orifunc:10
"""
对不定长有参函数加装饰器
"""
def decfunc(func):
def noname(*args,**kwargs):
print("decfunc")
func(*args,**kwargs)
return noname
@decfunc
def orifunc(num,*args,**kwargs):
print("num:%d"%num)
print("args:",args)
print("kwargs:",kwargs)
orifunc(1)
orifunc(1,2)
orifunc(1,2,key=3)
decfunc
num:1
args: ()
kwargs: {}
decfunc
num:1
args: (2,)
kwargs: {}
decfunc
num:1
args: (2,)
kwargs: {'key': 3}
"""
对有返回值函数加装饰器
"""
def decfunc(func):
def noname(*args,**kwargs):
print("decfunc")
return func(*args,**kwargs)
return noname
@decfunc
def orifunc(*args,**kwargs):
print("args:",args)
print("kwargs:",kwargs)
return "ZS"
res=orifunc(1)
print(res)
decfunc
args: (1,)
kwargs: {}
ZS
"""通用装饰器"""
def decfunc(func):
def noname(*args,**kwargs):
return func(*args,**kwargs)
return noname
"""带参数装饰器"""
def decp(params):
def call_func(func):
def noname(*args,**kwargs):
print("decp-%s"%params)
return func(*args,**kwargs)
return noname
return call_func
@decp("zs")
def funcp():
print("funcp--")
funcp()
decp-zs
funcp--
"""多个装饰器"""
def dec1(func):
def noname(*args,**kwargs):
print("dec1")
return func(*args,**kwargs)
return noname
def dec2(func):
def noname(*args,**kwargs):
print("dec2")
return func(*args,**kwargs)
return noname
#先装饰desc2,再装饰desc1,调用顺序就是先desc1,再desc2
@dec1
@dec2
def func():
print("function")
func()
dec1
dec2
function
"""类装饰器"""
class decclass():
def __init__(self,func):
self.func=func
def __call__(self, *args, **kwargs):
print("decclass")
return self.func()
#相当于 funct=decclass(funct) funct()->对象()调用call方法
@decclass
def funct():
print("funct")
funct()
decclass
funct
3.元类
1.类也是对象,元类就是用来创建这些类(对象)的,元类就是类的类。
2.元类的主要目的就是为了当创建类时能够自动地改变类。
3.元类应用在ORM框架中,给模型类添加处理方法和映射关系。
"""
元类通过type进行创建
a对象是A类创建的,A类是type类创建的,type类是type类创建的
"""
class A():
pass
a=A()
print(a.__class__)
print(a.__class__.__class__)
print(a.__class__.__class__.__class__)
"""
通过type函数创建类
"""
class Person():
pass
class Student(Person):
count=0
def show(self):
print("student")
stu=Student()
stu.show()
def show(self):
print("student")
Stu=type("Student",(Person,),{"count":0,"show":show})
stu=Stu()
stu.show()
"""
通过MetaSporter类修改Sporter创建方式(不指定默认type创建)
"""
class MetaSporter(type):
def __new__(cls, class_name,class_parents,class_attr):
attrs = ((name, value) for name, value in class_attr.items()
#改变公有变量为大写
if not name.startswith('__'))
uppercase_attr = dict((name.upper(), value) for name, value in attrs)
return type.__new__(cls,class_name,class_parents,uppercase_attr)
class Sporter(metaclass=MetaSporter):
name="MVP"
sporter=Sporter()
print(sporter.NAME)
<class 'main.A'>
<class 'type'>
<class 'type'>
student
student
MVP
三.Redis
1.Redis概述
1.Redis 是完全开源免费的,遵守BSD协议,是一个高性能的key-value数据库。
2.性能极高 – Redis能读的速度是110000次/s,写的速度是81000次/s 。
3.原子 – Redis的所有操作都是原子性的。
4.用于服务器缓存,计数器等。
2.安装配置
http://www.runoob.com/redis/redis-install.html
3.数据类型和操作
1.Redis支持五种数据类型:string(字符串),hash(哈希),list(列表),set(集合)及zset(有序集合)。
2.string 是 redis 最基本的类型,一个 key 对应一个 value。
string 类型是二进制安全的。意思是 redis 的 string 可以包含任何数据。比如jpg图片或者序列化的对象。
string 类型的值最大能存储 512MB。
基本操作:
http://www.runoob.com/redis/redis-data-types.html
4.Python使用Redis
1.启动redis-server模块
cd redis/src
./redis-server
通过ps -x|grep redis 查看
2.安装导入redis模块
3.使用
import redis
def main():
rs = redis.StrictRedis(host="127.0.0.1",port="6379",db=0)
name = rs.get("name")
print(name)
res=rs.set("name","zsy")
print(res)
name=rs.get("name")
print(name)
if __name__ == '__main__':
main()
None
True
b'zsy'
四.爬虫
使用requests模块请求网络数
import requests
import json
"""
基本使用requests模块获取请求头和响应头
"""
# url="{}{}".format("http://","www.baidu.com") #格式化字符串
# response=requests.get(url)
# print("response:%s"%response.headers)
# print("resquest:%s"%response.request.headers)
# print(response.content.decode())
"""
伪造请求头header
"""
# header={"User-Agent":"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.98 Safari/537.36"}
# response=requests.get(url,headers=header)
# print(response.content.decode())
"""
post请求体添加
"""
# url="{}".format("https://api.taotiangou.cn/api2_1/index/getIndexIcon")
# headers={}
# data={"userid":"189"}
# response=requests.post(url,headers=headers,data=data)
# #print(response.content.decode())
#转成json打印
# dict=json.loads(response.content.decode())
# print(dict["data"][0]["a_name"])
"""
使用代理:
让服务器以为不是同一个客户端请求;防止真实地址泄漏
"""
# proxies={"http":"http://27.42.173.133"}
# response=requests.get(url,proxies=proxies)
"""
cookie添加访问登录页面
"""
url="{}".format("https://pan.baidu.com/disk/home?#/all?path=%2F&vmode=list")
#第一种方法:直接header中写入cookie
headers={"User-Agent":"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.98 Safari/537.36",
"Cookie":"PSTM=1525329664; BIDUPSID=A33CF2B8C662B817DF7F62AE990D655C; PANWEB=1; MCITY=-%3A; BAIDUID=70FA8F8866B423880A1CA29BC1C68FCE:FG=1; BDORZ=B490B5EBF6F3CD402E515D22BCDA1598; BDCLND=x9MVHACLFgvF9IL7rIVTLM2OQhjVDfhmCW8C%2FihLVLw%3D; BDUSS=3Q3OX5VYUFUNkFNeC1wUnpwb21pSDh-MkFFd3JMU3h0SUZNZmlGfkl5dW9uM0JjQVFBQUFBJCQAAAAAAAAAAAEAAACj7KhNemhvdXNpeWFuZzE5OTAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAKgSSVyoEklcQ; pan_login_way=1; STOKEN=b8eccf9e1b192287d4486db9afd6a585a8022bdc2cc6586f57a938a8f9c28b6f; SCRC=d43dcdf89116b6b96ed8e3224a76acac; pgv_pvi=160503808; SE_LAUNCH=5%3A25806433_0%3A25806433; Hm_lvt_7a3960b6f067eb0085b7f96ff5e660b0=1548033802,1548034171,1548034218,1548394494; cflag=13%3A3; BDRCVFR[feWj1Vr5u3D]=I67x6TjHwwYf0; delPer=0; PSINO=1; locale=zh; pgv_si=s8925985792; H_PS_PSSID=1456_21091_20697_28328_28414_22072; BCLID=8267917567788901312; BDSFRCVID=oskOJeC62G-qlT69srwwuGzxamj5nTnTH6aoH36b11HYuz94DD82EG0PeM8g0Kub1eJMogKKyeOTHu8F_2uxOjjg8UtVJeC6EG0P3J; H_BDCLCKID_SF=tJIJoK_hfIK3fP36q4jqMJFtKh5yhnFXKKOLVb7b2h7keq8CDxtVKtA7jGrebJbfbmvEXnjE2D5_Sbr2y5jHhUvyjxKDJxvkb6L8_pbgfIopsIJMbfFWbT8U5fKDKxTuaKvia-THBMb1fDnDBT5h2M4qMxtOLR3pWDTm_q5TtUt5OCcnK4-Xj533DabP; Hm_lpvt_7a3960b6f067eb0085b7f96ff5e660b0=1548411429; PANPSC=16507912538981936925%3AMH68bVsDvKL4sE9jqMmgcqikII2LTYQX6iJWjf1IM76iE4uyuiKDw%2FFMne%2FXPWb6IL1H0PxEv92SQhzndJOhXsk9gyF%2FWtZZ82toIHXFJKL2daqLHTAOegPMsbEIX3KNyFMq753BNv%2Bev3JCgJ4cjzyDU9xFytyIxnT2tA7ZiDW928MbUB6%2BRw%3D%3D"}
#第二种方法:把cookie值转成字典使用请求参数传递
cookiestr="PSTM=1525329664; BIDUPSID=A33CF2B8C662B817DF7F62AE990D655C; PANWEB=1; MCITY=-%3A; BAIDUID=70FA8F8866B423880A1CA29BC1C68FCE:FG=1; BDORZ=B490B5EBF6F3CD402E515D22BCDA1598; BDCLND=x9MVHACLFgvF9IL7rIVTLM2OQhjVDfhmCW8C%2FihLVLw%3D; BDUSS=3Q3OX5VYUFUNkFNeC1wUnpwb21pSDh-MkFFd3JMU3h0SUZNZmlGfkl5dW9uM0JjQVFBQUFBJCQAAAAAAAAAAAEAAACj7KhNemhvdXNpeWFuZzE5OTAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAKgSSVyoEklcQ; pan_login_way=1; STOKEN=b8eccf9e1b192287d4486db9afd6a585a8022bdc2cc6586f57a938a8f9c28b6f; SCRC=d43dcdf89116b6b96ed8e3224a76acac; pgv_pvi=160503808; SE_LAUNCH=5%3A25806433_0%3A25806433; Hm_lvt_7a3960b6f067eb0085b7f96ff5e660b0=1548033802,1548034171,1548034218,1548394494; cflag=13%3A3; BDRCVFR[feWj1Vr5u3D]=I67x6TjHwwYf0; delPer=0; PSINO=1; locale=zh; pgv_si=s8925985792; H_PS_PSSID=1456_21091_20697_28328_28414_22072; BCLID=8267917567788901312; BDSFRCVID=oskOJeC62G-qlT69srwwuGzxamj5nTnTH6aoH36b11HYuz94DD82EG0PeM8g0Kub1eJMogKKyeOTHu8F_2uxOjjg8UtVJeC6EG0P3J; H_BDCLCKID_SF=tJIJoK_hfIK3fP36q4jqMJFtKh5yhnFXKKOLVb7b2h7keq8CDxtVKtA7jGrebJbfbmvEXnjE2D5_Sbr2y5jHhUvyjxKDJxvkb6L8_pbgfIopsIJMbfFWbT8U5fKDKxTuaKvia-THBMb1fDnDBT5h2M4qMxtOLR3pWDTm_q5TtUt5OCcnK4-Xj533DabP; Hm_lpvt_7a3960b6f067eb0085b7f96ff5e660b0=1548411429; PANPSC=16507912538981936925%3AMH68bVsDvKL4sE9jqMmgcqikII2LTYQX6iJWjf1IM76iE4uyuiKDw%2FFMne%2FXPWb6IL1H0PxEv92SQhzndJOhXsk9gyF%2FWtZZ82toIHXFJKL2daqLHTAOegPMsbEIX3KNyFMq753BNv%2Bev3JCgJ4cjzyDU9xFytyIxnT2tA7ZiDW928MbUB6%2BRw%3D%3D"
#通过字符串截取获取把字符串转成字典
cookies={kv.split("=")[0]:kv.split("=")[1] for kv in cookiestr.split(";")}
response=requests.post(url,headers=headers,cookies=cookies)
print(response.content.decode())
"""
cookie转字典
"""
def getcookie():
url="{}".format("http://www.runoob.com/python/att-string-format.html")
response=requests.get(url)
print("cookie:%s"%response.cookies)
dict=requests.utils.dict_from_cookiejar(response.cookies)
print("dict:{}".format(dict))
"""
访问HTTPS不安全网站,设置超时时间
"""
def settime():
url="{}".format("https://pan.baidu.com",verify=False,timeout=10)
response=requests.get(url)
print("status_code:{}".format(response.status_code))
使用json模块处理json数据
import requests
import json
#通过手机豆瓣找到电影列表json(去掉callback=json字段)
url="{}".format("https://m.douban.com/rexxar/api/v2/subject_collection/movie_free_stream/items?os=ios&start=0&count=8&loc_id=108288&_=1548485894537") #格式化字符串
header={"User-Agent":"Mozilla/5.0 (iPhone; CPU iPhone OS 11_0 like Mac OS X) AppleWebKit/604.1.38 (KHTML, like Gecko) Version/11.0 Mobile/15A372 Safari/604.1"
,"Referer":"https://m.douban.com/movie/"
}
response=requests.get(url,headers=header)
#json转对象(字典)
dbjson=json.loads(response.content.decode())
with open("douban.json","w",encoding="utf-8") as f:
#json对象写入文件
json.dump(dbjson,f,ensure_ascii=False,indent=4)
使用re模块处理html标签
正则表达式
http://www.runoob.com/python3/python3-reg-expressions.html
pattern = re.compile("<p>.*?</p>") #预编译
pattern.match() #从头查找
pattern.findall() #找所有
pattern.search() #找一个
pattern.sub() #替换
使用lxml模块提取html/xml数据
1.xpath语法介绍
- / 从根节点选取
- // 从匹配选择的当前节点选择文档中的节点,而不考虑它们的位置。
- . 选取当前节点
- .. 选取当前节点的父节点
- @ 选取属性
"""
以 https://m.douban.com/movie/ 为例子
"""
#1.获取文本
/html/head/title/text()
#2.获取属性
/html/head/link/@rel
#3.筛选
//div[@class="down-app"]
#4.获取热映电影名称列表
//div[@class="card"]//span[@class="item-title"]/text()
#5.可以使用通配符*,所有节点的所有属性
//*[@*]
2.lxml模块
from lxml import etree
htmlStr="""
<div>
<ul>
<li><span>first</span><a href='first.cn'></a></li>
<li><span>second</span><a href='second.cn'></a></li>
<li><span>third</span><a href='third.cn'></a></li>
</ul>
</div>
"""
#字符串转成HTML对象
html=etree.HTML(htmlStr)
#print(html)
#使用xpath语法获取li元素
li=html.xpath("//li")
#遍历li列表,使用xpath截取文本和链接
for e in li:
text=e.xpath("./span/text()")
href=e.xpath("./a/@href")
if(len(text)>0):
print(text[0])
if(len(href)>0):
print(href[0])
使用Mongodb存储爬虫数据
MongoDB 是由C++语言编写的,是一个基于分布式文件存储的开源数据库系统。
在高负载的情况下,添加更多的节点,可以保证服务器性能。
MongoDB 旨在为WEB应用提供可扩展的高性能数据存储解决方案。
MongoDB 将数据存储为一个文档,数据结构由键值(key=>value)对组成。MongoDB 文档类似于 JSON 对象。字段值可以包含> > 其他文档,数组及文档数组。
1.基本操作
http://www.runoob.com/mongodb/mongodb-tutorial.html
2.使用pymongo模块进行Python交互
五.数据分析
1.matplotlib模块基本使用
可参考文档:https://matplotlib.org/
from matplotlib import pyplot as plt
import random
import matplotlib
"""折线图"""
def showzhexian():
#1.设置显示大小和DPI
plt.figure(figsize=(20,8),dpi=80)
#2.定义x坐标和y坐标
x=range(2,100)
y1=[random.randint(1,100) for i in range(2,100)]
plt.plot(x,y1,label="y1")
y2 = [random.randint(1, 100) for i in range(2, 100)]
plt.plot(x,y2,label="y2")
#x_ticks_lab=[i for i in list(x)[::2]]
x_ticks_lab=["s{}".format(i) for i in x]
#3.重新定义横坐标显示(加入字符串,设置步长,旋转)
plt.xticks(list(x)[::3],x_ticks_lab[::3],rotation=45)
#4.设置中文字体
font = {'family': 'Helvetica',
'weight': 'bold',
'size': '15'}
matplotlib.rc("font", **font)
plt.xlabel("x轴名称",fontdict=font)
plt.ylabel("y轴名称",fontdict=font)
#5.设置网格
plt.grid()
#6.显示图例
plt.legend()
#7.展示
plt.show()
"""散点图"""
def showsandian():
plt.figure(figsize=(20, 8), dpi=80)
x = range(2, 100)
y = [random.randint(1, 100) for i in range(2, 100)]
plt.scatter(x,y)
plt.show()
"""柱状图"""
def showzhuzhuang():
plt.figure(figsize=(20, 8), dpi=80)
x = range(2, 100)
y = [random.randint(1, 100) for i in range(2, 100)]
#竖向
#plt.bar(x,y)
#横向
plt.barh(x,y)
plt.show()
"""直方图"""
def showzhifang():
plt.figure(figsize=(20, 8), dpi=80)
#离散数据
num = [random.randint(1, 100) for i in range(2, 100)]
#离散数据分组组数
numcount=10
plt.hist(num,numcount)
plt.show()
if __name__ == '__main__':
showzhifang()
2.numpy基本使用
http://www.runoob.com/numpy/numpy-tutorial.html
import numpy as np
"""创建"""
def create():
#numpy创建的数据类型为numpy.ndarray,可以通过数组和range初始化
t1=np.array([1,2,3])
print(type(t1),t1)
t2=np.array(range(10))
print(type(t2),t2)
t3=np.arange(1,10,2)
print(type(t3),t3)
#创建时元素类型可以指定修改,包含比Python更多的类型,比如int64,complex...
t4=np.array(range(5),dtype=float)
print(t4.dtype,t4)
t4=t4.astype(dtype="i4")
print(t4.dtype,t4)
#初始化元素为0,1或者随机数值的二维形状的numpy
t5=np.empty([2,2],dtype="i4")
print(t5)
t6=np.zeros([3,3],dtype=float)
print(t6)
t7=np.ones([2,3])
print(t7)
def operate():
"""切片和基本索引"""
t1=np.array([[1,2,3,2,1],[4,5,6,5,4],[7,8,9,8,7]])
print(t1)
#转置
print(t1.transpose())
print(t1.T)
#取某个数据
print(t1[0][2])
print(t1[0,2])
#取不相邻多个点 (0,1),(2,2),(1,2)三个点
print(t1[[0,2,1],[1,2,2]])
#取某一行
print(t1[1])
#取连续行(1-2行),切片方式
print(t1[1:3:])
#取不连续行
print(t1[[0,2]])
#取不连续多列,第1,3列
print(t1[:,[0,2]])
#取多行多列,第2行-3行,2-3列(交叉点)
print(t1[1:3,1:3])
"""布尔索引"""
#取t1<5的数据并赋值为0
t1[t1<5]=0
print(t1)
def operate2():
t1=np.arange(10)
print(t1)
t2=np.arange(10,20,1)
print(t2)
#水平拼接
t3=np.vstack((t1,t2))
print(t3)
#垂直拼接
t4=np.hstack((t1,t2))
print(t4)
#修改数组形状,切分为(2,5)形状的二维数组
t5=t1.reshape(2,5)
print(t5)
#迭代
for x in np.nditer(t1):
print(x,end="")
"""广播机制"""
def calculate():
#维度相同的对应位置进行计算
t1=np.array([1,2,3,4])
t2=np.array([9,8,7,6])
rs=t1+t2
print(rs)
#维度不同的
"""
当在两个数组上操作时,NumPy在元素级别比较它们的形状。它从尾随的维度开始,并朝着前进的方向前进。两个维度兼容,当
他们是平等的,或者其中之一是1
如果不满足这些条件,则抛出ValueError: frames are not aligned异常,指示数组具有不兼容的形状。结果数组的大小是沿着输入数组的每个维度的最大大小。
"""
t3=np.array([[1,2,3,2,1],[4,5,6,5,4],[7,8,9,8,7]])
t4=np.array([1,1,1,1,1])
t5=np.array([[3],[3],[3]])
print(t3.shape,t4.shape,t5.shape)
print(t3)
#相加之后,每个大数组的元素都会和小数组元素相加
rs2=t3+t4
print(rs2)
rs3=t3+t5
print(rs3)
if __name__ == '__main__':
calculate()