参考文献
- python 3.7官方文档;
- Bookschina爬虫案例
一、基础知识
1.装饰器与闭包
coding:utf-8
# 闭包
def f1(a,b):
def f2(a,b):
print(a+b)
return f2(a,b)
f1(1,2)
##装饰器--不带参数
def add_dec(f):
def ff():
print("start")
f()
print("end!!!!")
return ff
@add_dec
def add():
print("now")
add()
##装饰器--带参数
def add_dec(f):
def ff(a,b):
print("start")
f(a,b)
print("end!!!!")
return ff
@add_dec
def add(a,b):
print(a+b)
add(22,33)
2.系统编码
import sys
sys.getdefaultencoding()
3.return 与yield
def myList1(l):
for i in l:
return i
def myList2(l):
for i in l :
#如果不用for来遍历myList2,此条语句不会执行,因为返回的是生成器对象
print("yield")
yield i
a = [1,2,3,4,5]
print(myList1(a))
print(myList2(a))
for i in myList2(a):
print(i)
1
<generator object myList2 at 0x105a9bf10>
yield
1
yield
2
yield
3
yield
4
yield
5
4.property
class StudentClass1(object):
def __init__(self, name, score):
self.name = name
self.score = score
class StudentClass2(object):
def __init__(self, name, score):
self.name = name
self.__score = score
def get_score(self):
return self.__score
def set_score(self, score):
if score < 0 or score > 100:
raise ValueError('invalid score')
self.__score = score
class StudentClass3(object):
def __init__(self, name, score):
self.name = name
self.__score = score
@property
def score(self):
"""get方法"""
return self.__score
@score.setter
def score(self, score):
if score < 0 or score > 100:
raise ValueError('invalid score')
self.__score = score
class StudentClass4(object):
def __init__(self, name, score):
self.name = name
self.__score = score
def get_score(self):
"""get方法"""
return self.__score
def set_score(self, score):
if score < 0 or score > 100:
raise ValueError('invalid score')
self.__score = score
score = property(get_score,set_score)
if __name__ == "__main__":
# #st1可以使用点来访问私有变量
# st1 = StudentClass1('xiaobai',50)
# print(st1.score)
# st1.score=100
# print(st1.score)
# #st2无法使用点来访问私有变量
# st2 = StudentClass2('xiaoxin',70)
# print(st2.get_score())
# st2.set_score(90)
# print(st2.get_score())
# # 经过property装修后,可以使用点来访问
# st3 = StudentClass3('xiaoxin',70)
# print(st3.score)
# st3.score =99
# print(st3.score)
# 经过property()函数,可以使用点来访问
st4 = StudentClass4('xiaoxin',70)
print(st4.score)
st4.score =99
print(st4.score)
5.函数标注
: 表示声明变量的类型
-> 表示函数返回值的类型
In [6]: def pingfang(x:int,y:int =2) ->int:
...: return x**y
In [7]: pingfang(10)
Out[7]: 100
6.列表的特殊用途
作为栈使用—后进先出
In [8]: l = [1,3,4,5,6,9]
In [9]: l.pop()
Out[9]: 9
作为队列使用–先进先出
In [8]: l = [1,3,4,5,6,9]
In [10]: l.pop(0)
Out[10]: 1
列表用作这个目的相当低效。因为在列表的末尾添加和弹出元素非常快,但是在列表的开头插入或弹出元素却很慢,一般用下面的collections.deque
In [12]: from collections import deque
In [13]: q = deque([1,3,4,5,6,7])
In [14]: q
Out[14]: deque([1, 3, 4, 5, 6, 7])
In [15]: q.popleft()
Out[15]: 1
7.eval与exec用法
- 语法结构
eval(source, globals=None, locals=None, /)
exec(source, globals=None, locals=None, /)
# expression:这个参数是一个字符串,代表要执行的语句 。该语句受后面两个字典类型参数 globals 和 locals 的限制,只有在 globals 字典和 locals 字典作用域内的函数和变量才能被执行。
# globals:这个参数管控的是一个全局的命名空间,即 expression 可以使用全局命名空间中的函数。如果只是提供了 globals 参数,而没有提供自定义的 __builtins__,则系统会将当前环境中的 __builtins__ 复制到自己提供的 globals 中,然后才会进行计算;如果连 globals 这个参数都没有被提供,则使用 Python 的全局命名空间。
# locals:这个参数管控的是一个局部的命名空间,和 globals 类似,当它和 globals 中有重复或冲突时,以 locals 的为准。如果 locals 没有被提供,则默认为 globals。
- 区别
1.eval() 执行完会返回结果,而 exec() 执行完不返回结果(返回none);
2.eval() 中不识别等号,exec()中可以给变量赋值。 - 原码:https://github.com/python/cpython/blob/05d68a8bd84cb141be9f9335f5b3540f15a989c4/Python/ceval.c
8.对第二层字典的value求和
In [19]: allGuests
Out[19]:
{'Alice': {'apples': 5, 'pretzels': 12},
'Bob': {'ham sandwiches': 3, 'apples': 2},
'Carol': {'cups': 3, 'apple pies': 1}}
In [16]: a=0
In [17]: for d in allGuests.values():
...: a += sum(d.values())
In [18]: a
Out[18]: 26
9.小数字缓存池
Python 解释器对于数字有个小数字缓存池:-5~257, 原因是:地址数据最少是32位的,现在都是64位了,如果单独为一个小整数创建一个对象,10个地方用到这个小整数,那么就会在内存中创建10个存储的内存地址的空间,地址占用的数据长度比数据本身还大这样非常不划算。而有这个缓存池,python解释器内部就会共享这个小整数对象,不去开内存空间。从而减少内存的使用率,降低浪费。字符串也有内存池,给了2k空间,python内部有算法,按照内部权重排列,如果级别高了就把你放入内存。列表、字典都有
二、常见异常处理
1.爬虫爬取的数据格式处理
1)日期格式处理:"2018-01-01 / "
def str_time(value):
new_value = value.replace('/','')
return pd.to_datetime(new_value.strip())
data['book_time'] = data['book_time'].apply(str_time)
data.drop_duplicates(inplace=True)#数据去重
2)金额处理:“¥60.7”
def convert_float(value):
new_value = value.replace('¥','')
return np.float(new_value)
data['book_time']=data['book_time'].apply(convert_float)
3)字符转数字
#data里'tem_min'列为字符串数字,现将其转为数字
data['tem_min'].apply(lambda x :int(x))
#apply是针对一维数据,applymap是针对全部数据
2.单独导入字体
from matplotlib.font_manager import FontProperties
font_china=FontProperties(fname=r"/Users/gin2010/GIN/python/fonts/SimHei.ttf", size=15)
3.网上下载需要的字体,并导入到matplotlib库里
1)下载需要的字体并放入到matplotlib模块中:
/Users/gin2010/GIN/python/scrapy_project/scrapyENV/lib/python3.6/site-packages/matplotlib/mpl-data/fonts/ttf
2)删除系统matplotlib中的临时文件:
/Users/gin2010/.matplotlib/ 里的全部删除,尤其是fontlist-v300.json文件 一定要删除掉。
3)修改matplotlibrc文件中的内容:
/Users/gin2010/GIN/python/scrapy_project/scrapyENV/lib/python3.6/site-packages/matplotlib/mpl-data/matplotlibrc
font.family : sans-serif ####去掉前面的 # 号
.....
font.sans-serif ####去掉前面的 # 号,并在后面内容首位添加一个SimHei
axes.unicode_minus ####去掉前面的 # 号,将True改为False,解决负号‘-‘显示为方块的问题
4)在代码前动态加入配置
import matplotlib as mpl
#指定默认字体
mpl.rcParams['font.sans-serif'] = 'SimHei'
mpl.rcParams['font.family']='sans-serif'
#解决负号'-'显示为方块的问题
matplotlib.rcParams['axes.unicode_minus'] = False
4.SSLError
使用requests.post往https发送请求时出现sslerror
ssl.SSLCertVerificationError: ("hostname '172.26.2.199' doesn't match either of '*.aisino.com', 'aisino.com'",)
urllib3.exceptions.MaxRetryError: HTTPSConnectionPool(host='172.26.2.199', port=8443): Max retries exceeded with url: /Aisinojxpf/fpcy/fpcy.action (Caused by SSLError(SSLCertVerificationError("hostname '172.26.2.199' doesn't match either of '*.aisino.com', 'aisino.com'")))
解决办法
ssl._create_default_https_context = ssl._create_unverified_context
verify = False
import ssl
ssl._create_default_https_context = ssl._create_unverified_context
http_url ="https://*:8443/Aisinojxpf/fpcy/fpcy.action"
data_json = {"appcode":"QvPcIRUuqUng8X2dJlVeXMtfdu5pvZu/k0ZSMZha5pE=",
"data":{
"nsrsbh":"91110000710927388B",
"fpdm":"011001900111",
"fphm":"75209595",
"kprq":"20190517",
"je":"50.35",
"jym":"826515"
}
}
p = requests.post(http_url, json=data_json,verify = False)
5.pymysql异常处理
1)自动化用例中由于sql注入语句(1’ or ‘1’='1)导致的pymysql往数据库插入数据时,前面的单引号与括号里第一个单引号闭合,提示 “Truncated incorrect DOUBLE value”
results.append(["sql注入F",getstring.random_string_multiple(['SZ'], length) + "'or'1'='1"])
–解决办法: 增加一个引号
results.append(["sql注入F",getstring.random_string_multiple(['SZ'], length) + "''or''1''=''1"])
2)解决None没办法成功插入到数据库
# 用replace将None替换为Null
for temp in args:
if isinstance(temp,str):
args_temp.append('"%s"' % temp)
else:
args_temp.append(str(temp))
args_temp = [x.replace('None','Null') for x in args_temp]
三、常见模块使用
1.pysnooper基本使用
可以替换print作用,在函数前增加装饰,可查看变量值的变化
import os
import pysnooper as ps
DIR = "experience"
@ps.snoop()
def file(DIR):
FILE = os.path.join(os.getcwd(),DIR)
return FILE
if __name__ == "__main__":
file(DIR)
输出:
@ps.snoop("log.txt") #将日志输出到log文件中
@ps.snoop(watch=(DIR)) #查看除装饰函数里局部变量之外的变量的值,这里查看全局变量DIR的值
@ps.snoop(watch_explode=("file2","DIR")) #将DIR中的string用for循环遍历打印出来
@ps.snoop(prefix="****water****") #日志以****water****开头
2.在文件中间插入内容
思路:先读出此文件read(),并把文件内容传给content,通过字符串切片与查找的方法实现在中间插入内容。
f = open("./123.xml",'r')
data = """
<CheckPoint>
<Bh>2019082118118</Bh>
<RetMsg>123456</RetMsg>
</CheckPoint>
"""
content = f.read()
f.close()
num = content.find("</CasePool>")
content_new = content[:num] +"\n" + data +"\n" + content[num:]
f= open("./123.xml",'w')
f.write(content_new)
f.close()