来源于Python入门+数据分析,供复习使用
Python介绍
诞生和发展
特点
- 开源、易于维护
- 可移植
- 易于使用、简单优雅
- 广泛的标准库、功能强大
- 可扩展、可嵌入
缺点:运行速度慢,Python是解释型语言,运行时翻译为机器码非常耗时,而java、C语言是运行前直接编译成CPU能执行的机器码,但是大量的应用程序不需要这么快的运行素服,因为用户感觉不出来。
pycharm代码模板
设置中检索 template,找到python scripy:
基础语法
格式化输出
age = 10
print("我今年%d岁"%age)
age = 18
name = "hello"
print("我的姓名是%s,年龄是%d"%(name,age))
print("1234567890-------")
print("1234567890\n-------")
print("aaa","bbb","ccc")
print("www","baidu","com",sep=".")
print("hello",end="")
print("world",end="\t")
print("python",end="\n")
print("end")
输入
password = input("请输入密码:")
print('您刚刚输入的密码是:', password)
print(type(password))
c = int("123")
print(type(c))
运算符
和其他语言类似。
条件判断语句
a = 10
if a > 1:
print("1")
print("jjjj")
else:
print("0")
print("end")
score = 77
if 90 <= score <= 100:
print('本次考试,等级为A')
elif 80 <= score < 90:
print('本次考试,等级为B')
elif 70 <= score < 80:
print('本次考试,等级为C')
elif score >= 60 and score < 70:
print('本次考试,等级为D')
else:
print('本次考试,等级为E')
xingBie = 1
danShen = 1
if xingBie == 1:
print("是男生")
if danShen == 1:
print("我给你介绍一个吧?")
else:
print("你给我介绍一个呗?")
else:
print("你是女生")
print("……")
import 与 from…import
在 python 用 import 或者 from…import 来导入相应的模块。
将整个模块(somemodule)导入,格式为: import somemodule
从某个模块中导入某个函数,格式为: from somemodule import somefunction
从某个模块中导入多个函数,格式为: from somemodule import firstfunc, secondfunc, thirdfunc
将某个模块中的全部函数导入,格式为: from somemodule import \*
【生成随机数】
import random
computer = random.randint(0,2)
循环语句
for循环
格式:
for 临时变量 in 列表或者字符串等:
循环满足条件时执行的代码
name = 'hello'
for item in name:
print(item)
for i in range(5):
print(i)
for i in range(0,11,3):
print(i)
for i in range(-10,-100,-20):
print(i)
a = ["aa","bb","cc"]
for i in range(len(a)):
print(i,a[i])
while
i = 0
while i<5:
print("当前是第%d次执行循环"%(i+1))
print("i=%d"%i)
i+=1
break,continue,pass
break,continue和其他编程语言意义相同
pass是空语句 一般用作占位语句 不做任何事情
字符串、列表、元组、字典
字符串
Python中的字符串可以使用单引号、双引号和三引号(三个单引号或三个双引号)括起来,表示一个字符串
三引号可以保留格式
word = '字符串'
sentence = "则会是一个句子"
parapraph = """
想没有用,要实际操作!
"""
print(word)
print(sentence)
print(parapraph)
str = "hello"
print(str[0])
print(str[0:2])
print((str[0:5:2]))
print(str[2:])
print(str[:2])
print(r"hello\nchengdu")
单引号和双引号的选择
-
包含单引号的字符串 假如你想定义一个字符串my_str,其值为: I’m a student,则可以采用如下方式,通过转义字符 \ 进 行定义。 my_str = 'I\'m a student'
也可以不使用转义字符,利用双引号直接进行定义。 my_str = "I'm a student"
-
包含双引号的字符串 假如你想定义一个字符串my_str,其值为: Jason said “I like you” ,则可以采用如下方式,通过转义 字符 \ 进行定义。 my_str = "Jason said \"I like you\""
也可以不使用转义字符,利用单引号直接进行定义。 my_str = 'Jason said "I like you"'
字符串常用操作
序号 | 方法 | 描述 |
---|
1 | bytes.decode(encoding=“utf-8”, errors=“strict”) | Python3 中没有 decode 方法,但我 们可以使用 bytes 对象的 decode() 方法来解码给定的 bytes 对象,这个 bytes 对象可以由 str.encode() 来编码返回。 | 2 | encode(encoding=‘UTF-8’,errors=‘strict’) | 以 encoding指定的编码格式编码字符串,如 果出错默认报一个ValueError 的异常,除非 errors 指定的是’ignore’或者’replace’ | 3 | isalnum() 如果字符串至少有一个字符并且所有字符都是字母或数字则返 回 True,否则返回 False | 如果字符串至少有一个字符并且所有字符都是字母或数字则返 回 True,否则返回 False | 4 | isdigit() | 如果字符串只包含数字则返回 True 否则返回 False. | 5 | isnumeric() | 如果字符串中只包含数字字符,则返回 True,否则返回 False | 6 | join(seq) | 以指定字符串作为分隔符,将 seq 中所有的元素(的字符串表示)合并为一个新的 字符串 | 7 | len(string) | 返回字符串长度 | 8 | lstrip() | 截掉字符串左边的空格或指定字符。 | 9 | rstrip() | 删除字符串字符串末尾的空格 | 10 | split(str=“”, num=string.count(str)) num=string.count(str)) | 以 str 为分隔符截取字 符串,如果 num 有指定值,则仅截取 num+1 个子字符串 |
列表 List
- 列表可以完成大多数集合类的数据结构实现。
- 列表中元素的类型可以不相同,它支持数字,字符串甚至可以包含列表(所谓嵌套)。
- 列表是写在方括号之间、用逗号分隔开的元素列表。
- 列表索引值以0为开始值,-1为从末尾的开始位置。列表可以使用+操作符进行拼接,使用*表示重复。
列表定义与访问
-
列表的格式 变量A的类型为列表 namesList = ['xiaoWang','xiaoZhang','xiaoHua']
testList = [1, 'a']
-
打印列表 namesList = ['xiaoWang','xiaoZhang','xiaoHua']
print(namesList[0])
print(namesList[1])
print(namesList[2])
-
列表的循环遍历 namesList = ['xiaoWang','xiaoZhang','xiaoHua']
for name in namesList:
print(name)
常用操作
方法 | 操作名称 | 解释操作 |
---|
list[index] | 访问列表中的元素 | 通过下标直接访问列表中的元素 | list[start:end:length] | 列表的切片 | 使用[开始下标索引:结束下标索引 :步进值 ],注意范围区间是"左闭右开" | for i in list:print(i) | 遍历列表元素 | for循环 | list.append(values) | 【增】追加数据到列表中尾部 | 将新的元素值追加到当前列表中末尾位置 | list.extend(list1) | 【增】列表的追加 | 将其他列表的元素添加到当前列表中 | list.insert(index,value) | 【增】列表数据插入 | 根据给定索引指定位置插入元素 | del list[index] list.remove(value) | 【删】列表的删除 | del :我们通过索引删除指定位置的元素。 remove:移除列表中指定值的第一个匹配值。如果没找到的话,会抛异常 | list.pop() | 【删】弹出列表尾部元素 | 弹出当前列表尾部元素,相当于删除元素 | list[index] = 8 | 【改】更新列表中的数据 | 通过下标修改指定元素 | value in list value not in list | 【查】列表成员关系 | in not in | value in list value not in list | 【查】列表成员关系 | in not in | list.count(value) | 【查】查找元素出现次数 | 统计指定元素在当前列表中出现的次数 | list3 = list1 +list2 | 列表的加法操作 | + | list.sort() | 【排】列表的排序 | 将当前列表元素进行排序(升序) | list.reverse() | 【排】列表的反转 | 将列表所有元素进行反转 a.sort(reverse=True) | len() | 获取列表长度 | 获取当前列表长度 | max() | 获取列表元素最大值 | 获取列表元素最大值 | min() | 获取列表元素最小值 | 获取列表元素最小值 | list() | 其他类型对象转换成列表 | 其他类型对象转换成列表 |
列表嵌套
一个列表中的元素又是一个列表,就是列表嵌套,说白了,就是一个二维数组。
schoolNames = [['北京大学','清华大学'],['南开大学','天津大学','天津师范大学'],['山东大学','中国海洋大学']]
print(schoolNames[0][0])
元组 Tuple
定义与访问
tuple与list相似,不同之处在于tuple的元素写在小括号里,元素之间用逗号隔开。
-
创建空元组 tup1 = ()
-
元组的定义 tup1 = (50)
print(type(tup1))
tup1 = (50,)
print(type(tup1))
-
元组的访问 tup1 = ('Google', 'baidu', 2000, 2020)
tup2 = (1, 2, 3, 4, 5, 6, 7 )
print ("tup1[0]: ", tup1[0])
print ("tup2[1:5]: ", tup2[1:5])
-
元组中的元素值是不允许修改的,但我们可以对元组进行连接组合,如下实例: tup1 = (12, 34.56)
tup2 = ('abc', 'xyz')
tup3 = tup1 + tup2
print (tup3)
-
删除元组后,再次访问会报错 tup = ('Google', 'baidu', 2000, 2020)
print (tup)
del tup
print ("删除后的元组 tup : ")
print (tup)
常用操作
方法 | 操作名称 | 解释操作 |
---|
tuple[index] | 访问元组中的元素操作名称 | 通过下标直接访问元组中的元素解释操作 | for i in tuple:print(i) | 遍历元组 | for循环 | tuple[start:end:length] | 元组的切片 | 使用[开始下标索引:结束下标索引 :步进值 ],注意范围区间是"左闭右开" | value in tuple value not in tuple | 【查】元组成员关系 | in not in | tuple.count(value) | 【查】查找元素出现次数 | 统计指定元素在当前元组中出现的次数 | tuple3 = tuple1+tuple2 | 元组的加法操作 | 元组的新增方法 | len() | 获取元组长度 | 获取元组列表长度 | max() | 获取元组元素最大值 | 获取元组元素最大值 | min() | 获取元组元素最小值 | 获取元组元素最小值 | tuple() | 其他类型对象转换成元组 | 其他类型对象转换成元组 |
- 定义好的元组的元素不可修改,但可以包含对象,如list
- 删除时,是删除整个元组,不是元组中的元素
- 定义一个只有一个元素的tuple,必须加逗号
字典 dict
字典的定义
字典是无序的对象集合,使用键值对(key-value)存储,具有极快的查找速度
变量info为字典类型:
info = {'name':'班长', 'id':100, 'sex':'f', 'address':'地球亚洲中国北京'}
说明:
- 字典和列表一样,也能够存储多个数据
- 列表中找某个元素时,是根据下标进行的
- 字典中找某个元素时,是根据’名字’(就是冒号:前面的那个值,例如上面代码中 的’name’、‘id’、‘sex’)
- 字典的每个元素由2部分组成,键:值。例如 ‘name’:‘班长’ ,'name’为键,'班长’为值
根据键访问值
info = {'name':'吴彦祖','age':18}
print(info['age'])
print(info.get('sex'))
若访问不存在的键,则会报错:
info['sex']
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
KeyError: 'sex'
在我们不确定字典中是否存在某个键而又想获取其值时,可以使用get方法,还可以设置默认值:
>>> age = info.get('age')
>>> age
>>> type(age)
<type 'NoneType'>
>>> age = info.get('age', 18)
>>> age
18
常用操作
操作名称 | 操作方法 | 举例 |
---|
dict[key] | 访问字典中的元素 | 通过key访问,key不存在会抛出异常 | dict.get(key) | 访问字典中的元素 | 通过get方法,不存在返回None,不抛出异常 | for key in dict: print(key,dict[key]) | 遍历字典 | 通过for循环,只能获取key,values需要使用dict[key]获取 | for key,value in dict.items():print(key,value) | 遍历字典 | 配合items方法,获取key和value | dict.keys() dict.values() dict.items() | 获取所有key 获取所有value 获取所有的key-value | 使用keys和values方法 | dict[key] = newvalue | 修改value | 直接通过key来修改value | dict[newkey] = newvalue | 新增键值对 | 直接新增 | del dict[key] | 删除字典元素 | 通过key删除字典元素 | dict.pop(key) | 弹出字典元素 | 通过key弹出字典元素 | key in dict | 判断key是否存在 | in | dict.update(dict2) | 合并字典 | | dict(zip(list1,list2)) | 把列表转化成字典 | 把两个列表转为字典 | dict2 = dict([[‘key1’,‘value1’]]) | 把一个嵌套列表转为字典 | 把一个嵌套列表转为字典 | dict.clear() | 清除字典内的元素 | 清除字典内的元素 |
代码:
info = {'name':'qzp','age':'24','sex':'男'}
print(info['name'])
print(info['age'])
print(info['sex'])
for i in info:
print(i)
print(info.keys())
print(info.values())
print(info.items())
newId = input("请输入你加入的id")
info['id'] = newId
print("_"*20)
print('新增后遍历字典元素')
for i in info:
print(i,info[i])
del info['id']
print("删除后的遍历字典元素")
for i in info:
print(i,info[i])
del info;
info.clear(info);
info['name'] = 'wjw'
for i in info:
print(i,info[i])
for i in info.keys():
print(i)
for i in info.values():
print(i)
for key,value in info.items():
print(key,value)
myList = ['a','b','c','d','e','f']
for i,x in enumerate(myList):
print(i+1,x)
集合 set
定义
- set是一组key的集合,但不存储value
- key不可以重复
- set是无序的,重复的元素会被自s动过滤
常用操作
方法 | 操作名称 | 解释操作 |
---|
for i in myset:print(i) | 遍历集合 | 通过for循环遍历集合中的元素 | myset.update(set1) | 更新集合 | 将其他集合中的元素追加到当前集合中 | myset.add(key) | 添加元素 | 向当前集合中添加元素 | myset.remove(key) | 删除元素 | 移除当前集合中存在的元素,key不存在会报错 | val = myset.pop() | 弹出元素 | 随机弹出当前集合中的一个元素,val代表被弹出的元素 | myset.clear() | 清除元素 | 清除当前集合的所有元素 | del myset | 删除集合 | 删除整个集合 | len() | 长度 | 获取集合长度 | max() | 最大值 | 获取集合最大的元素 | min() | 最小值 | 获取集合最小的元素 | set() | 转换 | 其他类型对象转换成集合 |
小结
| 是否有序 | 是否可变类型 |
---|
列表[ ] | 有序 | 可变类型 | 元组( ) | 有序 | 不可变类型 | 字典{ } | 无序 key | 不可变 val可变 | 集合{ } | 无序 | 可变类型(不重复) |
函数
定义与调用
格式:
def 函数名():
代码
def printInfo():
print '------------------------------------'
print ' 人生苦短,我用Python'
print '------------------------------------'
定义了函数之后,就相当于有了一个具有某些功能的代码,想要让这些代码能够执行,需要调用它 调用函数很简单的,通过 函数名() 即可完成调用
printInfo()
函数参数
定义、调用带有参数的函数
def add2num(a, b):
c = a+b
print c
add2num(11, 22)
函数返回值
带返回值的函数
一个函数到底有没有返回值,就看有没有return,因为只有return才可以返回数据
def add2num(a, b):
c = a+b
return c
result = add2num(100,98)
print result
在python中返回多个值
>>> def divid(a, b):
... shang = a//b
... yushu = a%b
... return shang, yushu
...
>>> sh, yu = divid(5, 2)
>>> sh
5
>>> yu
1
文件操作
文件,就是把一些数据存放起来,可以让程序下一次执行的时候直接使用,而不必重新制作一份,省 时省力。
文件打开与关闭
打开文件
在python,使用open函数,可以打开一个已经存在的文件,或者创建一个新文件
open(文件名,访问模式)
示例如下:
f = open('test.txt', 'w')
访问模式:
访问模式 | 说明 |
---|
r | 以只读方式打开文件。文件的指针将会放在文件的开头。这是默认模式 | w | 打开一个文件只用于写入。如果该文件已存在则将其覆盖。如果该文件不存在,创建新文件 | a | 打开一个文件用于追加。如果该文件已存在,文件指针将会放在文件的结尾。也就是说,新的内容将会被写入到已有内容之后。如果该文件不存在,创建新文件进行写入 | rb | 以二进制格式打开一个文件用于只读。文件指针将会放在文件的开头。这是默认模式 | wb | 以二进制格式打开一个文件只用于写入。如果该文件已存在则将其覆盖。如果该文件不存在,创建新文件 | ab | 以二进制格式打开一个文件用于追加。如果该文件已存在,文件指针将会放在文件的结尾。也就是说,新的内容将会被写入到已有内容之后。如果该文件不存在,创建新文件进行写入 | r+ | 打开一个文件用于读写。文件指针将会放在文件的开头 | w+ | 打开一个文件用于读写。如果该文件已存在则将其覆盖。如果该文件不存在,创建新文件 | a+ | 打开一个文件用于读写。如果该文件已存在,文件指针将会放在文件的结尾。文件打开时会是追加模式。如果该文件不存在,创建新文件用于读写 | rb+ | 以二进制格式打开一个文件用于读写。文件指针将会放在文件的开头。 | wb+ | 以二进制格式打开一个文件用于读写。如果该文件已存在则将其覆盖。如果该文件不存在,创建新文件。 | ab+ | 以二进制格式打开一个文件用于追加。如果该文件已存在,文件指针将会放在文件的结尾。如果该文件不存在,创建新文件用于读写 |
注意:文件默认会新建并保留在当前项目文件目录下。
f = open('test.txt', 'w')
f.close()
文件读写
写数据
使用write()可以完成向文件写入数据
f = open('test.txt', 'w')
f.write('hello world, i am here!')
f.close()
如果文件不存在那么创建,如果存在那么就先清空,然后写入数据
读数据(read)
使用read(num)可以从文件中读取数据,num表示要从文件中读取的数据的长度(单位是字节),如果 没有传入num,那么就表示读取文件中所有的数据
f = open('test.txt', 'r')
content = f.read(5)
print(content)
print("-"*30)
content = f.read()
print(content)
f.close()
注意:
- 如果open是打开一个文件,那么可以不用写打开的模式,即只写 open(‘test.txt’)
- 如果使用读了多次,那么后面读取的数据是从上次读完后的位置开始的
读数据(readlines)
就像read没有参数时一样,readlines可以按照行的方式把整个文件中的内容进行一次性读取,并且返回的是一个列表,其中每一行的数据为一个元素。
f = open('test.txt', 'r')
content = f.readlines()
print(type(content))
i=1
for temp in content:
print("%d:%s"%(i, temp))
i+=1
f.close()
读数据(readline)
一次读一行 (指针一行一行的移动)
f = open('test.txt', 'r')
content = f.readline()
print("1:%s"%content)
content = f.readline()
print("2:%s"%content)
f.close()
文件的相关操作
有些时候,需要对文件进行重命名、删除等一些操作,python的os模块中都有这么功能
文件重命名
os模块中的rename()可以完成对文件的重命名操作
rename(需要修改的文件名, 新的文件名)
import os
os.rename("毕业论文.txt", "毕业论文-最终版.txt")
删除文件
os模块中的remove()可以完成对文件的删除操作
remove(待删除的文件名)
import os
os.remove("毕业论文.txt")
创建文件夹
import os
os.mkdir("张三")
获取当前目录
import os
os.getcwd()
改变默认目录
import os
os.chdir("../")
获取目录列表
import os
os.listdir("./")
删除文件夹
import os
os.rmdir("张三")
异常
简介
print '-----test--1---'
open('123.txt','r')
print '-----test--2---'
打开一个不存在的文件123.txt,当找不到123.txt 文件时,就会抛出给我们一个IOError类型的错 误,No such file or directory:123.txt (没有123.txt这样的文件或目录)
异常:
当Python检测到一个错误时,解释器就无法继续执行了,反而出现了一些错误的提示,这就是所 谓的"异常"
捕获异常 try…except…
- 把可能出现问题的代码,放在try中
- 把处理异常的代码,放在except中
try:
print('-----test--1---')
open('123.txt','r')
print('-----test--2---')
except IOError:
pass
说明:
- 此程序看不到任何错误,因为用except 捕获到了IOError异常,并添加了处理的方法 pass 表示实现了相应的实现,但什么也不做;
- 如果把pass改为print语句,那么就会输出其他信息
except捕获多个异常
try:
print('-----test--1---')
open('123.txt','r')
print('-----test--2---')
print(num)
except (IOError,NameError):
当捕获多个异常时,可以把要捕获的异常的名字,放到except 后,并使用元组的方式仅进行存储
获取异常的信息描述
try:
print("----test1------")
f = open("123.txt", "r")
print("----test2--------")
print(num)
except (IOError,NameError) as result:
print("产生了异常")
print(result)
except Exception as result:
try…except…finally…
在程序中,如果一个段代码必须要执行,即无论异常是否产生都要执行,那么此时就需要使用finally。 比如文件关闭,释放锁,把数据库连接返还给连接池等。
import time
try:
f = open('test.txt')
try:
while True:
content = f.readline()
if len(content) == 0:
break
time.sleep(2)
print(content)
except:
pass
finally:
f.close()
print('关闭文件')
except:
print("没有这个文件")
test.txt文件中每一行数据打印,但是我有意在每打印一行之前用time.sleep方法暂停2秒钟。这样 做的原因是让程序运行得慢一些。在程序运行的时候,按Ctrl+c中断(取消)程序。 我们可以观察到KeyboardInterrupt异常被触发,程序退出。但是在程序退出之前,finally从句仍 然被执行,把文件关闭。
python爬虫
任务
爬取豆瓣电影Top250的基本信息,包括电影的名称、豆瓣评分、评价数、电影概况、电影链接等。
网址:豆瓣电影 Top 250 (douban.com)
爬虫初识
- 什么是爬虫
网络爬虫,是一种按照一定规则,自动抓取互联网信息的程序或者脚本。由于互联网数据的多样性和资源的有限性,根据用户需求定向抓取相关网页并分析已成为如今主流的爬取策略。 - 爬虫可以做什么
你可以爬取图片,爬取视频等等,只要你能通过浏览器访问的数据都可以通过爬虫获取。 - 爬虫的本质是什么
模拟浏览器打开网页,获取网页中我们想要的那部分数据。
基本流程
-
准备工作 通过浏览器查看分析目标网页,学习编程基础规范。 -
获取数据 通过HTTP库向目标站点发起请求,请求可以包含额外的header等信息,如果服务器能正常响应,会得到一个Response,便是所要获取的页面内容。 -
解析内容 得到的内容可能是HTML、json等格式,可以用页面解析库、正则表达式等进行解析。 -
保存数据 保存形式多样,可以存为文本,也可以保存到数据库,或者保存特定格式的文件。
引入模块
-
引入自定义的模块 根目录下创建test文件夹,test文件夹下创建test1.py test1.py中有add方法 若在根目录下的test2文件夹中的py文件想使用add方法 引用方式:from test import test1 -
引入第三方模块 import -
引入 from bs4 import BeautifulSoup
import re
import urllib.request,urllib.error
import xlwt
import sqlite3
基本思路
def main():
baseUrl = "https://movie.douban.com/top250?start="
dataList = getData(baseUrl)
savePath = ".\\豆瓣电影Top250.xls"
saveData(savePath)
def getData(baseUrl):
dataList = []
return dataList;
def saveData(savePath):
pass
urllib介绍
是python内置的一个http请求库,不需要额外的安装。只需要关注请求的链接,参数,提供了强大的 解析。
模拟请求:
-
简单的一个get请求 import urllib.request
response = urllib.request.urlopen("http://www.baidu.com")
print(response.read().decode('utf-8'))
-
简单的post请求 import urllib.parse
import urllib.request
data = bytes(urllib.parse.urlencode({'hello':'world'}),encoding='utf-8')
reponse = urllib.request.urlopen('http://httpbin.org/post',data=data)
print(reponse.read().decode("utf-8"))
-
超时处理 import urllib.request
response = urllib.request.urlopen('http://httpbin.org/get',timeout=1)
print(response.read())
import urllib.request
import socket
import urllib.error
try:
response = urllib.request.urlopen('http://httpbin.org/get',timeout=0.01)
except urllib.error.URLError as e:
if isinstance(e.reason,socket.timeout):
print('time out!')
-
打印出响应类型,状态码,响应头 import urllib.request
response=urllib.request.urlopen('http://www.baidu.com')
print(type(response))
import urllib.request
response = urllib.request.urlopen('http://www.baidu.com')
print(response.status)
print(response.getheaders())
print(response.getheader('Server'))
print(response.read().decode('utf-8'))
由于使用urlopen无法传入参数,我们需要解决这个问题 我们需要声明一个request对象,通过这个对象来添加参数 import urllib.request
request = urllib.request.Request('https://python.org')
response = urllib.request.urlopen(request)
print(response.read().decode('utf-8'))
-
我们还可以分别创建字符串、字典等等来带入到request对象里面 from urllib import request,parse
url='http://httpbin.org/post'
headers={
'user-agent': 'Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36
(KHTML, like Gecko) Chrome/71.0.3578.98 Safari/537.36',
'Host':'httpbin.org'
}
dict={
'name':'jay'
}
data = bytes(parse.urlencode(dict),encoding='utf-8')
req=request.Request(url=url,data=data,headers=headers,method='POST')
response=request.urlopen(req)
print(response.read().decode('utf-8'))
beautiful soup
Beautiful Soup是一个库,提供一些简单的、python式的用来处理导航、搜索、修改分析树等功能,通过解析文档为用户提供需要抓取的数据。我们需要的每个电影都在一个<div>的标签中,且每个div标签都有一个属性class= "item”。
代码示例:
from bs4 import BeautifulSoup
file = open('./aa.html', 'rb')
html = file.read()
bs = BeautifulSoup(html,"html.parser")
print(bs.prettify())
print(bs.title)
print(bs.title.name)
print(bs.title.string)
print(bs.head)
print(bs.div)
print(bs.div["id"])
print(bs.a)
print(bs.find_all("a"))
BeautifulSoup4四大对象种类
BeautifulSoup4将复杂HTML文档转换成一个复杂的树形结构,每个节点都是Python对象,所有对象可以 归纳为4种:
-
Tag Tag通俗点讲就是HTML中的一个个标签,例如: from bs4 import BeautifulSoup
file = open('./aa.html', 'rb')
html = file.read()
bs = BeautifulSoup(html,"html.parser")
print(bs.title)
print(bs.head)
print(bs.a)
print(type(bs.a))
我们可以利用 soup 加标签名轻松地获取这些标签的内容,这些对象的类型是bs4.element.Tag。但是 注意,它查找的是在所有内容中的第一个符合要求的标签。 对于 Tag,它有两个重要的属性,是 name 和 attrs: from bs4 import BeautifulSoup
file = open('./aa.html', 'rb')
html = file.read()
bs = BeautifulSoup(html,"html.parser")
print(bs.name)
print(bs.head.name)
print(bs.a.attrs)
print(bs.a['class'])
bs.a['class'] = "newClass"
print(bs.a)
del bs.a['class']
print(bs.a)
-
NavigableString 既然我们已经得到了标签的内容,那么问题来了,我们要想获取标签内部的文字怎么办呢?很简单,用 .string 即可,例如: from bs4 import BeautifulSoup
file = open('./aa.html', 'rb')
html = file.read()
bs = BeautifulSoup(html,"html.parser")
print(bs.title.string)
print(type(bs.title.string))
-
BeautifulSoup
BeautifulSoup对象表示的是一个文档的内容。大部分时候,可以把它当作 Tag 对象,是一个特殊的 Tag,我们可以分别获取它的类型,名称,以及属性,例如:
from bs4 import BeautifulSoup
file = open('./aa.html', 'rb')
html = file.read()
bs = BeautifulSoup(html,"html.parser")
print(type(bs.name))
print(bs.name)
print(bs.attrs)
Comment 对象是一个特殊类型的 NavigableString 对象,其输出的内容不包括注释符号。
from bs4 import BeautifulSoup
file = open('./aa.html', 'rb')
html = file.read()
bs = BeautifulSoup(html,"html.parser")
print(bs.a)
print(bs.a.string)
print(type(bs.a.string))
遍历文档树
contents:获取Tag的所有子节点,返回一个list
print(bs.head.contents)
print(bs.head.contents[1])
children:获取Tag的所有子节点,返回一个生成器
for child in bs.body.children:
print(child)
搜索文档树
find_all(name, attrs, recursive, text, **kwargs)
在上面的例子中我们简单介绍了find_all的使用,接下来介绍一下find_all的更多用法-过滤器。这些过滤 器贯穿整个搜索API,过滤器可以被用在tag的name中,节点的属性等。
-
name参数 字符串过滤:会查找与字符串完全匹配的内容 a_list = bs.find_all("a")
print(a_list)
正则表达式过滤:如果传入的是正则表达式,那么BeautifulSoup4会通过search()来匹配内容 from bs4 import BeautifulSoup
import re
file = open('./aa.html', 'rb')
html = file.read()
bs = BeautifulSoup(html,"html.parser")
t_list = bs.find_all(re.compile("a"))
for item in t_list:
print(item)
列表:如果传入一个列表,BeautifulSoup4将会与列表中的任一元素匹配到的节点返回 t_list = bs.find_all(["meta","link"])
for item in t_list:
print(item)
方法:传入一个方法,根据方法来匹配 from bs4 import BeautifulSoup
file = open('./aa.html', 'rb')
html = file.read()
bs = BeautifulSoup(html,"html.parser")
def name_is_exists(tag):
return tag.has_attr("name")
t_list = bs.find_all(name_is_exists)
for item in t_list:
print(item)
-
kwargs参数: from bs4 import BeautifulSoup
import re
file = open('./aa.html', 'rb')
html = file.read()
bs = BeautifulSoup(html,"html.parser")
t_list = bs.find_all(id="head")
print(t_list)
t_list = bs.find_all(href=re.compile("http://news.baidu.com"))
print(t_list)
t_list = bs.find_all(class_=True)
for item in t_list:
print(item)
-
attrs参数: 并不是所有的属性都可以使用上面这种方式进行搜索,比如HTML的data-*属性: t_list = bs.find_all(data-foo="value")
如果执行这段代码,将会报错。我们可以使用attrs参数,定义一个字典来搜索包含特殊属性的tag: t_list = bs.find_all(attrs={"data-foo":"value"})
for item in t_list:
print(item)
-
text参数: 通过text参数可以搜索文档中的字符串内容,与name参数的可选值一样,text参数接受 字符串,正则 表达式,列表 from bs4 import BeautifulSoup
import re
file = open('./aa.html', 'rb')
html = file.read()
bs = BeautifulSoup(html, "html.parser")
t_list = bs.find_all(attrs={"data-foo": "value"})
for item in t_list:
print(item)
t_list = bs.find_all(text="hao123")
for item in t_list:
print(item)
t_list = bs.find_all(text=["hao123", "地图", "贴吧"])
for item in t_list:
print(item)
t_list = bs.find_all(text=re.compile("\d"))
for item in t_list:
print(item)
当我们搜索text中的一些特殊属性时,同样也可以传入一个方法来达到我们的目的: def length_is_two(text):
return text and len(text) == 2
t_list = bs.find_all(text=length_is_two)
for item in t_list:
print(item)
-
limit参数: 可以传入一个limit参数来限制返回的数量,当搜索出的数据量为5,而设置了limit=2时,此时只会返回 前2个数据 from bs4 import BeautifulSoup
import re
file = open('./aa.html', 'rb')
html = file.read()
bs = BeautifulSoup(html, "html.parser")
t_list = bs.find_all("a",limit=2)
for item in t_list:
print(item)
find_all除了上面一些常规的写法,还可以对其进行一些简写:
t_list = bs("a")
t_list = bs.a(text="新闻")
-
find() find()将返回符合条件的第一个Tag,有时我们只需要或一个Tag时,我们就可以用到find()方法了。当然 了,也可以使用find_all()方法,传入一个limit=1,然后再取出第一个值也是可以的,不过未免繁琐。 from bs4 import BeautifulSoup
import re
file = open('./aa.html', 'rb')
html = file.read()
bs = BeautifulSoup(html, "html.parser")
t_list = bs.find_all("title",limit=1)
print(t_list)
t = bs.find("title")
print(t)
t = bs.find("abc") print(t)
从结果可以看出find_all,尽管传入了limit=1,但是返回值仍然为一个列表,当我们只需要取一个值 时,远不如find方法方便。但是如果未搜索到值时,将返回一个None 在上面介绍BeautifulSoup4的时候,我们知道可以通过bs.div来获取第一个div标签,如果我们需要获取 第一个div下的第一个div, 我们可以这样: t = bs.div.div
t = bs.find("div").find("div")
-
CSS选择器 BeautifulSoup支持大部分的CSS选择器,在Tag获取BeautifulSoup对象的.select()方法中传入字符串参 数,即可使用CSS选择器的语法找到Tag:
-
通过标签名查找 print(bs.select('title'))
print(bs.select('a'))
-
通过类名查找 print(bs.select('.mnav'))
-
通过id查找 print(bs.select('#u1'))
-
组合查找 print(bs.select('div .bri'))
-
属性查找 print(bs.select('a[class="bri"]'))
print(bs.select('a[href="http://tieba.baidu.com"]'))
-
直接子标签查找 t_list = bs.select("head > title")
print(t_list)
-
兄弟节点标签查找 t_list = bs.select(".mnav ~ .bri")
print(t_list)
-
获取内容 t_list = bs.select("title")
print(bs.select('title')[0].get_text())
-
CSS选择器 BeautifulSoup支持大部分的CSS选择器,在Tag获取BeautifulSoup对象的.select()方法中传入字符串参 数,即可使用CSS选择器的语法找到Tag:
-
通过标签名查找 print(bs.select('title'))
print(bs.select('a'))
-
通过类名查找 print(bs.select('.mnav'))
-
通过id查找 print(bs.select('#u1'))
-
组合查找 print(bs.select('div .bri'))
-
属性查找 print(bs.select('a[class="bri"]'))
print(bs.select('a[href="http://tieba.baidu.com"]'))
-
直接子标签查找 t_list = bs.select("head > title")
print(t_list)
-
兄弟节点标签查找 t_list = bs.select(".mnav ~ .bri")
print(t_list)
-
获取内容 t_list = bs.select("title")
print(bs.select('title')[0].get_text())
正则提取
Re库功能函数:
正则表达式可以包含一些可选标志修饰符来控制匹配的模式。修饰符被指定为一个可选的标志。 多个标志可以通过按位 OR(|) 它们来指定。如 re.I | re.M 被设置成 I 和 M 标志:
主要是想入门python的语法,后面的爬虫 可视化数据就跳过了……
以下学习资料来源 https://github.com/jackfrued/Python-100-Days.git
面向对象
基础
面向对象比较官方的定义:
把一组数据结构和处理它们的方法组成对象(object),把相同行为的对象归纳为类(class),通过类的封装(encapsulation)隐藏内部细节,通过继承(inheritance)实现类的特化(specialization)和泛化(generalization),通过多态(polymorphism)实现基于对象类型的动态分派。
类和对象概念
简单的说,类是对象的蓝图和模板,而对象是类的实例。这个解释虽然有点像用概念在解释概念,但是从这句话我们至少可以看出,类是抽象的概念,而对象是具体的东西。在面向对象编程的世界中,一切皆为对象,对象都有属性和行为,每个对象都是独一无二的,而且对象一定属于某个类(型)。当我们把一大堆拥有共同特征的对象的静态特征(属性)和动态特征(行为)都抽取出来后,就可以定义出一个叫做“类”的东西。
类的定义和使用
在Python中可以使用class 关键字定义类,然后在类中通过之前学习过的函数来定义方法,这样就可以将对象的动态特征描述出来,代码如下所示。
class Student(object):
def __init__(self, name, age):
self.name = name
self.age = age
def study(self, course_name):
print('%s正在学习%s.' % (self.name, course_name))
def __str__(self):
return '这是海尔洗?机的说明书'
def __del__(self):
print(f'{self}对象已经被删除')
def watch_av(self):
if self.age < 18:
print('%s只能观看《熊出没》.' % self.name)
else:
print('%s正在观看电影.' % self.name)
创建和使用对象
def main():
stu1 = Student('骆昊', 38)
stu1.study('Python程序设计')
stu1.watch_av()
stu2 = Student('王大锤', 15)
stu2.study('思想品德')
stu2.watch_av()
if __name__ == '__main__':
main()
访问可见性
在Java中,通常将对象的属性设置为私有的或受保护的,简而言之,不允许外界访问,对象的方法通常是公开的。在Python中,属性和方法的访问权限只有两种,也就是公开的和私有的,如果希望属性是私有的,在给属性命名时可以用两个下划线作为开头,下面的代码可以验证这一点。
class Test:
def __init__(self, age):
self.__age = 18
def bar(self):
print(self.__age)
def main():
test = Test('hello')
test.bar()
if __name__ == "__main__":
main()
python没有真正意义上的私有,大多数Python程序员会遵循一种命名惯例就是让属性名以单下划线开头来表示属性是受保护的,本类之外的代码在访问这样的属性时应该要保持慎重。这种做法并不是语法上的规则,单下划线开头的属性和方法外界仍然是可以访问的,所以更多的时候它是一种暗示或隐喻。
class Test:
def __init__(self, age):
self.__age = 18
def bar(self):
print(self.__age)
def main():
test = Test('hello')
print(test._Test__age)
if __name__ == "__main__":
main()
(补充)python中带下划线或双下划线
- 以单下划线开头,表示这是一个保护成员,只有类对象和子类对象自己能访问到这些变量。以单下划线开头的变量和函数被默认是内部函数,使用from module import *时不会被获取,但是使用import module可以获取。实例._变量,可以被访问。
- 以单下划线结尾仅仅是为了区别该名称与关键词
- 双下划线开头,表示为私有成员,只允许类本身访问,子类也不行。在文本上被替换为_class__method
- 双下划线开头,双下划线结尾。一种约定,Python内部的名字,用来区别其他用户自定义的命名,以防冲突。是一些 Python 的“魔术”对象,表示这是一个特殊成员,例如:定义类的时候,若是添加__init__方法,那么在创建类的实例的时候,实例会自动调用这个方法,一般用来对实例的属性进行初使化,Python不建议将自己命名的方法写为这种形式。即以双下划线开头的方法和变量不会被继承
进阶
@property装饰器
之前的建议是将属性命名以单下划线开头,通过这种方式来暗示属性是受保护的,不建议外界直接访问,那么如果想访问属性可以通过属性的getter(访问器)和setter(修改器)方法进行对应的操作。如果要做到这点,就可以考虑使用@property包装器来包装getter和setter方法,使得对属性的访问既安全又方便,代码如下所示。
class Person(object):
def __init__(self, name, age):
self._name = name
self._age = age
@property
def name(self):
return self._name
@property
def age(self):
return self._age
@age.setter
def age(self, age):
self._age = age
def play(self):
if self._age <= 16:
print('%s正在玩飞行棋.' % self._name)
else:
print('%s正在玩斗地主.' % self._name)
def main():
person = Person('王大锤', 12)
person.play()
person.age = 22
person.play()
if __name__ == '__main__':
main()
__slots__魔法
Python是一门动态语言。通常,动态语言允许我们在程序运行时给对象绑定新的属性或方法,当然也可以对已经绑定的属性和方法进行解绑定。但是如果我们需要限定自定义类型的对象只能绑定某些属性,可以通过在类中定义__slots__变量来进行限定。需要注意的是__slots__的限定只对当前类的对象生效,对子类并不起任何作用。
class Person(object):
__slots__ = ('_name', '_age', '_gender')
def __init__(self, name, age):
self._name = name
self._age = age
@property
def name(self):
return self._name
@property
def age(self):
return self._age
@age.setter
def age(self, age):
self._age = age
def play(self):
if self._age <= 16:
print('%s正在玩飞行棋.' % self._name)
else:
print('%s正在玩斗地主.' % self._name)
def main():
person = Person('王大锤', 22)
person.play()
person._gender = '男'
静态方法和类方法静态方法和类方法
我们在类中定义的方法都是对象方法,也就是说这些方法都是发送给对象的消息。实际上,我们写在类中的方法并不需要都是对象方法,例如我们定义一个“三角形”类,通过传入三条边长来构造三角形,并提供计算周长和面积的方法,但是传入的三条边长未必能构造出三角形对象,因此我们可以先写一个方法来验证三条边长是否可以构成三角形,这个方法很显然就不是对象方法,因为在调用这个方法时三角形对象尚未创建出来(因为都不知道三条边能不能构成三角形),所以这个方法是属于三角形类而并不属于三角形对象的。我们可以使用静态方法来解决这类问题,代码如下所示。
from math import sqrt
class Triangle(object):
def __init__(self, a, b, c):
self._a = a
self._b = b
self._c = c
@staticmethod
def is_valid(a, b, c):
return a + b > c and b + c > a and a + c > b
def perimeter(self):
return self._a + self._b + self._c
def area(self):
half = self.perimeter() / 2
return sqrt(half * (half - self._a) *
(half - self._b) * (half - self._c))
def main():
a, b, c = 3, 4, 5
if Triangle.is_valid(a, b, c):
t = Triangle(a, b, c)
print(t.perimeter())
print(t.area())
else:
print('无法构成三角形.')
if __name__ == '__main__':
main()
和静态方法比较类似,Python还可以在类中定义类方法,类方法的第一个参数约定名为cls,它代表的是当前类相关的信息的对象(类本身也是一个对象,有的地方也称之为类的元数据对象),通过这个参数我们可以获取和类相关的信息并且可以创建出类的对象,代码如下所示。
class Student:
name="jom"
age=21
@classmethod
def classshow(cls,str):
print(cls,cls.name,cls.age,str)
p=Student()
print("输出实例p:")
print(p)
print("输出类名称Student:")
print(Student)
print("使用实例调用的结果:")
p.classshow("实例调用")
print("使用类名称调用的结果:")
Student.classshow("类名称调用")
输出实例p:
<__main__.Student object at 0x0000020FB08B6BC0>
输出类名称Student:
<class '__main__.Student'>
使用实例调用的结果:
<class '__main__.Student'> jom 21 实例调用
使用类名称调用的结果:
<class '__main__.Student'> jom 21 类名称调用
类之间的关系
类和类之间的关系有三种:is-a、has-a和use-a关系。
- is-a关系也叫继承或泛化,比如学生和人的关系、手机和电子产品的关系都属于继承关系。
- has-a关系通常称之为关联,比如部门和员工的关系,汽车和引擎的关系都属于关联关系;关联关系如果是整体和部分的关联,那么我们称之为聚合关系;如果整体进一步负责了部分的生命周期(整体和部分是不可分割的,同时同在也同时消亡),那么这种就是最强的关联关系,我们称之为合成关系。
- use-a关系通常称之为依赖,比如司机有一个驾驶的行为(方法),其中(的参数)使用到了汽车,那么司机和汽车的关系就是依赖关系。
利用类之间的这些关系,我们可以在已有类的基础上来完成某些操作,也可以在已有类的基础上创建新的类,这些都是实现代码复用的重要手段。复用现有的代码不仅可以减少开发的工作量,也有利于代码的管理和维护,这是我们在日常工作中都会使用到的技术手段。
继承和多态
刚才我们提到了,可以在已有类的基础上创建新类,这其中的一种做法就是让一个类从另一个类那里将属性和方法直接继承下来,从而减少重复代码的编写。提供继承信息的我们称之为父类,也叫超类或基类;得到继承信息的我们称之为子类,也叫派生类或衍生类。子类除了继承父类提供的属性和方法,还可以定义自己特有的属性和方法,所以子类比父类拥有的更多的能力,在实际开发中,我们经常会用子类对象去替换掉一个父类对象,这是面向对象编程中一个常见的行为,对应的原则称之为里氏替换原则。下面我们先看一个继承的例子。
class Person(object):
"""人"""
def __init__(self, name, age):
self._name = name
self._age = age
@property
def name(self):
return self._name
@property
def age(self):
return self._age
@age.setter
def age(self, age):
self._age = age
def play(self):
print('%s正在愉快的玩耍.' % self._name)
def watch_av(self):
if self._age >= 18:
print('%s正在观看电影.' % self._name)
else:
print('%s只能观看《熊出没》.' % self._name)
class Student(Person):
"""学生"""
def __init__(self, name, age, grade):
super().__init__(name, age)
self._grade = grade
@property
def grade(self):
return self._grade
@grade.setter
def grade(self, grade):
self._grade = grade
def study(self, course):
print('%s的%s正在学习%s.' % (self._grade, self._name, course))
class Teacher(Person):
"""老师"""
def __init__(self, name, age, title):
super().__init__(name, age)
self._title = title
@property
def title(self):
return self._title
@title.setter
def title(self, title):
self._title = title
def teach(self, course):
print('%s%s正在讲%s.' % (self._name, self._title, course))
def main():
stu = Student('王大锤', 15, '初三')
stu.study('数学')
stu.watch_av()
t = Teacher('骆昊', 38, '老叫兽')
t.teach('Python程序设计')
t.watch_av()
if __name__ == '__main__':
main()
子类在继承了父类的方法后,可以对父类已有的方法给出新的实现版本,这个动作称之为方法重写(override)。通过方法重写我们可以让父类的同一个行为在子类中拥有不同的实现版本,当我们调用这个经过子类重写的方法时,不同的子类对象会表现出不同的行为,这个就是多态(poly-morphism)。
from abc import ABCMeta, abstractmethod
class Pet(object, metaclass=ABCMeta):
"""宠物"""
def __init__(self, nickname):
self._nickname = nickname
@abstractmethod
def make_voice(self):
"""发出声音"""
pass
class Dog(Pet):
"""狗"""
def make_voice(self):
print('%s: 汪汪汪...' % self._nickname)
class Cat(Pet):
"""猫"""
def make_voice(self):
print('%s: 喵...喵...' % self._nickname)
def main():
pets = [Dog('旺财'), Cat('凯蒂'), Dog('大黄')]
for pet in pets:
pet.make_voice()
if __name__ == '__main__':
main()
在上面的代码中,我们将Pet 类处理成了一个抽象类,所谓抽象类就是不能够创建对象的类,这种类的存在就是专门为了让其他类去继承它。Python从语法层面并没有像Java或C#那样提供对抽象类的支持,但是我们可以通过abc 模块的ABCMeta 元类和abstractmethod 包装器来达到抽象类的效果,如果一个类中存在抽象方法那么这个类就不能够实例化(创建对象)。上面的代码中,Dog 和Cat 两个子类分别对Pet 类中的make_voice 抽象方法进行了重写并给出了不同的实现版本,当我们在main 函数中调用该方法时,这个方法就表现出了多态行为(同样的方法做了不同的事情)。
|