time模块:
在python中,通常有以下几种方式来表示时间:
1、时间戳,如time.time
2、格式化的时间字符串,如'17/01/2017 10:17:00'
3、元组(struct_time),如gmtime、localtime等等
time.time():把从1970年开始到现在的所有时间转换成秒数,即时间戳
time.gmtime():将时间戳(秒数)转换成UTC时区的元组形式
time.localtime():将时间戳转换成当地时区的元组形式
这种元组形式的时间可以通过其内部的方法取得需要的时间元素。例:
x = time.localtime()
x.tm_year可以取得当前是哪一年
x.tm_mon可以取得当前是哪一月
x.tm_mday可以取得当前是哪一天
time.sleep(s):睡眠s秒
time.mktime(t):将元组(tuple)形式的时间转换成时间戳
time.strftime(format [, tuple]): 将元组形式的时间转换成格式化的时间字符串(用数字方式显示),若不指定tuple则转换当前的localtime
time.strptime(string, format):将格式化的时间字符串转换成元组形式的时间
time.asctime([tuple]): 将元组形式的时间转换成格式化的时间字符串(用英文方式显示),若不指定tuple则转换当前的localtime
time.ctime([seconds]): 将时间戳转换成格式化的时间字符串(用英文方式显示),若不指定时间戳则转换当前的时间戳
datetime模块:
datetime.datetime.now():取得当前的日期与时间
datetime.datetime.now() + datetime.datetime.delta(3):取得三天后的当前时间
datetime.datetime.now() + datetime.datetime.delta(-3):取得三天前的当前时间
datetime.datetime.now() + datetime.datetime.delta(hours=3):取得三小时后的当前时间
datetime.datetime.now() + datetime.datetime.delta(hours=-3):取得三小时前的当前时间
datetime.datetime.now().replace(minute=10,hour=10):时间替换
random模块:随机数
random.random():取得0-1之间的浮点随机数
random.uniform(1,10):取得1-10之间的浮点随机数,1和10可以任意指定
random.randint(1,3):取得1-3之间的任意随机数,包括1和3,这里的1和3可以任意指定
random.randrange(1,3):取得1-3之间的任意随机数,不包括3,这里的1和3可以任意指定
random.choice('equence):从序列sequence中随机取一个元素
random.sample(sequence,count):每次从序列sequence中随机取count个元素
random.shuffle(sequence):洗牌,将一个序列的顺序打乱
os模块:提供对操作系统进行调用的接口
os.getcwd():获取当前工作目录
os.chdir(path):切换目录
os.curdir:返回当前目录
os.pardir:返回当前目录的父目录
os.makedirs(name, mode=511, exist_ok=False):递归创建目录
例:os.makedirs(r'/a/b/c/d/e')
os.removedirs(name):若目录为空则删除,并递归到上一级目录,若还是为空则再删除,依此类推
os.mkdir(path, mode=511, *, dir_fd=None):创建单级目录,若父目录不存在则抛出异常
os.rmdir(path, *, dir_fd=None):删除单级空目录,若目录不为空则抛出异常
os.listdir(path=None):列出某路径下的所有文件,包括文件和目录
os.remove():删除一个文件
os.rename('oldname','newname'):重命名文件/目录
os.stat('path/to/filename'):获取文件/目录信息
os.sep:输出操作系统特定的路径分隔符,win下为’\\',linux下为'/'
os.linesep:输出当前平台使用的行终止符,win下为'\r\n',linux下为'\n'
os.pathsep:输出用于分割文件路径的字符串,存放多个路径的时候区分不同路径时用的分隔符
os.name:输出字符串指示当前使用平台。win-->'nt',linux-->'posix'
os.system('bash command'):运行shell命令,直接显示结果,返回值为命令执行的状态码
os.popen('bash command'):运行shell命令,命令结果作为返回值返回并打印至屏幕
os.startfile('/path/to/file'):以图形化方式打开一个程序,只适用于windows
os.environ:获取系统环境变量
os.urandom(n):返回指定n字节的加密强随机数据
os.path.abspath(path):返回path规范化的绝对路径
os.path.split(path):返回将path分割成以目录和文件名作为元素的2元素元组
os.path.dirname(path):返回path的目录。其实就是os.path.split(path)的第一个元素
os.path.basename(path):返回path最后的文件名。如果path以/或\结尾,那么就会返回空值。
其实就是os.path.split(path)的第二个元素
os.path.exists(path):判断path是否存在,存在返回True,否则返回False
os.path.isabs(path):判断path是不是一个绝对路径,是则返回True,否则返回False
os.path.isfile(path):判断path是不是一个文件,是则返回True,否则返回False
os.path.isdir(path):判断path是不是一个目录,是则返回True,否则返回False
os.path.join(path1 [, path2 [, ...]]):
将多个路径组合后返回,第一个绝对路径之前的参数将被忽略
os.path.getatime(path):返回path所指向的文件或目录的最后存取时间
os.path.getmtime(path):返回path所指向的文件或目录的最后修改时间
sys模块:提供对python进行调用的接口
sys.argv:命令行参数list,第一个元素是程序本身路径
sys.exit(n):退出程序,正常退出时exit(0),n可以是数字也可以是字符串
sys.version:获取python解释程序的版本信息
sys.maxint:最大的int值
sys.path:返回模块的搜索路径,初始化时使用PYTHONPATH环境变量的值
sys.platform:返回操作系统平台名称
sys.stdout.write('please: ')
va1 = sys.stdin.readline()[:-1]
sys.modules:返回当前系统已加载的所有模块信息字典
fileinput:遍历文本文件所有的行
fileinput.input(/path/to/file):返回一个可迭代的文件流类的实例对象
fileinput.filename():返回当前文件名
fileinput.lineno():返回当前行号
fileinput.filelineno():返回文件行数
fileinput.isfirstline():判断当前行是不是文件的第一行
fileinput.isstdin():检查最后一行是否来自于标准输入流
fileinput.nextfile():关闭当前文件并将指针移动到下一个文件
fileinput.close():关闭所有已打开的文件
shutil:专门用来copy文件,可以压缩包
shutil.copyfileobj(fsrc,fdst [, length]):
将ffsrc的内容拷贝至fdst中,可以通过length设置拷贝多少内容
shutil.copyfile(src,dst):拷贝src至dst
shutil.copymode(src,dst):仅拷贝权限。新文件的内容、组、用户均不变(谁创建的文件就是谁的)
shutil.copystat(src,dst):拷贝状态的信息,包括mode bits,atime,mtime,flags
shutil.copy(src,dst):拷贝文件和权限
shutil.copy2(src,dst):拷贝文件和状态信息
shutil.copytree(src,dst,symlink=False,ignore=None):递归的去拷贝文件
shutil.rmtree(path [, ignore_errors [, onerror]]):递归的去删除文件
shutil.move(src,dst):递归的去移动文件
shutil.make_archive(base_name,format,...):创建压缩包并返回文件路径,例如:zip、tar
base_name: 压缩包的文件名,也可以是压缩包的路径。只是文件名时,则保存至当前目录,否则保存至指定路径。
如:www => 保存至当前路径
如:/Users/sean/www => 保存至/Users/sean/www
format:压缩包种类。'zip'、'tar'、'bztar'、'gztar'
root_dir:要压缩的目录路径(默认当前目录)
owner:用户。默认当前用户
group:组。默认当前组
logger:用于记录日志。通常是logging.Logger对象
shutil对压缩包的处理是调用ZipFile和TarFile两个模块来进行的。
zipfile模块:
压缩:
z = zipfile.ZipFile('test.zip','w')
z.write('a.log')
z.write('data.data')
z.close()
解压:
z = zipfile.ZipFile('test.zip','r')
z.extractall()
z.close()
tarfile模块:
压缩:
tar = tarfile.open('your.tar','w')
tar.add('/Users/sean/www.zip',arcname='www.zip')
tar.add('/Users/sean/cmdb.zip',arcname='cmdb.zip')
tar.close()
解压:
tar = tarfile.open('your.tar','r')
tar.extractall()
tar.close()
json & pickle:用于序列化的两个模块
json,用于字符串和python数据类型间进行转换
把python内存中的数据类型转换成字符串存储在硬盘的文件上, 解决了不同语言、不同平台之间的数据交换问题。
import json
#字符串形式的json数据转化为字典
str = '{"name":"Jack","age":28}'
print(json.loads(str))
#将字典转成字符串形式的json数据
d = {"name":"Jack","age":28}
print(json.dumps(d))
#将转换后的json数据写入文件
d = {"name":"Jack","age":28}
json.dump(d,open("test.txt","w"))
#以字典形式读json文件
json.load(open("test.txt","r"))
Python的json模块提供了一种很简单的方式来编码和解码JSON数据。 其中两个主要的函数是 json.dumps() 和 json.loads() , 要比其他序列化函数库如pickle的接口少得多。
下面演示如何将一个Python数据结构转换为JSON:
import json
data = {
'name' : 'ACME',
'shares' : 100,
'price' : 542.23
}
json_str = json.dumps(data)
下面演示如何将一个JSON编码的字符串转换回一个Python数据结构:
data = json.loads(json_str)
如果你要处理的是文件而不是字符串,你可以使用 json.dump() 和 json.load() 来编码和解码JSON数据。例如:
# Writing JSON data
with open('data.json', 'w') as f:
json.dump(data, f)
# Reading data back
with open('data.json', 'r') as f:
data = json.load(f)
用法示例:
相对于python解析XML来说,我还是比较喜欢json的格式返回,现在一般的api返回都会有json与XML格式的选择,json的解析起来个人觉得相对简单些
先看一个简单的豆瓣的图书查询的api返回
http://api.douban.com/v2/book/isbn/9787218087351
{"rating":{"max":10,"numRaters":79,"average":"9.1","min":0},"subtitle":"","author":["野夫"],"pubdate":"2013-9","tags":[{"count":313,"name":"野夫","title":"野夫"},{"count":151,"name":"散文随笔","title":"散文随笔"},{"count":83,"name":"身边的江湖","title":"身边的江湖"},{"count":82,"name":"土家野夫","title":"土家野夫"},{"count":70,"name":"散文","title":"散文"},{"count":44,"name":"中国文学","title":"中国文学"},{"count":43,"name":"随笔","title":"随笔"},{"count":38,"name":"中国现当代文学","title":"中国现当代文学"}],"origin_title":"","image":"http://img5.douban.com/mpic/s27008269.jpg","binding":"","translator":[],"catalog":"自序 让记忆抵抗n001 掌瓢黎爷n024 遗民老谭n039 乱世游击:表哥的故事n058 绑赴刑场的青春n076 风住尘香花已尽n083 “酷客”李斯n100 散材毛喻原n113 颓世华筵忆黄门n122 球球外传:n一个时代和一只小狗的际遇n141 童年的恐惧与仇恨n151 残忍教育n167 湖山一梦系平生n174 香格里拉散记n208 民国屐痕","pages":"256","images":{"small":"http://img5.douban.com/spic/s27008269.jpg","large":"http://img5.douban.com/lpic/s27008269.jpg","medium":"http://img5.douban.com/mpic/s27008269.jpg"},"alt":"http://book.douban.com/subject/25639223/","id":"25639223","publisher":"广东人民出版社","isbn10":"7218087353","isbn13":"9787218087351","title":"身边的江湖","url":"http://api.douban.com/v2/book/25639223","alt_title":"","author_intro":"郑世平,笔名野夫,网名土家野夫。毕业于武汉大学,曾当过警察、囚徒、书商。曾出版历史小说《父亲的战争》、散文集《江上的母亲》(获台北2010国际书展非虚构类图书大奖,是该奖项第一个大陆得主)、散文集《乡关何处》(被新浪网、凤凰网、新华网分别评为2012年年度好书)。","summary":"1.野夫书稿中被删减最少,最能体现作者观点、情感的作品。n2.文字凝练,具有极强的感染力。以一枝孤笔书写那些就在你我身边的大历史背景下普通人的生活变迁。n3. 柴静口中“一半像警察,一半像土匪”的野夫,以其特有的韵律表达世间的欢笑和悲苦。","price":"32元"}
看起来别提多乱了,现在我们将其格式进行简单的整理
{
rating: {
max: 10,
numRaters: 79,
average: "9.1",
min: 0
},
subtitle: "",
author: [
"野夫"
],
pubdate: "2013-9",
tags: [
{
count: 313,
name: "野夫",
title: "野夫"
},
{
count: 151,
name: "散文随笔",
title: "散文随笔"
},
{
count: 83,
name: "身边的江湖",
title: "身边的江湖"
},
{
count: 82,
name: "土家野夫",
title: "土家野夫"
},
{
count: 70,
name: "散文",
title: "散文"
},
{
count: 44,
name: "中国文学",
title: "中国文学"
},
{
count: 43,
name: "随笔",
title: "随笔"
},
{
count: 38,
name: "中国现当代文学",
title: "中国现当代文学"
}
],
origin_title: "",
image: "http://img5.douban.com/mpic/s27008269.jpg",
binding: "",
translator: [ ],
catalog: "自序 让记忆抵抗 001 掌瓢黎爷 024 遗民老谭 039 乱世游击:表哥的故事 058 绑赴刑场的青春 076 风住尘香花已尽 083 “酷客”李斯 100 散材毛喻原 113 颓世华筵忆黄门 122 球球外传: 一个时代和一只小狗的际遇 141 童年的恐惧与仇恨 151 残忍教育 167 湖山一梦系平生 174 香格里拉散记 208 民国屐痕",
pages: "256",
images: {
small: "http://img5.douban.com/spic/s27008269.jpg",
large: "http://img5.douban.com/lpic/s27008269.jpg",
medium: "http://img5.douban.com/mpic/s27008269.jpg"
},
alt: "http://book.douban.com/subject/25639223/",
id: "25639223",
publisher: "广东人民出版社",
isbn10: "7218087353",
isbn13: "9787218087351",
title: "身边的江湖",
url: "http://api.douban.com/v2/book/25639223",
alt_title: "",
author_intro: "郑世平,笔名野夫,网名土家野夫。毕业于武汉大学,曾当过警察、囚徒、书商。曾出版历史小说《父亲的战争》、散文集《江上的母亲》(获台北2010国际书展非虚构类图书大奖,是该奖项第一个大陆得主)、散文集《乡关何处》(被新浪网、凤凰网、新华网分别评为2012年年度好书)。",
summary: "1.野夫书稿中被删减最少,最能体现作者观点、情感的作品。 2.文字凝练,具有极强的感染力。以一枝孤笔书写那些就在你我身边的大历史背景下普通人的生活变迁。 3. 柴静口中“一半像警察,一半像土匪”的野夫,以其特有的韵律表达世间的欢笑和悲苦。",
price: "32元"
}
下面我们通过python来取出想要的信息,比如我们想要rating,images里的large和summary
import urllib2
import json
html = urllib2.urlopen(r'http://api.douban.com/v2/book/isbn/9787218087351')
hjson = json.loads(heml.read())
print hjson['rating']
print hjson['images']['large']
print hjson['summary']
pickle,用于python特有的类型和python的数据类型间进行转换把python内存中的任意数据类型转换成字符串存储在硬盘的文件上、
两者均提供了四个功能:dumps、dump、loads、load
dumps和loads直接在内存中操作,不对文件进行操作
dump和load会对文件进行操作:写入和读取
shelve:一个简单的字典类型的(key,value),将内存数据通过文件持久化存储的模块, 可以持久化存储任何pickle可支持的python数据类型
写入:
d = shelve.open('shelve_test')#打开一个文件
class Test(object):
def __init__(self,n):
self.n = n
t = Test(123)
t2 = Test(1234567)
name = ['tom','jerry','test']
d['test'] = name #持久化列表
d['t1'] = t #持久化类
d['t2'] = t2
d.close()
读取:
d.get('test')
d.get('t1')
d.get('t2')
xml:用来在python中处理xml
import xml.etree.ElementTree as ET
tree = ET.parse('xmltest.xml')#要处理的文件名
root = tree.getroot()
print(root.tag)#打印根标签名
#遍历xml文档
for child in root:
print(child.tag,child.attrib)
for i in child:
print(i.tag,i.text)
#只遍历year节点
for node in root.iter('year'):
print(node.tag,node.text)
#修改
for node in root.iter('year'):
new_year = int(node.text) + 1
node.text = str(new_year)
node.set("updated_by","sean")
tree.write('xmltest.xml')
#删除node
for country in root.findall('country'):
rank = int(country.find('rank').text)
if rank > 50:
root.remove(country)
tree.write('output.xml')
configparser:生成和修改常见配置文档生成:
import configparser
config = configparser.ConfigParser()
config['DEFAULT'] = {'ServerAliveInterval':'45',
'Compression':'yes',
'CompressionLevel':'9'}
config['bitbucket.org'] = {}
config['bitbucket.org']['User'] = 'hg'
config['topsecret.server.com'] = {}
topsecret = config['topsecret.server.com']
topsecret['Host Port'] = '50022'
topsecret['ForwardX11'] = 'no'
config['DEFAULT']['ForwardX11'] = 'yes'
with open('example.ini','w') as configfile:
config.write(configfile)
读取:
conf = configparser.ConfigParser()
conf.read('example.ini')
print(conf.defaults())
print(conf['bitbucket.org']['user'])
hashlib:用于加密相关的操作 ,3.x系列代替了2.x系列中的md5模块和sha模块。主要提供SHA1、SHA224、SHA256、SHA284、SHA512和MD5算法
import hashlib
m = hashlib.md5()
m.update(b'Hello')
m.update(b"It's me")
print(m.digest())#二进制格式hash
print(m.hexdigest())#十六进制格式hash
注意:前面执行了两次update,然后才打印的结果,此时的结果是两次update的对象加在一起生成的hash
webbrowser:
webbrowser.open(url):打开一个网页
paramiko模块,通过ssh2协议远程登录服务器执行命令或上传下载文件
ssh 公钥密钥连接
RSA -非对称密钥验证
公钥 public key
私钥 private key
10.0.0.31 ----> 10.0.0.41
私钥 公钥
10.0.0.31先生成一对公钥和私钥,将公钥给要被登录的机器
ssh-keygen生成一对公钥私钥,id_rsa.pub公钥,id_rsa私钥
将公钥放到.ssh/authorized_keys下面
ssh-copy-id "-p52113 [email protected]"
基于账号密码的形式,执行命令或上传下载文件
import paramiko
# 基于账号密码执行命令
# 创建SSH对象
ssh = paramiko.SSHClient()
# 允许连接不在know_hosts文件中的机器
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
# 连接服务器
ssh.connect(hostname="192.168.80.20", port=22, username="root", password="test@2015")
# 执行命令
stdin, stdout, stderr = ssh.exec_command("free -m")
# 获取命令结果
res, err = stdout.read(), stderr.read()
result = res if res else err
print(result.decode())
# 关闭连接
ssh.close()
# 基于账号密码的上传下载
transport = paramiko.Transport(("192.168.80.20", 22))
transport.connect(username="root", password="test@2015")
sftp = paramiko.SFTPClient.from_transport(transport)
# 将location.py上传至服务器的/tmp/test.py
sftp.put("高级FTP.png", "/root/高级FTP.png")
# 将remove_path下载到本地local_path
sftp.get("remove_path", "local_path")
transport.close()
# SSHClient 封装 Transport
transport = paramiko.Transport(('hostname', 22))
transport.connect(username='wupeiqi', password='123')
ssh = paramiko.SSHClient()
ssh._transport = transport
stdin, stdout, stderr = ssh.exec_command('df')
print(stdout.read().decode())
transport.close()
基于密钥的形式,执行命令或上传下载文件
import paramiko
# 基于密钥执行命令
private_key = paramiko.RSAKey.from_private_key_file("id_rsa")
ssh = paramiko.SSHClient()
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
ssh.connect(hostname="192.168.80.24", port=22, username="root", pkey=private_key)
stdin, stdout, stderr = ssh.exec_command("ifconfig")
res, err = stdout.read(), stderr.read()
result = res if res else err
print(result.decode())
ssh.close()
# 基于密钥的上传下载
private_key = paramiko.RSAKey.from_private_key_file("id_rsa")
transport = paramiko.Transport(("192.168.80.24", 22))
transport.connect(username="root", pkey=private_key)
sftp = paramiko.SFTPClient.from_transport(transport)
sftp.get("test.txt", "1")
transport.close()
# SSHClient 封装 Transport
private_key = paramiko.RSAKey.from_private_key_file('/home/auto/.ssh/id_rsa')
transport = paramiko.Transport(('hostname', 22))
transport.connect(username='wupeiqi', pkey=private_key)
ssh = paramiko.SSHClient()
ssh._transport = transport
stdin, stdout, stderr = ssh.exec_command('df')
transport.close()
生成激活码
#!/usr/bin/env python
#encoding:utf-8
#Author:sean
import string
import random
#激活码中的字符和数字
field = string.letters + string.digits
#获得四个字母和数字的随机组合
def getRandom():
return ''.join(random.sample(field,4))
#生成的每个激活码中有几组
def concatenate(group):
return '-'.join([getRandom() for i in range(group)])
#生成n组激活码
def generate(n):
return [concatenate(4) for i in range(n)]
if __name__ == '__main__':
print generate(10)
统计单词
#!/usr/bin/env python
#encoding:utf-8
import re
from collections import Counter
FileSource = './media/abc.txt'
def getMostCommonWord(articlefilesource):
'''输入一个英文的纯文本文件,统计其中的单词出现的个数'''
pattern = r'[A-Za-z]+|\$?\d+%?$'
with open(articlefilesource) as f:
r = re.findall(pattern,f.read())
return Counter(r).most_common()
if __name__ == '__main__':
print getMostCommonWord(FileSource)
提取网页正文
#!/usr/bin/env python
#encoding:utf-8
from goose import Goose
from goose.text import StopWordsChinese
import sys
#要分析的网页url
url = '
def extract(url):
'''
提取网页正文
'''
g = Goose({'stopwords_class':StopWordsChinese})
artlcle = g.extract(url=url)
return artlcle.cleaned_text
if __name__ == '__main__':
print extract(url)
selectors模块是在python3.4版本中引进的,它封装了IO多路复用中的select和epoll,能够更快,更方便的实现多并发效果。
官方文档见:https://docs.python.org/3/library/selectors.html
以下是一个selectors模块的代码示范:
#!/usr/bin/python
#Author:sean
import selectors
import socket
#selectors模块默认会用epoll,如果你的系统中没有epoll(比如windows)则会自动使用select
sel = selectors.DefaultSelector() #生成一个select对象
def accept(sock, mask):
conn, addr = sock.accept() # Should be ready
print('accepted', conn, 'from', addr)
conn.setblocking(False) #设定非阻塞
sel.register(conn, selectors.EVENT_READ, read) #新连接注册read回调函数
def read(conn, mask):
data = conn.recv(1024) # Should be ready
if data:
print('echoing', repr(data), 'to', conn)
conn.send(data)
else:
print('closing', conn)
sel.unregister(conn)
conn.close()
sock = socket.socket()
sock.bind(('localhost', 8080))
sock.listen()
sock.setblocking(False)
sel.register(sock, selectors.EVENT_READ, accept) #把刚生成的sock连接对象注册到select连接列表中,并交给accept函数处理
while True:
events = sel.select() #默认是阻塞,有活动连接就返回活动的连接列表
#这里看起来是select,其实有可能会使用epoll,如果你的系统支持epoll,那么默认就是epoll
for key, mask in events:
callback = key.data #去调accept函数
callback(key.fileobj, mask) #key.fileobj就是readable中的一个socket连接对象
logging模块
#很多程序都有记录日志的需求,并且日志中包含的信息即有正常的程序访问日志,还可能有错误、警告等信息输出,python的logging模块提供了标准的日志接口,你可以通过它存储各种格式的日志,logging的日志可以分为 debug(), info(), warning(), error() and critical() 5个级别
import logging
#打印日志
logging.warning("user [alex] attempted wrong password more than 3 times")
logging.critical("server is down")
#把日志写到文件中
#其中下面这句中的level=loggin.INFO意思是,把日志纪录级别设置为INFO,也就是说,只有比日志是INFO或比INFO级别更高的日志才会被纪录到文件里,在这个例子, 第一条日志是不会被纪录的,如果希望纪录debug的日志,那把日志级别改成DEBUG就行了。
logging.basicConfig(filename="example.log",level=logging.INFO)
logging.debug("This is debug message")
logging.info("This is info message")
logging.warning("This is warning message")
#给日志加上时间
logging.basicConfig(filename="example.log",level=logging.INFO,format="%(asctime)s %(message)s",datefmt="%Y-%m-%d %H:%M:%S")
logging.warning("This is warning message")
# 日志格式
# %(name)s
# Logger的名字
# %(levelno)s
# 数字形式的日志级别
# %(levelname)s
# 文本形式的日志级别
# %(pathname)s
# 调用日志输出函数的模块的完整路径名,可能没有
# %(filename)s
# 调用日志输出函数的模块的文件名
# %(module)s
# 调用日志输出函数的模块名
# %(funcName)s
# 调用日志输出函数的函数名
# %(lineno)d
# 调用日志输出函数的语句所在的代码行
# %(created)f
# 当前时间,用UNIX标准的表示时间的浮 点数表示
# %(relativeCreated)d
# 输出日志信息时的,自Logger创建以 来的毫秒数
# %(asctime)s
# 字符串形式的当前时间。默认格式是 “2003-07-08 16:49:45,896”。逗号后面的是毫秒
# %(thread)d
# 线程ID。可能没有
# %(threadName)s
# 线程名。可能没有
# %(process)d
# 进程ID。可能没有
# %(message)s
# 用户输出的消息
logging.basicConfig(filename="example.log",
level=logging.INFO,
format="%(asctime)s %(levelname)s - %(message)s",
datefmt="%Y-%m-%d %H:%M:%S")
logging.debug("This is debug")
logging.info("This is info")
logging.warning("This is warning")
logging.error("This is error")
logging.critical("This is critical")
#将日志分别以文件和控制台形式分别输出
# create logger
logger = logging.getLogger('TEST-LOG')
logger.setLevel(logging.DEBUG)
# create console handler and set level to debug
ch = logging.StreamHandler()
ch.setLevel(logging.DEBUG)
# create file handler and set level to warning
fh = logging.FileHandler("access.log")
fh.setLevel(logging.WARNING)
# create formatter
formatter = logging.Formatter(fmt='%(asctime)s - %(name)s - %(levelname)s - %(message)s',datefmt="%Y-%m-%d %H:%M:%S")
# add formatter to ch and fh
ch.setFormatter(formatter)
fh.setFormatter(formatter)
# add ch and fh to logger
logger.addHandler(ch)
logger.addHandler(fh)
# 'application' code
logger.debug('debug message')
logger.info('info message')
logger.warn('warn message')
logger.error('error message')
logger.critical('critical message')
#截断日志
import logging
from logging import handlers
logger = logging.getLogger(__name__)
log_file = "timelog.log"
#fh = handlers.RotatingFileHandler(filename=log_file,maxBytes=10,backupCount=3)
fh = handlers.TimedRotatingFileHandler(filename=log_file,when="D",interval=1,backupCount=5)
#filename 日志文件
#when 以什么时间截断,天、小时、分钟、秒
#interval 时间间隔
#backupCount 保留几个备份
formatter = logging.Formatter(fmt='%(asctime)s %(module)s:%(lineno)d %(message)s',
datefmt="%Y-%m-%d %H:%M:%S")
fh.setFormatter(formatter)
logger.addHandler(fh)
logger.warning("test1")
logger.warning("test12")
logger.warning("test13")
logger.warning("test14")
re模块
import re
# 常用正则表达式符号
# '.' 默认匹配除\n之外的任意一个字符若指定flag DOTALL, 则匹配任意字符包括换行
# '^' 匹配字符开头若指定flags MULTILINE, 这种也可以匹配上(r"^a", "\nabc\neee", flags=re.MULTILINE)
# '$' 匹配字符结尾或e.search("foo$", "bfoo\nsdfsf", flags=re.MULTILINE).group()也可以
# '*' 匹配 * 号前的字符0次或多次re.findall("ab*", "cabb3abcbbac")结果为['abb', 'ab', 'a']
# '+' 匹配前一个字符1次或多次re.findall("ab+", "ab+cd+abb+bba")结果['ab', 'abb']
# '?' 匹配前一个字符1次或0次
# '{m}' 匹配前一个字符m次
# '{n,m}' 匹配前一个字符n到m次re.findall("ab{1,3}", "abb abc abbcbbb")结果'abb', 'ab', 'abb']
# '|' 匹配 | 左或 | 右的字符re.search("abc|ABC", "ABCBabcCD").group()结果'ABC'
# '(...)' 分组匹配re.search("(abc){2}a(123|456)c", "abcabca456c").group()结果abcabca456c
# '\A' 只从字符开头匹配re.search("\Aabc", "alexabc")是匹配不到的
# '\Z' 匹配字符结尾同$
# '\d' 匹配数字0 - 9
# '\D' 匹配非数字
# '\w' 匹配[A - Za - z0 - 9]
# '\W' 匹配非[A - Za - z0 - 9]
# 's' 匹配空白字符、\t、\n、\r, re.search("\s+", "ab\tc1\n3").group()结果'\t'
# '(?P
#最常用的匹配语法
# re.match 从头开始匹配
# re.search 匹配包含
# re.findall 把所有匹配到的字符放到以列表中的元素返回
# re.splitall 以匹配到的字符当做列表分隔符
# re.sub 匹配字符并替换
hashlib模块
import hashlib
#md5
m = hashlib.md5()
m.update(b"admin") #m.update("admin".encode("utf-8"))
print(m.hexdigest())
#如果数据量很大,可以分块多次调用update(),最后计算的结果是一样的
md5 = hashlib.md5()
md5.update('how to use md5 in '.encode('utf-8'))
md5.update('python hashlib?'.encode('utf-8'))
print(md5.hexdigest())
#sha1
m = hashlib.sha1()
m.update(b"admin")
print(m.hexdigest())
#sha256
m = hashlib.sha256()
m.update(b"admin")
print(m.hexdigest())
#sha512
m = hashlib.sha512()
m.update(b"admin")
print(m.hexdigest())
#hmac
#网络的消息加密传输
import hmac
h_obj = hmac.new(b"salt",b"hello")
xml模块
import xml.etree.ElementTree as ET
tree = ET.parse("test.xml")
root = tree.getroot()
print(root.tag)
#遍历xml文档
for child in root:
print(child.tag,child.attrib)
for i in child:
print(i.tag,i.text)
#只遍历year节点
for node in root.iter("year"):
print(node.tag,node.text)
#修改xml文档内容
for node in root.iter("year"):
new_year = int(node.text) + 1
node.text = str(new_year)
node.set("updated","yes")
tree.write("test.xml")
#删除xml文档内容
for country in root.findall("country"):
rank = int(country.find("rank").text)
if rank > 50:
root.remove(country)
tree.write("test.xml")
#自己创建xml文档
new_xml = ET.Element("namelist")
name = ET.SubElement(new_xml,"name",attrib={"enrolled":"yes"})
age = ET.SubElement(name,"age",attrib={"checked":"no"})
sex = ET.SubElement(name,"sex")
age.text = "33"
sex.text = "man"
name2 = ET.SubElement(new_xml,"name",attrib={"enrolled":"no"})
age = ET.SubElement(name2,"age")
age.text = "29"
et = ET.ElementTree(new_xml) #生成文档对象
et.write("text1.xml",encoding="utf-8",xml_declaration=True)
ET.dump(new_xml) #打印生成格式
shelve模块
import shelve
d = shelve.open('shelve_test')
def stu_data(name,age):
print("register stu",name,age)
t = stu_data("Jack",28)
name = ["Jack","Tom"]
d["test"] = name
d["func"] = stu_data
d.close()
shutil模块
import shutil
#将文件内容拷贝到另一个文件中,可以部分内容
f1 = open("1","r")
f2 = open("2","w")
shutil.copyfileobj(f1,f2)
#拷贝文件
shutil.copyfile("1","2")
#只拷贝文件权限
shutil.copymode("1","2")
#拷贝状态的信息,包括:mode bits, atime, mtime, flags
shutil.copystat("1","2")
#拷贝文件和权限
shutil.copy("1","2")
#拷贝文件和状态信息
shutil.copy2("1","2")
#递归的去拷贝文件,ignore忽略
shutil.copytree("D:\learn_python3\函数和常用模块\作业1\员工信息表","test",ignore=shutil.ignore_patterns("*.py"))
#递归删除
shutil.rmtree("D:\learn_python3\练习\\111")
#递归移动
shutil.move("原路径","目标路径")
#压缩文件
# base_name: 压缩包的文件名,也可以是压缩包的路径。只是文件名时,则保存至当前目录,否则保存至指定路径,
# 如:www =>保存至当前路径
# 如:/Users/wupeiqi/www =>保存至/Users/wupeiqi/
# format: 压缩包种类,“zip”, “tar”, “bztar”,“gztar”
# root_dir: 要压缩的文件夹路径(默认当前目录)
# owner: 用户,默认当前用户
# group: 组,默认当前组
# logger: 用于记录日志,通常是logging.Logger对象
shutil.make_archive("20170213","zip","D:\learn_python3\函数和常用模块")
#解压zipfile
import zipfile
z = zipfile.ZipFile("zip_file_name","r")
z.extractall() #可设置解压路径
z.close()
#解压tarfile
import tarfile
tar = tarfile.open("tar_file_name","r")
tar.extractall() #可设置解压路径
tar.close()
sys模块
import sys
#返回模块的搜索路径,初始化时使用PYTHONPATH环境变量的值
print(sys.path)
#返回操作系统平台名称
print(sys.platform)
#命令行参数List,第一个元素是程序本身路径
print(sys.argv)
#退出程序,正常退出时exit(0)
#sys.exit(0)
#获取Python解释程序的版本信息
print(sys.version)
subprocess模块
# os.system 输出命令结果,返回执行结果,0为执行正确,非0为执行错误
# os.popen("dir").read() 保存命令的执行结果输出
import subprocess
subprocess.run(["df","-h"])
subprocess.run("df -h | grep sda1",shell=True)
subprocess.call(["df","-h"]) #等于os.system 输出命令结果,返回执行结果,0为执行正确,非0为执行错误
subprocess.check_call(["df","-h"]) #命令存在输出命令结果,返回执行结果,命令不存在报错
subprocess.getstatusoutput("df -h") #接收字符串格式命令,返回元祖,第一个元素为执行状态,第二个元素为命令结果
subprocess.getoutput("df -h") #接收字符串格式命令,返回结果
subprocess.check_output(["df","-h"]) #执行正确返回结果,执行错误报错
res = subprocess.Popen("ifconfig|grep 192",shell=True,stdout=subprocess.PIPE,stderr=subprocess.PIPE)
res.stdin.read() #抓取输入
res.stdout.read() #抓取输出
res.stderr.read() #抓取错误
res = subprocess.Popen("sleep 10;echo 'hello'",shell=True,stdout=subprocess.PIPE,stderr=subprocess.PIPE,cmd="/tmp")
print(res.poll()) #结合poll执行命令比较长的,没执行完返回None,执行完返回执行结果
print(res.wait()) #等待执行结果
print(res.terminate()) #杀掉进程
print(res.communicate()) #等待任务结束
subprocess.Popen("echo '123' | sudo -S install vim",shell=True) #subprocess实现sudo 自动输入密码
os模块
import os
#获取当前目录
print(os.getcwd())
#改变当前目录
os.chdir("D:\learn_python3")
#生成单层目录
os.mkdir("1")
#删除单层目录,目录中不能有文件
os.rmdir("1")
#生成多层目录
os.makedirs("1\\test")
#删除多层目录
os.removedirs("1\\test")
#列出指定目录下的所有文件和子目录,包括隐藏文件,并以列表方式打印
os.listdir()
#重命名文件/目录
os.rename("11","1")
#获取文件/目录信息
print(os.stat("test.py"))
#输出操作系统特定的路径分隔符
print(os.sep)
#输出当前平台使用的行终止符
print(os.linesep)
#输出用于分割文件路径的字符串
print(os.pathsep)
#输出字符串指示当前使用平台
print(os.name)
#运行shell命令,直接显示
os.system("free -m")
#获取系统环境变量
print(os.environ)
#返回path规范化的绝对路径
print(os.path.abspath("D:\learn_python3\练习\\"))
#将path分割成目录和文件名二元组返回
print(os.path.split("D:\learn_python3\练习\\test.py"))
#返回path的目录
print(os.path.dirname("D:\learn_python3\练习\\test.py"))
#返回path最后的文件名
print(os.path.basename("D:\learn_python3\练习\\test.py"))
#如果path存在,返回True;如果path不存在,返回False
print(os.path.exists("D:\learn_python3\练习"))
#如果path是绝对路径,返回True
print(os.path.isabs("learn_python3"))
#如果path是一个存在的文件,返回True。否则返回False
print(os.path.isfile("D:\learn_python3\练习\\1.py"))
#如果path是一个存在的目录,则返回True。否则返回False
print(os.path.isdir("D:\learn_python3\练习"))
#将多个路径组合后返回,第一个绝对路径之前的参数将被忽略
print(os.path.join("D:\\","learn_python\\","练习"))
#返回path所指向的文件或者目录的最后存取时间,以时间戳形式
print(os.path.getatime("test.py"))
#返回path所指向的文件或者目录的最后修改时间,以时间戳形式
print(os.path.getmtime("test.py"))
random模块
import random
#打印一个随机的小数
print(random.random())
#打印一个范围的随机数
print(random.randint(1,5))
#打印1-4,步长为2的随机数
print(random.randrange(1,5,2))
#range(10)中取5个随机数
print(random.sample(range(10),5))
checkcode = ""
for i in range(4):
if i == random.randrange(0,4):
temp = chr(random.randint(65,90))
else:
temp = random.randint(0,9)
checkcode += str(temp)
print(checkcode)
getpass模块
import getpass
password = getpass.getpass('password:')
print (password)
time模块
import time
import datetime
#时间戳
print(time.time())
#时间元祖
print(time.localtime())
#时间戳转时间元祖
print(time.gmtime(time.time()+28800))
#时间元祖转时间戳
print(time.mktime(time.localtime()))
#时间元祖转自定义时间格式
print(time.strftime("%Y%m%d",time.localtime()))
#自定义时间格式转时间元祖
print(time.strptime("2017-02-13","%Y-%m-%d"))
#时间元祖转"%a %b %d %H.%M:%S %Y"串
print(time.asctime(time.localtime()))
#时间戳转"%a %b %d %H.%M:%S %Y"串
print(time.ctime(time.time()))
# %a 本地(locale)简化星期名称
# %A 本地完整星期名称
# %b 本地简化月份名称
# %B 本地完整月份名称
# %c 本地相应的日期和时间表示
# %d 一个月中的第几天(01 - 31)
# %H 一天中的第几个小时(24小时制,00 - 23)
# %I 第几个小时(12小时制,01 - 12)
# %j 一年中的第几天(001 - 366)
# %m 月份(01 - 12)
# %M 分钟数(00 - 59)
# %p 本地am或者pm的相应符
# %S 秒(01 - 61)
# %U 一年中的星期数。(00 - 53星期天是一个星期的开始。)第一个星期天之前的所有天数都放在第0周。
# %w 一个星期中的第几天(0 - 6,0是星期天)
# %W 和%U基本相同,不同的是%W以星期一为一个星期的开始。
# %x 本地相应日期
# %X 本地相应时间
# %y 去掉世纪的年份(00 - 99)
# %Y 完整的年份
# %Z 时区的名字(如果不存在为空字符)
# %% ‘%’字符
#time加减,前一个小时的时间
hour_second = 3600
time_now = time.time()+28800
last_hour = time_now - hour_second
print(time.gmtime(last_hour))
print(time.strftime("%Y-%m-%d %H:%M:%S",time.gmtime(last_hour)))
#打印格式2017-02-13 13:43:23.391471
print(datetime.datetime.now())
#当前时间加减
print(datetime.datetime.now()+datetime.timedelta(days=3,hours=1,seconds=0))
#时间替换
print(datetime.datetime.now().replace(year=2016,month=1,day=1,hour=12,minute=0,second=0))
文件操作
#对文件操作过程
#1.打开文件,得到文件句柄赋值给变量
#2.操作
#3.关闭文件
#文件句柄
#f = open('yesterday','r',encoding='utf-8')
#r模式为读模式
#f = open('yesterday','r',encoding='utf-8')
#w模式为写,创建文件
#f = open('yesterday2','w',encoding='utf-8')
#f.write("我爱北京天安门,\n")
#f.write("天安门上太阳升\n")
#a模式为追加,创建文件
#f = open('yesterday2','a',encoding='utf-8')
#f.write("我爱北京天安门,\n")
#f.write("天安门上太阳升\")
#关闭文件
#f.close()
#读前5行
'''
f = open('yesterday2','r',encoding='utf-8')
for i in range(5):
print (f.readline())
'''
#
'''
f = open('yesterday2','r',encoding='utf-8')
for i in f.readlines():
print (i,)
'''
#high bige
'''
count = 0
f = open('yesterday2','r',encoding='utf-8')
for line in f:
if count == 9:
print ('------我是分割线-------')
count += 1
continue
print (line.strip())
count += 1
'''
#seek和tall用法
'''
f = open('yesterday2','r',encoding='utf-8')
print (f.tell())
print (f.readline().strip())
print (f.readline().strip())
print (f.readline().strip())
print (f.tell())
f.seek(0)
print (f.readline().strip())
'''
#
#f = open('yesterday2','r',encoding='utf-8')
#print (f.encoding)
#强制刷新保存
#f.flush()
#截断
#f = open('yesterday2','r',encoding='utf-8')
#f.truncate(10)
#读写,r+,读和追加
'''
f = open('yesterday2','r+',encoding='utf-8')
print (f.readline())
print (f.readline())
print (f.readline())
f.write('-----diao----\n')
print (f.readline())
'''
#写读,w+,先创建一个文件
'''
f = open('yesterday2','w+',encoding='utf-8')
f.write('-----diao----\n')
f.write('-----diao----\n')
f.write('-----diao----\n')
f.write('-----diao----\n')
print (f.tell())
f.seek(10)
print (f.readline())
f.write('should\n')
'''
#追加读,a+
#读二进制文件
#f = open('yesterday2','rb')
#print (f.readline())
#写二进制文件
#f = open('yesterday2','wb')
#f.write('hello\n'.encode('utf-8'))
#f.close()
#文件修改
f = open('yesterday2','r',encoding='utf-8')
f_new = open('yesterday3','w',encoding='utf-8')
for line in f:
if '肆意的快乐' in line:
line = line.replace('肆意的快乐等我享受','肆意的快乐等贾晨享受')
f_new.write(line)
f.close()
requests是python的一个HTTP客户端库,跟urllib,urllib2类似,那为什么要用requests而不用urllib2呢?官方文档中是这样说明的:
python的标准库urllib2提供了大部分需要的HTTP功能,但是API太逆天了,一个简单的功能就需要一大堆代码。
1. 安装
安装很简单,我是win系统,就在这里下载了安装包(网页中download the zipball处链接),然后$ python setup.py install就装好了。
当然,有easy_install或pip的朋友可以直接使用:easy_install requests或者pip install requests来安装。
至于linux用户,这个页面还有其他安装方法。
测试:在IDLE中输入import requests,如果没提示错误,那说明已经安装成功了!
2. 小试牛刀
import requests
r= requests.get('https://www.baidu.com/s')
print(r.status_code)
print(r.headers['content-type'])
print(r.encoding)
print(r.text)
3. 快速指南
3.1 发送请求
发送请求很简单的,首先要导入requests模块:
>>>import requests
接下来让我们获取一个网页,例如我个人博客的首页:
>>>r = requests.get('http://www.sharejs.com')
接下来,我们就可以使用这个r的各种方法和函数了。
另外,HTTP请求还有很多类型,比如POST,PUT,DELETE,HEAD,OPTIONS。也都可以用同样的方式
因为目前我还没用到这些,所以没有深入研究。
>>> r = requests.post("http://httpbin.org/post")
>>> r = requests.put("http://httpbin.org/put")
>>> r = requests.delete("http://httpbin.org/delete")
>>> r = requests.head("http://httpbin.org/get")
>>> r = requests.options("http://httpbin.org/get")
3.2 在URLs中传递参数
有时候我们需要在URL中传递参数,比如在采集百度搜索结果时,我们wd参数(搜索词)和rn参数(搜素结果数量),
import requests
r = requests.get('http://ip.taobao.com/service/getIpInfo.php?ip=122.88.60.28')
print(r.json()['data']['country'])
u'http://www.baidu.com/s?rn=100&wd=%E5%BC%A0%E4%BA%9A%E6%A5%A0'
上面wd=的乱码就是“张亚楠”的转码形式。(好像参数按照首字母进行了排序。)
3.3 获取响应内容
可以通过r.text来获取网页的内容。
print(r.url) 用r.content 或者r.print 来替换urllib2.urlopen(url)read()
>>>
文档里说,requests会自动将内容转码。大多数unicode字体都会无缝转码。但我在cygwin下使用时
老是出现UnicodeEncodeError错误,郁闷。倒是在python的IDLE中完全正常。
另外,还可以通过r.content来获取页面内容。
import requests
r = requests.get('http://ip.taobao.com/service/getIpInfo.php?ip=122.88.60.28')
print(r.content)
>>> r.content
文档中说r.content是以字节的方式去显示,所以在IDLE中以b开头。但我在cygwin中用起来并没有,
下载网页正好。所以就替代了urllib2的urllib2.urlopen(url).read()功能。(基本上是我用的最多的一
个功能。)
3.4 获取网页编码
可以使用r.encoding来获取网页编码。
import requests
r = requests.get('
print(r.status_code)
>>> r.encoding
当你发送请求时,requests会根据HTTP头部来猜测网页编码,当你使用r.text时,requests就会使用这个编码。当然你
还可以修改requests的编码形式。
像上面的例子,对encoding修改后就直接会用修改后的编码去获取网页内容。
3.5 json
像urllib和urllib2,如果用到json,就要引入新模块,如json和simplejson,但在requests中已经有了内置的函数,r.json()。就拿查询IP的API来说:
>>>
r = requests.get('http://ip.taobao.com/service/getIpInfo.php?ip=122.88.60.28')
print(r.json()['data']['country'])
3.6 网页状态码
>>
我们可以用r.status_code来检查网页的状态码。
>>>r.status_code
import requests
def get_status(url):
r = requests.get(url, allow_redirects=False)
return r.status_code
print(get_status('http://www.zhidaow.com'))
# 200
print(get_status('http://www.zhidaow.com/hi404/'))
# 404
print(get_status('http://mengtiankong.com'))
# 301
print(get_status('http://www.baidu.com/link?url=QeTRFOS7TuUQRppa0wlTJJr6FfIYI1DJprJukx4Qy0XnsDO_s9baoO8u1wvjxgqN'))
# 302
print(get_status('http://www.huiya56.com/com8.intre.asp?46981.html'))
# 500
这里能看出他是使用了302跳转。也许有人认为这样可以通过判断和正则来获取跳转的状态码了,其实
还有个更简单的方法:
前两个例子很正常,能正常打开的返回200,不能正常打开的返回404。但第三个就有点奇怪了,那个
是百度搜索结果中的302跳转地址,但状态码显示是200,接下来我用了一招让他原形毕露:
只要加上一个参数allow_redirects,禁止了跳转,就直接出现跳转的状态码了,好用吧?我也利用这个在最后一掌做了
个简单的获取网页状态码的小应用,原理就是这个。
>>> r.headers
3.7 响应头内容
可以通过r.headers来获取响应头内容。
{
import requests
# r = requests.get('http://www.zhidaow.com')
#
# print(r.request.headers)
#自定义请求头部
r = requests.get('http://www.baidu.com')
print(r.request.headers['User-Agent'])
# print(r.request.headers)
# python-requests/1.2.3 CPython/2.7.3 Windows/XP
headers = {'User-Agent': 'alexkh'}
r = requests.get('http://www.zhidaow.com', headers=headers)
print(r.request.headers['User-Agent'])
.
可以看到是以字典的形式返回了全部内容,我们也可以访问部分内容。
)
3.8 设置超时时间
我们可以通过timeout属性设置超时时间,一旦超过这个时间还没获得响应内容,就会提示错误。
Traceback (most recent call last):
3.9 代理访问
采集时为避免被封IP,经常会使用代理。requests也有相应的proxies属性。
import requests
proxies = {
"http" : "http://10.6.0.1:80",
"https" : "http://10.6.0.100:80"
}
r = requests.get("http://www.zhidaow.com", proxies=proxies)
print(r.headers)
3.10 请求头内容
如果代理需要账户和密码,则需这样:
proxies = {
"http": "http://user:[email protected]:3128/",
}
请求头内容可以用r.request.headers来获取。
r = requests.get('http://www.baidu.com')
print(r.request.headers['User-Agent'])
# print(r.request.headers)
# python-requests/1.2.3 CPython/2.7.3 Windows/XP
headers = {'User-Agent': 'alexkh'}
r = requests.get('http://www.zhidaow.com', headers=headers)
print(r.request.headers['User-Agent'])
{3.11 自定义请求头部
伪装请求头部是采集时经常用的,我们可以用这个方法来隐藏:
header}
3.12 持久连接keep-alive
requests的keep-alive是基于urllib3,同一会话内的持久连接完全是自动的。同一会话内的所有请求都会自动使用恰当的连接。
也就是说,你无需任何设置,requests会自动实现keep-alive。
4. 简单应用
4.1 获取网页返回码
import requests
def get_status(url):
r = requests.get(url, allow_redirects=False)
return r.status_code
print(get_status('http://www.zhidaow.com'))
# 200
print(get_status('http://www.zhidaow.com/hi404/'))
# 404
print(get_status('http://mengtiankong.com'))
# 301
print(get_status('http://www.baidu.com/link?url=QeTRFOS7TuUQRppa0wlTJJr6FfIYI1DJprJukx4Qy0XnsDO_s9baoO8u1wvjxgqN'))
# 302
print(get_status('http://www.huiya56.com/com8.intre.asp?46981.html'))
# 500
python-nmap是基于系统nmap命令的一个端口扫描工具,使用简单方便。
最近为了加强服务器安全性和监管,需要每天把公司服务器开放端口扫描记录,一旦出现增加减少能发现。
import nmap
把nmap模块的端口扫描方法进行实例化
s=nmap.PortScanner()
使用scan('192.168.0.0/16',port='0-65536','sV')方法,里面分别是网段,端口范围,nmap的参数
result = s.scan('192.168.199.211', '20-443','')
这里result是执行的输出
print result
{'nmap': {'scanstats': {'uphosts': '1', 'timestr': 'Sat Dec 17 16:24:11 2016', 'downhosts': '0', 'totalhosts': '1', 'elapsed': '0.11'}, 'scaninfo': {'tcp': {'services': '20-443', 'method': 'syn'}}, 'command_line': 'nmap -oX - -p 20-443 192.168.199.211'}, 'scan': {'192.168.199.211': {'status': {'state': 'up', 'reason': 'localhost-response'}, 'hostnames': [{'type': 'PTR', 'name': 'salt'}], 'vendor': {}, 'addresses': {'ipv4': '192.168.199.211'}, 'tcp': {80: {'product': '', 'state': 'open', 'version': '', 'name': 'http', 'conf': '3', 'extrainfo': '', 'reason': 'syn-ack', 'cpe': ''}, 443: {'product': '', 'state': 'open', 'version': '', 'name': 'https', 'conf': '3', 'extrainfo': '', 'reason': 'syn-ack', 'cpe': ''}, 22: {'product': '', 'state': 'open', 'version': '', 'name': 'ssh', 'conf': '3', 'extrainfo': '', 'reason': 'syn-ack', 'cpe': ''}}}}}
初始化的实例如下方法
s.
s.all_hosts s.csv s.listscan s.scaninfo
s.analyse_nmap_xml_scan s.get_nmap_last_output s.nmap_version s.scanstats
s.command_line s.has_host s.scan
扫描的所有主机
s.all_hosts()
['192.168.199.211']
主机下的信息列表
s['192.168.199.211'].keys()
['status', 'hostnames', 'vendor', 'addresses', 'tcp']
主机下的tcp端口列表
s['192.168.199.211']['tcp'].keys()
[80, 443, 22]
查看22端口的详细信息
s['192.168.199.211']['tcp'][22]
{'conf': '3',
'cpe': '',
'extrainfo': '',
'name': 'ssh',
'product': '',
'reason': 'syn-ack',
'state': 'open',
'version': ''}
通过上面大家可以看到 s=nmap.PortScanner()实例化以后,会把信息存储到“s”里面,“s”可以像从json里面取数据一样超级方便。
#!/bin/bash
'''
author: baishaohua
date: 20161215
'''
host='192.168.1.224'
port='6379'
import nmap
import redis
import time
ctime = time.strftime('%Y_%m_%d')
r = redis.StrictRedis(host,port=port,db=12)
def get_info(ip):
'''获取集合,并把集合元素转换为整数'''
a=[]
for i in r.smembers(ip):
a.append(int(i))
return a
def set_info(ip, port_list):
r.delete(ip)#删除昨日的端口记录,下面遍历写入今日的端口
try:
for port in port_list:
r.sadd(ip, port)
except:
print "set redis err"
def r_log(msg):
f_path = "/tmp/report_%s.txt" % ctime
f = open(f_path, 'a+')
f.write(msg)
f.close()
def scan_port(my_ip,port_range):
'''
tow parameter: ip,port. will return a port list
'''
s = nmap.PortScanner()
result = s.scan(my_ip,port_range,'')
return s[my_ip]['tcp'].keys()
def scan_ips(ip_range,port_range):
'''
tow parameter: ip,port. will return a port list
'''
s = nmap.PortScanner()
result = s.scan(ip_range,port_range,'')
report_key = "report_%s" % ctime
a = {}
b = {}
for i in s.all_hosts():
a[i] = set(get_info(i))
b[i] = set(s[i]['tcp'].keys())
if r.exists(i):
less_port = a[i].difference(b[i])
add_port = b[i].difference(a[i])
if len(add_port)>0 and len(less_port)>0:
msg = "%s port %s new open \t %s have close\n" % (i, add_port, less_port)
print msg
r_log(msg)
elif len(add_port)>0:
msg = "%s port %s new open \n" % (i, add_port)
print msg
r_log(msg)
elif len(less_port)>0:
msg = "%s port %s close \n" % (i, less_port)
print msg
r_log(msg)
else:
print "%s port no change: %s , %s" % (i, a[i], b[i])
set_info(i, s[i]['tcp'].keys())
else:
msg = "new host: %s port %s open\n" % (i, s[i]['tcp'].keys())
print msg
r_log(msg)
set_info(i,s[i]['tcp'].keys())
def __main__():
scan_ips('192.168.1.211/28','20-8080')