Python合并多个字典的方法

示例

x = {'a': 1, 'b': 2}
y = {'b': 3, 'c': 4}

相同属性合并,后者覆盖前者的值。x和y合并后

>>> z
{'a': 1, 'b': 3, 'c': 4}

Python 3.5

在Python 3.5新增了字典合并的语法,只需要一条语句就可以实现字典的合并

z = {**x, **y}

其中**为字典解包操作符(dictionary unpacking operator)。

详细查看:https://docs.python.org/dev/whatsnew/3.5.html#pep-448-additional-unpacking-generalizations

Python 2 以及 Python 3.0-3.4

在Python 3.5之前,需要自己实现合并函数。

def merge_dicts(*dicts):
    result = {}
    for dict in dicts:
        result.update(dict)
    return result

python图表之pygal入门篇

pygal的简单使用

例子来自此书: 《Python编程从入门到实战》【美】Eric Matthes

pygal是一个SVG图表库。SVG是一种矢量图格式。全称Scalable Vector Graphics — 可缩放矢量图形。

用浏览器打开svg,可以方便的与之交互。

以下代码均在Jupyter Notebook中运行

模拟掷骰子

来看一个简单的例子。它模拟了掷骰子。

import random

class Die:
    """
    一个骰子类
    """
    def __init__(self, num_sides=6):
        self.num_sides = num_sides

    def roll(self):
        return random.randint(1, self.num_sides)

模拟掷骰子并可视化

import pygal

die = Die()
result_list = []
# 掷1000次
for roll_num in range(1000):
    result = die.roll()
    result_list.append(result)

frequencies = []
# 范围1~6,统计每个数字出现的次数
for value in range(1, die.num_sides + 1):
    frequency = result_list.count(value)
    frequencies.append(frequency)

# 条形图
hist = pygal.Bar()
hist.title = 'Results of rolling one D6 1000 times'
# x轴坐标
hist.x_labels = [1, 2, 3, 4, 5, 6]
# x、y轴的描述
hist.x_title = 'Result'
hist.y_title = 'Frequency of Result'
# 添加数据, 第一个参数是数据的标题
hist.add('D6', frequencies)
# 保存到本地,格式必须是svg
hist.render_to_file('die_visual.svg')

使用浏览器打开这个文件,鼠标指向数据,可以看到显示了标题“D6”, x轴的坐标以及y轴坐标。

可以发现,六个数字出现的频次是差不多的(理论上概率是1/6, 随着实验次数的增加,趋势越来越明显)

未分类

同时掷两个骰子

稍微改下代码就行,再实例化一个骰子

die_1 = Die()
die_2 = Die()

result_list = []
for roll_num in range(5000):
    # 两个骰子的点数和
    result = die_1.roll() + die_2.roll()
    result_list.append(result)

frequencies = []
# 能掷出的最大数
max_result = die_1.num_sides + die_2.num_sides

for value in range(2, max_result + 1):
    frequency = result_list.count(value)
    frequencies.append(frequency)

# 可视化
hist = pygal.Bar()
hist.title = 'Results of rolling two D6 dice 5000 times'
hist.x_labels = [x for x in range(2, max_result + 1)]
hist.x_title = 'Result'
hist.y_title = 'Frequency of Result'
# 添加数据
hist.add('two D6', frequencies)
# 格式必须是svg
hist.render_to_file('2_die_visual.svg')

从图中可以看出,两个骰子之和为7的次数最多,和为2的次数最少。因为能掷出2的只有一种情况 -> (1, 1);而掷出7的情况有(1, 6) , (2, 5), (3, 4), (4, 3), (5, 2), (6, 1)共6种情况,其余数字的情况都没有7的多,故掷得7得概率最大。

未分类

处理json数据–世界人口地图

需要用到人口数据

下载population.json: http://pan.baidu.com/s/1pKLB9N1 ,该数据来源于okfn.org这个网站

打开看下数据,其实这是个很长的列表,包含了许多国家从1960~2015年的人口数据。看第一数据,如下。后面的数据和第一个键都一样。

[ 
{
 "Country Name":"Arab World",
 "Country Code":"ARB",
 "Year":"1960",
 "Value":"92496099"
 },
...

只有四个键,其中Country Code指的是国别码,这里是3位的。Value就是人口数了。

import json

filename = r'F:Jupyter Notebookmatplotlib_pygal_csv_jsonpopulation.json'
with open(filename) as f:
    # json.load()可以将json文件转为Python能处理的形式,这里位列表,列表里是字典
    pop_data = json.load(f)

cc_populations = {}
for pop_dict in pop_data:
    if pop_dict['Year'] == '2015':
        country_name = pop_dict['Country Name']
        # 有些值是小数,先转为float再转为int
        population = int(float(pop_dict['Value']))
        print(country_name + ': ' + population)

上面的程序打印了2015年各个国家的人口数,当然要分析2014年的,代码中数字改改就行。

Arab World: 392168030
Caribbean small states: 7116360
Central Europe and the Baltics: 103256779
Early-demographic dividend: 3122757473.68203
East Asia & Pacific: 2279146555
...

需要注意的是,人口数据有些值是小数(不可思议)。人口数据类型是字符串str,如果直接转int,像’35435.12432’这样的字符串是不能强转位int的,必须先转为float,再丢失精度转为int。

获取两个字母的国别码

我们的数据中,国别码是三位的,而pygal的地图工具使用两位国别码。要使用pygal绘制世界地图。需要安装依赖包。

pip install pygal_maps_world就可以了

国别码位于i18n模块

from pygal_maps_world.i18n import COUNTRIES这样就导入了, COUNTRIES是一个字典,键是两位国别码,值是具体国家名。

key -> value
af Afghanistan
af Afghanistan
al Albania
al Albania
dz Algeria
dz Algeria
ad Andorra
ad Andorra
ao Angola

写一个函数,根据具体国家名返回pygal提供的两位国别码

def get_country_code(country_name):
    """
    根据国家名返回两位国别码
    """
    for code, name in COUNTRIES.items():
        if name == country_name:
            return code
    return None

世界人口地图绘制

先给出全部代码,需要用到World类

import json

from pygal_maps_world.i18n import COUNTRIES
from pygal_maps_world.maps import World
# 颜色相关
from pygal.style import RotateStyle
from pygal.style import LightColorizedStyle

def get_country_code(country_name):
    """
    根据国家名返回两位国别码
    """
    for code, name in COUNTRIES.items():
        if name == country_name:
            return code
    return None

filename = r'F:Jupyter Notebookmatplotlib_pygal_csv_jsonpopulation.json'
with open(filename) as f:
    pop_data = json.load(f)

cc_populations = {}
for pop_dict in pop_data:
    if pop_dict['Year'] == '2015':
        country_name = pop_dict['Country Name']

        # 有些值是小数,先转为float再转为int
        population = int(float(pop_dict['Value']))
        code = get_country_code(country_name)
        if code:
            cc_populations[code] = population

# 为了使颜色分层更加明显
cc_populations_1,cc_populations_2, cc_populations_3 = {}, {}, {}
for cc, population in cc_populations.items():
    if population < 10000000:
        cc_populations_1[cc] = population
    elif population < 1000000000:
        cc_populations_2[cc] = population
    else:
        cc_populations_3[cc] = population

wm_style = RotateStyle('#336699', base_style=LightColorizedStyle)
world = World(style=wm_style)
world.title = 'World Populations in 2015, By Country'
world.add('0-10m', cc_populations_1)
world.add('10m-1bn', cc_populations_2)
world.add('>1bn', cc_populations_3)
world.render_to_file('world_population_2015.svg')

有几个变量比较重要

  • cc_populations是一个dict,里面存放了两位国别码与人口的键值对。

  • cc_populations_1,cc_populations_2, cc_populations_3这是3个字典,把人口按照数量分阶梯,人口一千万以下的存放在cc_populations_1中,一千万~十亿级别的存放在cc_populations_2中,十亿以上的存放在cc_populations_3中,这样做的目的是使得颜色分层更加明显,更方便找出各个阶梯里人口最多的国家。由于分了三个层次,在添加数据的的时候也add三次,把这三个字典分别传进去。

  • world = World(style=wm_style)这是一个地图类,导入方法from pygal_maps_world.maps import World

  • wm_style = RotateStyle(‘#336699’, base_style=LightColorizedStyle)这里修改了pygal默认的主题颜色,第一个参数是16进制的RGB颜色,前两位代表R,中间两位代表G,最后两位代表B。数字越大颜色越深。第二个参数设置基础样式为亮色主题,pygal默认使用较暗的颜色主题,通过此方法可以修改默认样式。

中国大佬,No. 1

图中可以看出,分的三个颜色层次为。紫色系,十亿以上;蓝色系,一千万到十亿之间;绿色系,一千万一下。这三种颜色里面颜色最深的就对应了三个阶梯里人口最多的国家。

未分类

仔细观察,图中有些是空白的。并不是这些地方全部没人,而是我们的json数据中有些国家的名称与pygal中COUNTIES模块的国家名不对应导致。这算是一个遗憾,不过可以修改get_country_code函数,使得遇到不对应的国家名时,不返回None。对于这些国家,查阅COUNTRIES的代码,找出对应的国别码,返回之,应该就Ok了。比如下面这样

# 传入的参数country_name是json数据中的,可能与COUNTRIES里面的国家名不一致,按照上面的代码直接就返回None,导致绘图时这个国家的人口数据空白
if country_name == 'Yemen, Rep':
    return 'ye'

不过我懒得试了233

使用Web API分析数据

以GitHub为例,我想查看最受欢迎的Python库。以stars排序。

访问: https://api.github.com/search/repositories?q=language:python&sort=stars 就可查看。数据大概长这样

{
  "total_count": 1767997,
  "incomplete_results": false,
  "items": [{
     {
       "id": 21289110,
      "name": "awesome-python",
      "full_name": "vinta/awesome-python",
      "owner": {
        "login": "vinta",
        ...
          },
       ...    
       "html_url": "https://github.com/vinta/awesome-python",
        ...
          "stargazers_count": 35234,
        ...

  }, {...}
      ...]
}

第三个数据,items。里面是得到stars最多的top 30。name即库名称,owner下的login是库的拥有者,html_url是该库的网址(注意owner下也有个html_url。不过那个是用户的GitHub网址,我们要定位到该用户的具体这个库,所以不要用owner下的html_url),stargazers_count至关重要,所得的stars数目。

顺便说下第一个键total_count,表示Python语言的仓库的总数;第二个键,incomplete_results,表示响应的值不完全,一般来说是false,表示响应的数据完整。

import requests

url = 'https://api.github.com/search/repositories?q=language:python&sort=stars'
response = requests.get(url)
# 200为响应成功
print(response.status_code, '响应成功!')
response_dict = response.json()

total_repo = response_dict['total_count']
repo_list = response_dict['items']
print('总仓库数: ', total_repo)
print('top', len(repo_list))
for repo_dict in repo_list:
    print('nName: ', repo_dict['name'])
    print('Owner: ', repo_dict['owner']['login'])
    print('Stars: ', repo_dict['stargazers_count'])
    print('Repo: ', repo_dict['html_url'])
    print('Description: ', repo_dict['description'])

其实像这样已经得到结果了

200 响应成功!
总仓库数:  1768021
top 30

Name:  awesome-python
Owner:  vinta
Stars:  35236
Repo:  https://github.com/vinta/awesome-python
Description:  A curated list of awesome Python frameworks, libraries, software and resources

Name:  httpie
Owner:  jakubroztocil
Stars:  30149
Repo:  https://github.com/jakubroztocil/httpie
Description:  Modern command line HTTP client – user-friendly curl alternative with intuitive UI, JSON support, syntax highlighting, wget-like downloads, extensions, etc.  https://httpie.org

Name:  thefuck
Owner:  nvbn
Stars:  28535
Repo:  https://github.com/nvbn/thefuck
Description:  Magnificent app which corrects your previous console command.
...

可视化一下当然会更加直观。

pygal可视化数据

代码不是很难,有一个plot_dict比较关键,这是鼠标放在条形图上时,会显示出来的数据,键基本上都是固定写法,xlink里面时仓库地址,只要点击,浏览器就会新开一个标签跳转到该页面了!

import requests

import pygal
from pygal.style import LightColorizedStyle, LightenStyle

url = 'https://api.github.com/search/repositories?q=language:python&sort=stars'
response = requests.get(url)
# 200为响应成功
print(response.status_code, '响应成功!')
response_dict = response.json()

total_repo = response_dict['total_count']
repo_list = response_dict['items']
print('总仓库数: ', total_repo)
print('top', len(repo_list))

names, plot_dicts = [], []
for repo_dict in repo_list:
    names.append(repo_dict['name'])
    # 加上str强转,因为我遇到了'NoneType' object is not subscriptable (: 说明里面有个没有此项, 是NoneType
    plot_dict = {
        'value' : repo_dict['stargazers_count'],
        # 有些描述很长很长,选最前一部分
        'label' : str(repo_dict['description'])[:200]+'...',
        'xlink' : repo_dict['html_url']
    }
    plot_dicts.append(plot_dict)

# 改变默认主题颜色,偏蓝色
my_style = LightenStyle('#333366', base_style=LightColorizedStyle)
# 配置
my_config = pygal.Config()
# x轴的文字旋转45度
my_config.x_label_rotation = -45
# 隐藏左上角的图例
my_config.show_legend = False
# 标题字体大小
my_config.title_font_size = 30
# 副标签,包括x轴和y轴大部分
my_config.label_font_size = 20
# 主标签是y轴某数倍数,相当于一个特殊的刻度,让关键数据点更醒目
my_config.major_label_font_size = 24
# 限制字符为15个,超出的以...显示
my_config.truncate_label = 15
# 不显示y参考虚线
my_config.show_y_guides = False
# 图表宽度
my_config.width = 1000

# 第一个参数可以传配置
chart = pygal.Bar(my_config, style=my_style)
chart.title = 'Most-Starred Python Projects on GitHub'
# x轴的数据
chart.x_labels = names
# 加入y轴的数据,无需title设置为空,注意这里传入的字典,
# 其中的键--value也就是y轴的坐标值了
chart.add('', plot_dicts)
chart.render_to_file('most_stars_python_repo.svg')

看下图,chrome浏览器里显示效果。总感觉config里面有些设置没有起到作用, x、y轴的标签还是那么小orz…不过plot_dict里面的三个数据都显示出来了,点击即可跳转。

未分类

好了,就折腾这么多吧,这个库也不是特别大众的…

如何让 Docker 容器正常打印 Python 的日志

在 Docker 容器里跑 Python 程序时,我们经常遇到通过print函数或者logging模块输出的信息在容器 log 中迷之失踪,过了好久又迷之出现。这是因为 Python 在写 stdout 和 stderr 的时候有缓冲区,导致输出无法实时更新进容器 log。

有如下几种方法解决:

1. 增加环境变量

对于使用print函数打印的内容,在运行容器时增加环境变量PYTHONUNBUFFERED=0就可以解决。

2. 配置 logging 的 stream 参数

import logging
logging.basicConfig(stream=sys.stdout)

这样,通过 logging 模块打印的日志都会直接写到标准输出 stdout。

或者自定义两个StreamHandler分别配置为输出到 stdout 和 stderr,来对不同 log 分别进行输出处理。

3. WSGI server 配置参数

如果是以 WSGI server 运行的 web 应用,以 gunicorn 为例,在 gunicorn 的启动命令中增加参数–access-logfile – –error-logfile -即可。

Mac下安装Python虚拟环境Virtualenv

virtualenv官方文档对virtualenv的解释是:

virtualenv is a tool to create isolated Python environments.

virtualenv可以创建一个独立的 Python 环境,每个项目都可以有一个专属环境,避免了不同各种包安装冲突以及版本要求问题,可以让你更方便快捷的切换不同 Python 环境,更高效的开发。

pip是 Python 自带的包管理工具。

安装 virtualenv

$ sudo pip install virtualenv

测试virtualenv是否安装成功:

$ mkdir ~/Pyenv
$ cd ~/Pyenv
$ mkvirtualenv env1

安装 virtualenvwrapper

Virtaulenvwrapper是对virtualenv的封装,可以更方便地管理虚拟环境。

$ sudo easy_install virtualenvwrapper

第一次安装完成后需要,先设置WORKON_HOME,即环境的存储路径,并且运行source /usr/local/bin/virtualenvwrapper.sh

$ export WORKON_HOME=~/Pyenv
$ source /usr/local/bin/virtualenvwrapper.sh

把export命令和source命令加入到~/.bash_profile中,每次打开终端就无需初始化了。

$ vim ~/.bash_profile
$ export WORKON_HOME=~/Pyenv
$ source /usr/local/bin/virtualenvwrapper.sh

创建虚拟环境

$ mkvirtualenv env2

环境创建之后,会自动进入该目录,并激活该环境,当前路径前面就会有 (env2)。

列出虚拟环境:

$ lsvirtualenv -b
env1
env2

切换虚拟环境:

$ workon env1

查看环境里安装了哪些包:

$ lssitepackages

复制虚拟环境:

$ cpvirtualenv env1 env3
Copying env1 as env3...

退出虚拟环境:

$ deactivate

删除虚拟环境:

$ rmvirtualenv env2
Removing env2...

至此,Python虚拟环境Virtualenv安装流程完毕,你可以在你自己的虚拟环境下随意安装各种包,不同项目间也不会相互影响了。

python利用flask,gunicorn部署接口全过程

背景

无论开发 Android 还是 Web 端程序,有时候不免需要一些接口供自己调用进行测试,这里记录一下详细的过程。

环境配置

1、阿里云的 9.9 的学生特惠机, Ubuntu 14.04 64位

未分类

2、利用 putty 输入公网 ip 登录到服务器

先配置编码为 utf-8

未分类

未分类

输入账号密码

未分类

3、要利用 apt-get 包管理工具下载各种包,所以先更新下源,随手把 git 也安一下,安装中途输入 Y 即可

apt-get update
apt-get install git

未分类

Flask [flɑ:sk]

Flask是一个使用Python编写的轻量级Web应用框架。基于Werkzeug WSGI工具箱和Jinja2 模板引擎。 Flask 官方教程: http://docs.jinkan.org/docs/flask/index.html

我已经在本地写了一个简单的 Flask ,并且传到了 Coding

#coding=utf-8
from flask import Flask,jsonify,request
app = Flask(__name__) #获得 Flask 实例
 #写一个 POST 的方法,传一个 name 的参数,返回一个  json 数据
@app.route('/getJson', methods=['POST'])
def getJson():
    #bala bala,下边随便返回点东西
    name=request.form.get('name', default='windliang')
    data={
    'name':name,
    'place':'wuhan'
    }
    msg='get success'
    code=True
    return getBaseReturnValue(data,msg,code)
#返回 json 数据    
def getBaseReturnValue(data,msg,code):
  json_data = jsonify({'data':data,'msg':msg,'success':code})
  return json_data

if __name__ == '__main__':
    app.run(host='0.0.0.0') #在服务器上运行

依次执行下边的指令,‘//’后边的仅做注释不用复制

git clone https://git.coding.net/wind_liang/flasktest.git  //将 coding 上的代码克隆到本地
pip install virtualenv  //python 的一个创建隔离环境的工具
mkdir api  //创建一个新目录 api,virtualenv 直接用 clone 下的目录会出问题,原因不清楚
cp -i flasktest/api.py api  //将 coding 下载下来的 api.py 复制到新目录 api 中
cd api   // 进入 api 目录
virtualenv venv // 创建虚拟环境安包的文件夹
source venv/bin/activate //激活虚拟环境 ,这时会看到在最前边有 (venv) 标识 ,以后进入前都得先激活环境
pip install flask // 安装 flask 包
pip freeze > requirements.txt  // 将安装的包列表写到 reqirements.txt 中,
以后每次 pip 安装了新的库的时候,都需freeze 一次,
既能知道自己安装了什么库,也方便别人部署时,安装相应的库。
python api.py  // 运行程序 
ctrl+C 用于终止当前 python 程序
deactivate 用于关闭当前虚拟环境 ,先不用执行此句

virtualenv 是一个将不同项目所需求的依赖分别放在独立的地方的一个工具,它给这些工程创建虚拟的Python环境。它解决了“项目X依赖于版本1.x,而项目Y需要项目4.x”的两难问题,而且使你的全局site-packages目录保持干净和可管理。官方教程

阿里云还得设定开放 5000端口

未分类

未分类

此时利用 postman (谷歌浏览器的一个插件),或者 curl 等其他能发 post 请求的工具进行测试

未分类

未分类

ctrl+C 终止程序,进入下一步

gunicorn

Gunicorn是一个Python WSGI UNIX的HTTP服务器。这是一个预先叉工人模式,从Ruby的独角兽(Unicorn)项目移植。该Gunicorn服务器与各种Web框架兼容,我们只要简单配置执行,轻量级的资源消耗,以及相当迅速。现在我们使用 flask 自带的服务器,完成了 web 服务的启动。生产环境下,flask 自带的服务器,无法满足性能要求。我们这里采用 gunicorn 做 wsgi容器,用来部署 python

pip install gunicorn  //安装 gunicorn
pip freeze > requirements.txt //保存到当前安装的包的列表中
gunicorn -w4 -b0.0.0.0:8000 api:app
此时,我们需要用 8000 的端口进行访问,
原先的5000并没有启用。
其中 gunicorn 的部署中,
-w 表示开启多少个 worker,-b
表示 gunicorn  的访问地址 ,
api 是程序进入的文件名, 
app 是代码中获得的 flask 实例
进入阿里云记得开放8000端口

未分类

未分类

ctrl + c 终止当前程序

微信公众号服务器端 Flask 源码

python 2.7

# -*- coding: utf-8 -*-
# filename: main.py
from flask import Flask
import hashlib
import time
from flask import Flask,g,request,make_response
import xml.etree.ElementTree as ET
import requests 
import re
import os
from bs4 import BeautifulSoup
import warnings
app = Flask(__name__)
BASE_DIR = os.path.dirname(__file__) #获取当前文件夹的绝对路径
warnings.filterwarnings("ignore") #忽略警告
@app.route("/wx",methods=["GET","POST"])
def wx():
    if request.method == "GET":       # 判断请求方式是GET请求
        my_signature = request.args.get('signature')     # 获取携带的signature参数
        my_timestamp = request.args.get('timestamp')     # 获取携带的timestamp参数
        my_nonce = request.args.get('nonce')        # 获取携带的nonce参数
        my_echostr = request.args.get('echostr')         # 获取携带的echostr参数
        token = 'helloworld'     # 一定要跟微信端填写的token一致
        # 进行字典排序
        data = [token,my_timestamp ,my_nonce ]
        data.sort()
        # 拼接成字符串
        try:
            temp = ''.join(data)
        except:
            return "success"
        # 进行sha1加密
        mysignature = hashlib.sha1(temp).hexdigest()
        # 加密后的字符串可与signature对比,标识该请求来源于微信
        if my_signature == mysignature:
            return my_echostr
    else:
        rec = request.stream.read()
        xml_rec = ET.fromstring(rec)
        msgType=xml_rec.find("MsgType").text 
        if msgType != 'text': #只对文字进行回复
            return "success"
        tou = xml_rec.find('ToUserName').text
        fromu = xml_rec.find('FromUserName').text
        content = xml_rec.find('Content').text
        cc=content.encode('UTF-8') # 用户发送的文字
        t="狼吃羊"
        if(cc==t):
            content="http://windliang.oschina.io/worfeatsheep/"
        else:
            return "success"
        xml_rep = "<xml><ToUserName><![CDATA[%s]]></ToUserName><FromUserName><![CDATA[%s]]></FromUserName><CreateTime>%s</CreateTime><MsgType><![CDATA[text]]></MsgType><Content><![CDATA[%s]]></Content><FuncFlag>0</FuncFlag></xml>"
        response = make_response(xml_rep % (fromu,tou,str(int(time.time())), content))
        response.content_type='application/xml'
        return response

@app.route("/",methods=["GET"])
def index():
    return "hello,world"

if __name__ == '__main__':
    app.run(host='0.0.0.0',debug='true')

使用python 实现自动登录ssh

介绍

本文介绍使用python 自动连ssh,并通过正则处理返回值。

通过这段代码,可以使一些繁杂的工作,变成比较简单以及自动化。

代码

#!/usr/bin/env python

import pexpect
import signal, fcntl, termios, struct, sys

global_pexpect_instance = None

# 当窗口大小有改变时
def sigwinch_passthrough(sig, data):
    # Set terminal size
    if 'TIOCGWINSZ' in dir(termios):
        TIOCGWINSZ = termios.TIOCGWINSZ
    else:
        TIOCGWINSZ = 1074295912
    s = struct.pack ("HHHH", 0, 0, 0, 0)
    a = struct.unpack ('HHHH', fcntl.ioctl(sys.stdout.fileno(), TIOCGWINSZ , s))
    global global_pexpect_instance
    global_pexpect_instance.setwinsize(a[0],a[1])

# 处理返回值,并输入密码
def ssh_password(child,password,other=None):
    global base_path
    ssh_newkey = 'Are you sure you want to continue connecting'
    while True:
        step=[pexpect.TIMEOUT, ssh_newkey, '[pP]assword:.*', '.*[$#] '];
        if other:
            step.append(other);
        i = child.expect(step,timeout=120)
        print "expect:"+step[i];
        if i == 0:
            print child.before,child.befor
            print child.before,child.after
            print 'Time out'
            return False;
        if i == 1:
            child.sendline('yes')
        if i == 2:
            child.sendline(password)
        if i == 3:
            print child.before,child.after
            return True;
    return True;

# 发送命令
def ssh_command(host, user, password, post_command=None):
    global global_pexpect_instance
    print 'ssh -l %s %s'%(user, host);
    child = pexpect.spawn('ssh -l %s %s'%(user, host))
    global_pexpect_instance = child
    signal.signal(signal.SIGWINCH, sigwinch_passthrough)
    if not ssh_password(child,password):
        return None;
    if post_command :
        child.sendline(post_command);
    return child;
# 等待返回,当非字符交互界面时用:如执行命令,等待结束
def ssh_wait(child,other=None):
    step=[pexpect.TIMEOUT,    '.*[$#]'];
    if other:
        step.append(other);
    i = child.expect(step)
    print child.before
    print child.after

# 执行远程登录,如果有命令则直接返回,如果不是执行命令,则进入字符交互界面
def ssh(host,user,password,post_command=None):
    child=ssh_command(host,user,password,post_command)
    sigwinch_passthrough(None, None)
    if child==None:
        return
    if post_command==None:
        child.interact(chr(0x1e)) # ctrl+~
    else:
        ssh_wait(child)

解释

主要思路:

第一步: pexpect 包的spawn 执行ssh 并将用户名和地址填上

第二步:spawn会返回子进程的句柄,通过这个句柄,可以进行发送以及接收返回的字符串

第三步:使用 expect 函数,对返回进行正则匹配

第四步:

expect,会返回命中规则的下标,然后,可以对各种情况进行处理.

比如,在返回 ‘[pP]assword:.*’ 时,发送密码

第五步:

最后,调用interact 进入字符交互界面。然后,就可以手动输入其他命令了。

总结

有了这套工具,可以实现快捷地登录服务器,或者是以另外一种鉴权方式登录服务器(如短信)

比如,我当前的使用是,快捷登录,比如输入 myssh cmky 就可以登录我的服务器了。

相当方便,如果使用linux 还可以和tmux 一同工作。

番外篇:与tmux 一同工作

我们将以上脚本保存为一个叫myssh 的可执行文件,并保存在可执行目录下

我们添加一个脚本,叫tssh :

echo $1
ifattach=0;
tmux -L `whoami` list-sessions
if [[ $? -ne 0 ]]; then
    echo "mytmux";
    ifattach=1;
    tmux -L `whoami` new -d
fi
tmux -L `whoami` neww -n $1 "myssh $1"

if [[ $ifattach -eq 1 ]]; then
    echo "attach"
    tmux -L `whoami` attach
fi

之所以添加 -L whoami 是为了避免在多用户下,公用tmux 而产生的问题。

保证每个用户一个tmux 服务

注意替换 myssh $1 为你自己的命令。

部署python web环境

在这篇文章里,我们将搭建一个简单的 Web 应用,在虚拟环境中基于 Flask 框架,用 Gunicorn 做 wsgi 容器,用 Supervisor 管理进程,然后使用 OneAPM Python 探针来监测应用性能,形成一个「闭环」 !希望能对大家有所帮助,首先简单来介绍一下环境:

系统环境:ubuntu 14.04 Python 2.7.6

安装组件库

第一步安装所需要的存储库,因为打算用到虚拟环境,用到 pip 安装和管理 Python 组件,所以先更新本地包,然后安装组件:

sudo apt-get update
sudo apt-get install python-pip python-dev nginx

创建虚拟环境 virtualenv

在一个系统中创建不同的 Python 隔离环境,相互之间还不会影响,为了使系统保持干净,遂决定用 virtualenv 跑应用程序,创建一个容易识别的目录,开始安装,再创建项目目录 super,然后激活环境:

sudo pip install virtualenv
mkdir ~/supervisor && cd ~/supervisor
virtualenv super
source super/bin/activate

安装 Flask 框架

好了,现在在虚拟环境里面,开始安装 Flask 框架,flask 依赖两个库 werkzeug 和 jinjia2, 采用 pip 方式安装即可, pip 是一个重要的工具,Python 用它来管理包:

pip install flask

先用 Flask 写一个简单的 Web 服务 myweb.py ,因为后面要做一些测试,所以设置了几个请求:

from flask import Flask
app = Flask(__name__)
@app.route('/')
def index():
    return 'hello world  supervisor gunicorn '
@app.route('/1')
def index1():
    return 'hello world  supervisor gunicorn  ffffff'
@app.route('/qw/1')
def indexqw():
    return 'hello world  supervisor gunicorn fdfdfbdfbfb '
if __name__ == '__main__':
    app.debug = True
    app.run()

启动 Flask 看看!

python myweb.py

在浏览器中访问 http://127.0.0.1:5000 就可以看到了「几个路径都试一试」

用 Gunicorn 部署 Python Web

现在我们使用 Flask 自带的服务器,完成了 Web 服务的启动。生产环境下,Flask 自带的服务器,无法满足性能要求。所以我们这里采用 Gunicorn 做 wsgi 容器,用来部署 Python,首先还是安装 Gunicorn:

pip install gunicorn

当我们安装好 Gunicorn 之后,需要用 Gunicorn 启动 Flask,Flask 用自带的服务器启动时,Flask 里面的 name 里面的代码启动了 app.run()。而这里我们使用 Gunicorn,myweb.py 就等同于一个库文件,被 Gunicorn 调用,这样启动:

gunicorn -w 4 -b 0.0.0.0:8000 myweb:app

其中 myweb 就是指 myweb.py,app 就是那个 wsgifunc 的名字,这样运行监听 8000 端口,原先的 5000 端口并没有启用,-w 表示开启多少个 worker,-b 表示 Gunicorn 开发的访问地址。

想要结束 Gunicorn 只需执行 pkill Gunicorn,但有时候还要 ps 找到 pid 进程号才能 kill。可是这对于一个开发来说,太过于繁琐,因此出现了另外一个神器 —supervisor,一个专门用来管理进程的工具,还可以管理系统的工具进程。

安装 Supervisor

pip install supervisor
echo_supervisord_conf > supervisor.conf  # 生成 supervisor 默认配置文件
gedit  supervisor.conf                   # 修改 supervisor 配置文件,添加 gunicorn 进程管理

在 supervisor.conf 底部下添加 myweb.py 的配置 /home/wang/supervisor/super 是我的项目目录

[program:myweb]
command=/home/wang/supervisor/super/bin/gunicorn -w 4 -b 0.0.0.0:8000 myweb:app                                                                    
directory=/home/wang/supervisor                                            
startsecs=0                                                                  
stopwaitsecs=0                                                                  
autostart=false                                                                
autorestart=false                                                                
user=wang                                                                    
stdout_logfile=/home/wang/supervisor/log/gunicorn.log                  
stderr_logfile=/home/wang/supervisor/log/gunicorn.err

supervisor 的基本使用命令:

supervisord -c supervisor.conf    
supervisorctl -c supervisor.conf status                  查看supervisor的状态                                      
supervisorctl -c supervisor.conf reload                  重新载入 配置文件
supervisorctl -c supervisor.conf start [all]|[appname]   启动指定/所有 supervisor 管理的程序进程
supervisorctl -c supervisor.conf stop [all]|[appname]    关闭指定/所有 supervisor 管理的程序进程

supervisor 还有一个 web 的管理界面,可以激活。更改下配置:

[inet_http_server]     ; inet (TCP) server disabled by default
port=127.0.0.1:9001    ; (ip_address:port specifier, *:port for alliface)
username=wang          ; (default is no username (open server)
password=123           ; (default is no password (open server))
[supervisorctl]
serverurl=unix:///tmp/supervisor.sock ; use a unix:// URL  for a unix socket
serverurl=http://127.0.0.1:9001       ; use an http:// url to specify an inet socket
username=wang                         ; should be same as http_username if set
password=123                          ; should be same as http_password if set
;prompt=mysupervisor                  ; cmd line prompt (default "supervisor")
;history_file=~/.sc_history           ; use readline history if available

现在可以使用 supervsior 启动 gunicorn 啦。运行命令:

supervisord -c supervisor.conf

浏览器访问 http://127.0.0.1:9001 可以得到 supervisor 的 web 管理界面,访问http://127.0.0.1:8000 可以看见 gunicorn 启动的返回的页面。

配置 Nginx

前面我们已经在系统环境下安装了 Nginx, 安装好的 Nginx 二进制文件放在 /usr/sbin/ 文件夹下,接下来使用 Supervisor 来管理 Nginx。这里需要注意一个问题,权限问题。Nginx 是 sudo 的方式安装,启动的适合也是 root 用户,那么我们现在也需要用 root 用户启动 supervisor。在 supervisor.conf 下添加配置文件:

[program:nginx]
command=/usr/sbin/nginx
startsecs=0
stopwaitsecs=0
autostart=false
autorestart=false
stdout_logfile=/home/wang/supervisor/log/nginx.log
stderr_logfile=/home/wang/supervisor/log/nginx.err

好了,都配置完之后,启动 supervisor:

supervisord -c supervisor.conf

访问页面,也可以用 ab 进行压力测试:

ab -c 100 -n 100 http://127.0.0.1:8000/qw/1

-c 用于指定压力测试的并发数, -n 用于指定压力测试总共的执行次数。

安装 Python 探针

搭建好了 web,想实时监控应用数据,有什么好的工具,用 OneAPM 的 Python 探针试试,
首先也是安装 Python 探针:

pip install -i http://pypi.oneapm.com/simple --upgrade blueware

根据 License Key 生成配置文件:

blueware-admin generate-config (License Key) = blueware.ini

由于是在虚拟环境下,所以要特别注意路径,修改 supervisor.conf 里面两项:

[program:myapp]
command = /home/wang/supervisor/super/bin/blueware-admin run-program /home/wang/supervisor/super/bin/gunicorn -w 4 -b 0.0.0.0:8000 myapp:app
environment = BLUEWARE_CONFIG_FILE=blueware.ini

重启应用

supervisorctl    # 进入命令行
supervisor>  reload    # 重新加载

向上面一样访问页面,也可以用 ab 进行压力测试
几分钟后有下图,可以看到页面加载时间,web 事物,页面吞吐量,其中后面是设置自定义事物「Business Transaction」。

使用Python操作Zabbix Api

众所周知,zabbix是一款强大的分布式监控系统,集各家所长于一体,得到了广大SA的认可。其强大的管理界面也极其方便,但是美中不足的是,如果同时有大批量(50台+)的服务器需要添加监控时,这时,其图形界面反而显得有些臃肿了,好在zabbix提供了一套强大的API管理接口,我们可以使用它快速地添加或删除成千上万台服务器了。

下面的流程图代表了Zabbix API 工作的典型工作流。验证(方法user.login)是获取验证ID的强制步骤。这个ID又允许我们调用API提供的任何权限允许的方法来进行操作。在之前的例子中没有提到user.logout方法,这也是一次验证ID能够重复使用的原因所在。使用user.logout方法后将会使验证ID失效,后面的操作将不能再使用此ID。

未分类

1. 首先获取所有模板及ID

#!/usr/bin/python 
#coding:utf-8 

import json 
import urllib2 
from urllib2 import URLError 
import sys,argparse

class zabbix_api: 
    def __init__(self):
        self.url = 'http://10.0.8.8/api_jsonrpc.php'
        self.header = {"Content-Type":"application/json"}

    def user_login(self): 
        data = json.dumps({ 
                           "jsonrpc": "2.0", 
                           "method": "user.login", 
                           "params": { 
                                      "user": "pengdongwen",            #修改用户名
                                      "password": "pengdongwen"         #修改密码
                                      }, 
                           "id": 0 
                           }) 

        request = urllib2.Request(self.url, data) 
        for key in self.header: 
            request.add_header(key, self.header[key]) 

        try: 
            result = urllib2.urlopen(request) 
        except URLError as e: 
            print "33[041m 用户认证失败,请检查 !33[0m", e.code 
        else: 
            response = json.loads(result.read()) 
            result.close() 
            #print response['result'] 
            self.authID = response['result'] 
            return self.authID 

    def template_get(self,templateName=''): 
        data = json.dumps({ 
                           "jsonrpc":"2.0", 
                           "method": "template.get", 
                           "params": { 
                                      "output": "extend", 
                                      "filter": { 
                                                 "name":templateName                                                        
                                                 } 
                                      }, 
                           "auth":self.user_login(), 
                           "id":1, 
                           })

        request = urllib2.Request(self.url, data) 
        for key in self.header: 
            request.add_header(key, self.header[key]) 

        try: 
            result = urllib2.urlopen(request) 
        except URLError as e: 
            print "Error as ", e 
        else: 
            response = json.loads(result.read()) 
            result.close() 
            #print response
            for template in response['result']:                
                if len(templateName)==0:
                    print "template : 33[31m%s33[0mt  id : %s" % (template['name'], template['templateid'])
                else:
                    self.templateID = response['result'][0]['templateid'] 
            print "Template Name :  33[31m%s33[0m "%templateName
                    return response['result'][0]['templateid']

if __name__ == "__main__":
    zabbix=zabbix_api()
        zabbix_api().template_get()

2. 根据模板ID获取某个模板关联的主机ID

#!/usr/bin/python 
#coding:utf-8 

import json 
import urllib2 
from urllib2 import URLError 
import sys,argparse

class zabbix_api: 
    def __init__(self):
        self.url = 'http://10.0.8.8/api_jsonrpc.php'
        self.header = {"Content-Type":"application/json"}

    def user_login(self): 
        data = json.dumps({ 
                           "jsonrpc": "2.0", 
                           "method": "user.login", 
                           "params": { 
                                      "user": "pengdongwen",            #修改用户名
                                      "password": "pengdongwen" #修改密码
                                      }, 
                           "id": 0 
                           }) 

        request = urllib2.Request(self.url, data) 
        for key in self.header: 
            request.add_header(key, self.header[key]) 

        try: 
            result = urllib2.urlopen(request) 
        except URLError as e: 
            print "33[041m 用户认证失败,请检查 !33[0m", e.code 
        else: 
            response = json.loads(result.read()) 
            result.close() 
            self.authID = response['result'] 
            return self.authID 

    def host_get(self): 
        data=json.dumps({
                "jsonrpc": "2.0",
                "method": "host.get",
                "params": {
                          "output": ["hostid","name"],
                              "templateids":["10105"]
                          },
                "auth": self.user_login(),
                "id": 1
                })
        request = urllib2.Request(self.url,data) 
        for key in self.header: 
            request.add_header(key, self.header[key]) 

        try: 
            result = urllib2.urlopen(request) 
        except URLError as e: 
            if hasattr(e, 'reason'): 
                print 'We failed to reach a server.' 
                print 'Reason: ', e.reason 
            elif hasattr(e, 'code'): 
                print 'The server could not fulfill the request.' 
                print 'Error code: ', e.code 
        else: 
            response = json.loads(result.read()) 
            #print response
                for host in response['result']:
                    print "HostID : %st HostName : %st"%(host['hostid'],host['name'])
            result.close() 
            #print "主机数量: 33[31m%s33[0m"%(len(response['result']))

if __name__ == "__main__":
        zabbix=zabbix_api()
        zabbix.host_get()

3. 根据主机ID获取主机IP地址

#!/usr/bin/python 
#coding:utf-8 

import json 
import urllib2 
from urllib2 import URLError 
import sys,argparse

class zabbix_api: 
    def __init__(self):
        self.url = 'http://10.0.8.8/api_jsonrpc.php'
        self.header = {"Content-Type":"application/json"}

    def user_login(self): 
        data = json.dumps({ 
                           "jsonrpc": "2.0", 
                           "method": "user.login", 
                           "params": { 
                                      "user": "pengdongwen",            #修改用户名
                                      "password": "pengdongwen"         #修改密码
                                      }, 
                           "id": 0 
                           }) 

        request = urllib2.Request(self.url, data) 
        for key in self.header: 
            request.add_header(key, self.header[key]) 

        try: 
            result = urllib2.urlopen(request) 
        except URLError as e: 
            print "33[041m 用户认证失败,请检查 !33[0m", e.code 
        else: 
            response = json.loads(result.read()) 
            result.close() 
            self.authID = response['result'] 
            return self.authID 

    def host_ip(self): 
        data=json.dumps({
                "jsonrpc": "2.0",
                "method": "hostinterface.get",
                "params": {
                          "output": ["hostid","ip"],
                              "hostids": ["10031"]
                          },
                "auth": self.user_login(),
                "id": 1
                })
        request = urllib2.Request(self.url,data) 
        for key in self.header: 
            request.add_header(key, self.header[key]) 

        try: 
            result = urllib2.urlopen(request) 
        except URLError as e: 
            if hasattr(e, 'reason'): 
                print 'We failed to reach a server.' 
                print 'Reason: ', e.reason 
            elif hasattr(e, 'code'): 
                print 'The server could not fulfill the request.' 
                print 'Error code: ', e.code 
        else: 
            response = json.loads(result.read()) 
            #print response
                for host in response['result']:
                    print "HostID: %st IP: %st"%(host['hostid'],host['ip'])
            result.close() 
            print "主机数量: 33[31m%s33[0m"%(len(response['result']))

if __name__ == "__main__":
        zabbix=zabbix_api()
        zabbix.host_ip()

4. 多功能API

#!/usr/bin/python 
#coding:utf-8 

import json 
import urllib2 
from urllib2 import URLError 
import sys,argparse

class zabbix_api: 
    def __init__(self):
        self.url = 'http://nh.monitor.ejuops.com/api_jsonrpc.php'
        self.header = {"Content-Type":"application/json"}

    def user_login(self): 
        data = json.dumps({ 
                           "jsonrpc": "2.0", 
                           "method": "user.login", 
                           "params": { 
                                      "user": "pengdongwen",            #修改用户名
                                      "password": "pengdongwen@eju" #修改密码
                                      }, 
                           "id": 0 
                           }) 

        request = urllib2.Request(self.url, data) 
        for key in self.header: 
            request.add_header(key, self.header[key]) 

        try: 
            result = urllib2.urlopen(request) 
        except URLError as e: 
            print "33[041m 用户认证失败,请检查 !33[0m", e.code 
        else: 
            response = json.loads(result.read()) 
            result.close() 
            #print response['result'] 
            self.authID = response['result'] 
            return self.authID 

    def host_get(self,hostName=''): 
        data=json.dumps({
                "jsonrpc": "2.0",
                "method": "host.get",
                "params": {
                          "output": "extend",
                          "filter":{"host":hostName} 
                          },
                "auth": self.user_login(),
                "id": 1
                })
        request = urllib2.Request(self.url,data) 
        for key in self.header: 
            request.add_header(key, self.header[key]) 


        try: 
            result = urllib2.urlopen(request) 
        except URLError as e: 
            if hasattr(e, 'reason'): 
                print 'We failed to reach a server.' 
                print 'Reason: ', e.reason 
            elif hasattr(e, 'code'): 
                print 'The server could not fulfill the request.' 
                print 'Error code: ', e.code 
        else: 
            response = json.loads(result.read()) 
            #print response
            result.close() 
            print "主机数量: 33[31m%s33[0m"%(len(response['result']))
            for host in response['result']:      
                    status={"0":"OK","1":"Disabled"}
            available={"0":"Unknown","1":"available","2":"Unavailable"}
            #print host
            if len(hostName)==0:
                        print "HostID : %st HostName : %st Status :33[32m%s33[0m t Available :33[31m%s33[0m"%(host['hostid'],host['name'],status[host['status']],available[host['available']])
            else:
                        print "HostID : %st HostName : %st Status :33[32m%s33[0m t Available :33[31m%s33[0m"%(host['hostid'],host['name'],status[host['status']],available[host['available']])
                return host['hostid']

    def hostgroup_get(self, hostgroupName=''): 
        data = json.dumps({ 
                           "jsonrpc":"2.0", 
                           "method":"hostgroup.get", 
                           "params":{ 
                                     "output": "extend", 
                                     "filter": { 
                                                "name": hostgroupName 
                                                } 
                                     }, 
                           "auth":self.user_login(), 
                           "id":1, 
                           }) 

        request = urllib2.Request(self.url,data) 
        for key in self.header: 
            request.add_header(key, self.header[key]) 

        try: 
            result = urllib2.urlopen(request) 
        except URLError as e: 
            print "Error as ", e 
        else: 
            #print result.read()
            response = json.loads(result.read()) 
            result.close() 
            #print response()
            for group in response['result']:
                if  len(hostgroupName)==0:
                    print "hostgroup:  33[31m%s33[0m tgroupid : %s" %(group['name'],group['groupid'])
            else:
                    print "hostgroup:  33[31m%s33[0mtgroupid : %s" %(group['name'],group['groupid'])
                    self.hostgroupID = group['groupid'] 
                    return group['groupid'] 


    def template_get(self,templateName=''): 
        data = json.dumps({ 
                           "jsonrpc":"2.0", 
                           "method": "template.get", 
                           "params": { 
                                      "output": "extend", 
                                      "filter": { 
                                                 "name":templateName                                                        
                                                 } 
                                      }, 
                           "auth":self.user_login(), 
                           "id":1, 
                           })

        request = urllib2.Request(self.url, data) 
        for key in self.header: 
            request.add_header(key, self.header[key]) 

        try: 
            result = urllib2.urlopen(request) 
        except URLError as e: 
            print "Error as ", e 
        else: 
            response = json.loads(result.read()) 
            result.close() 
            #print response
            for template in response['result']:                
                if len(templateName)==0:
                    print "template : 33[31m%s33[0mt  id : %s" % (template['name'], template['templateid'])
                else:
                    self.templateID = response['result'][0]['templateid'] 
            print "Template Name :  33[31m%s33[0m "%templateName
                    return response['result'][0]['templateid']
    def hostgroup_create(self,hostgroupName):

        if self.hostgroup_get(hostgroupName):
            print "hostgroup  33[42m%s33[0m is exist !"%hostgroupName
            sys.exit(1)
        data = json.dumps({
                          "jsonrpc": "2.0",
                          "method": "hostgroup.create",
                          "params": {
                          "name": hostgroupName
                          },
                          "auth": self.user_login(),
                          "id": 1
                          })
        request=urllib2.Request(self.url,data)

        for key in self.header: 
            request.add_header(key, self.header[key]) 

        try: 
            result = urllib2.urlopen(request)
        except URLError as e: 
            print "Error as ", e 
        else: 
            response = json.loads(result.read()) 
            result.close()
            print "33[042m 添加主机组:%s33[0m  hostgroupID : %s"%(hostgroupName,response['result']['groupids'])



    def host_create(self, hostip, hostgroupName, templateName): 
        if self.host_get(hostip):
        print "33[041m该主机已经添加!33[0m" 
        sys.exit(1)
            if self.hostgroup_get(hostgroupName):
                print "33[041m该主机组存在!33[0m"
            else:
                data = json.dumps({
                                  "jsonrpc": "2.0",
                                  "method": "hostgroup.create",
                                  "params": {
                                  "name": hostgroupName
                                  },
                                  "auth": self.user_login(),
                                  "id": 1
                })
                request=urllib2.Request(self.url,data)

                for key in self.header:
                    request.add_header(key, self.header[key])

                try:
                    result = urllib2.urlopen(request)
                except URLError as e:
                    print "Error as ", e
                else:
                    response = json.loads(result.read())
                    result.close()
                    #print "33[042m 添加主机组:%s33[0m  hostgroupID : %s"%(hostgroupName,response['result']['groupids'])

        group_list=[]
        template_list=[]
        for i in hostgroupName.split(','):
            var = {}
            var['groupid'] = self.hostgroup_get(i)
            group_list.append(var)
        for i in templateName.split(','):
            var={}
            var['templateid']=self.template_get(i)
            template_list.append(var)   

        data = json.dumps({ 
                           "jsonrpc":"2.0", 
                           "method":"host.create", 
                           "params":{ 
                                     "host": hostip, 
                                     "interfaces": [ 
                                     { 
                                     "type": 1, 
                                     "main": 1, 
                                     "useip": 1, 
                                     "ip": hostip, 
                                     "dns": "", 
                                     "port": "10050" 
                                      } 
                                     ], 
                                   "groups": group_list,
                                   "templates": template_list,
                                     }, 
                           "auth": self.user_login(), 
                           "id":1                   
        }) 
        request = urllib2.Request(self.url, data) 
        for key in self.header: 
            request.add_header(key, self.header[key]) 

        try: 
            result = urllib2.urlopen(request) 
        except URLError as e: 
            print "Error as ", e 
        else: 
            response = json.loads(result.read()) 
            result.close() 
            print "添加主机 : 33[42m%s31[0m tid :33[31m%s33[0m" % (hostip, response['result']['hostids']) 



    def host_disable(self,hostip):
        data=json.dumps({
        "jsonrpc": "2.0",
        "method": "host.update",
        "params": {
        "hostid": self.host_get(hostip),
        "status": 1
        },
        "auth": self.user_login(),
        "id": 1
        })
        request = urllib2.Request(self.url,data)
            for key in self.header:
                request.add_header(key, self.header[key])       
            try: 
                result = urllib2.urlopen(request)
            except URLError as e: 
                print "Error as ", e 
            else: 
                response = json.loads(result.read()) 
                result.close()
                print '----主机现在状态------------'
            print self.host_get(hostip)


    def host_delete(self,hostid):
        hostid_list=[]
        #print type(hostid)
        for i in hostid.split(','):
            var = {}
            var['hostid'] = self.host_get(i)
            hostid_list.append(var)      
        data=json.dumps({
                "jsonrpc": "2.0",
                "method": "host.delete",
                "params": hostid_list,
                "auth": self.user_login(),
                "id": 1
                })

        request = urllib2.Request(self.url,data) 
        for key in self.header: 
            request.add_header(key, self.header[key]) 

        try: 
            result = urllib2.urlopen(request) 
        except Exception,e: 
            print  e
        else: 

            result.close() 
            print "主机 33[041m %s33[0m  已经删除 !"%hostid 


if __name__ == "__main__":
    zabbix=zabbix_api()
    parser=argparse.ArgumentParser(description='zabbix  api ',usage='%(prog)s [options]')
    parser.add_argument('-H','--host',nargs='?',dest='listhost',default='host',help='查询主机')
    parser.add_argument('-G','--group',nargs='?',dest='listgroup',default='group',help='查询主机组')
    parser.add_argument('-T','--template',nargs='?',dest='listtemp',default='template',help='查询模板信息')
    parser.add_argument('-A','--add-group',nargs=1,dest='addgroup',help='添加主机组')
    parser.add_argument('-C','--add-host',dest='addhost',nargs=3,metavar=('192.168.2.1', 'test01,test02', 'Template01,Template02'),help='添加主机,多个主机组或模板使用分号')
    parser.add_argument('-d','--disable',dest='disablehost',nargs=1,metavar=('192.168.2.1'),help='禁用主机')
    parser.add_argument('-D','--delete',dest='deletehost',nargs='+',metavar=('192.168.2.1'),help='删除主机,多个主机之间用分号')
    parser.add_argument('-v','--version', action='version', version='%(prog)s 1.0')
    if len(sys.argv)==1:
        print parser.print_help()
    else:
        args=parser.parse_args()

        if args.listhost != 'host' :
            if args.listhost:
                zabbix.host_get(args.listhost)
            else:
                zabbix.host_get()
        if args.listgroup !='group':
            if args.listgroup:
                zabbix.hostgroup_get(args.listgroup)
            else:
                zabbix.hostgroup_get()
        if args.listtemp != 'template':
            if args.listtemp:
                zabbix.template_get(args.listtemp)
            else:
                zabbix.template_get()
        if args.addgroup:
            zabbix.hostgroup_create(args.addgroup[0])
        if args.addhost:
            zabbix.host_create(args.addhost[0], args.addhost[1], args.addhost[2])
        if args.disablehost:
            zabbix.host_disable(args.disablehost)
        if args.deletehost:
            zabbix.host_delete(args.deletehost[0])

完结。。。

python升级后使用yum出现No module named yum错误处理

最近在看python,虚拟机装的是Centos6.6,自带的python版本是2.6.6,打算升级到2.7。

我的升级过程大致如下:

  • 下载2.7源码包https://www.python.org/downloads/source/
  • 卸载旧的python,rpm -e python
  • 编译安装python2.7

整个过程没有遇到问题,但升级完后,再用yum安装软件时报如下错误

[root@localhost python]# yum
There was a problem importing one of the Python modules
required to run yum. The error leading to this problem was:

   No module named yum

Please install a package which provides this module, or
verify that the module is installed correctly.

It's possible that the above module doesn't match the
current version of Python, which is:
2.7.13 (r266:84292, Jan 22 2014, 09:37:14) 
[GCC 4.4.7 20120313 (Red Hat 4.4.7-4)]

If you cannot solve this problem yourself, please go to 
the yum faq at:
  http://yum.baseurl.org/wiki/Faq

yum不可用了,这下问题就大了,spacer.gif没有yum,安装rpm包特别费劲。

开始百度关键字“No module named yum”,出来很多帖子和博客,博客上边说的大概意思就是yum就基于python的,升级python后,yum与高版本的python不兼容,导致yum无法使用。博客上给出的方法都是修改/usr/bin/yum文件的头部,把/usr/bin/python修改为/usr/bin/python2.6就可以了,但我的情况是我把旧的python已经卸载了,于是又开始安装2.6版本的python。

安装好2.6.6版本的之后以为就好了,但是还是报有错误:

[root@localhost python]# yum
There was a problem importing one of the Python modules
required to run yum. The error leading to this problem was:

   No module named yum

Please install a package which provides this module, or
verify that the module is installed correctly.

It's possible that the above module doesn't match the
current version of Python, which is:
2.6.6 (r266:84292, Jan 22 2014, 09:37:14) 
[GCC 4.4.7 20120313 (Red Hat 4.4.7-4)]

If you cannot solve this problem yourself, please go to 
the yum faq at:
  http://yum.baseurl.org/wiki/Faq

这就奇怪了,都已经把旧版本的装上了,还是不行。这时看到一篇博客是把python和yum都全部卸载后重新安装的。想想这也是个办法于是就又全部下载

whereis python |xargs rm -rf
rpm -e --nodeps python

卸载后重新安装,从光盘镜像里找到python和yum的包

rpm -ivh --nodeps python*
rpm -ivh --nodeps yum*

这次总该好了吧,验证一下

[root@localhost python]# python
Python 2.6.6 (r266:84292, Jan 22 2014, 09:37:14) 
[GCC 4.4.7 20120313 (Red Hat 4.4.7-4)] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> import yum
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/usr/lib/python2.6/site-packages/yum/__init__.py", line 23, in <module>
    import rpm
ImportError: No module named rpm

还是报错。。。

spacer.gif不过这次错误变了,变成了“No module named rpm”

再次百度,看到有人说是缺少包:rpm -ivh rpm-python-4.8.0-37.el6.i686.rpm

安装上面的包后一切yum恢复正常了。

那问题又来了难道因为yum就不升级python版本吗?当然不是。其实是我在安装新版python的时候把旧版本的也卸载了才导致这样的问题。

后来在不卸载2.6版本的python是,重新编译安装2.7版本,安装成功并且yum仍然可用。

python virtualenv 虚拟环境的使用

虚拟环境是一个将不同项目所需求的依赖分别放在独立的地方的一个工具,它给这些工程创建虚拟的 Python环境。它解决了“项目X依赖于版本1.x,而项目Y需要项目4.x”的两难问题,而且使你的全局 site-packages 目录保持干净和可管理。软件工程师全都是有洁癖的,这就出现下面的神器 virtualenv。

安装 virtualenv

首先,我们用 pip 安装 virtualenv:

$ pip install virtualenv

测试你的安装

$ virtualenv --version

进入我们的项目目录,创建一个独立的 Python 运行环境,命名为 venv。virtualenv venv 将会在当前的目录中创建一个文件夹包含了 Python 可执行文件, 以及 pip 库的一份拷贝,这样就能安装其他包了。虚拟环境的名字(此例中是 venv ) 可以是任意的;若省略名字将会把文件均放在当前目录。

$ cd /data/myproject
$ virtualenv --no-site-packages venv
Using base prefix '/usr/local/.../Python.framework/Versions/3.4'
New python executable in venv/bin/python3.4
Also creating executable in venv/bin/python
Installing setuptools, pip, wheel...done.

你可以选择使用一个Python解释器(比如python2.7):

$ virtualenv -p /usr/bin/python2.7 venv

命令 virtualenv 就可以创建一个独立的 Python 运行环境,我们还加上了参数 –no-site-packages,这样,已经安装到系统 Python 环境中的所有第三方包都不会复制过来,这样,我们就得到了一个不带任何第三方包的“干净”的 Python 运行环境。

进入独立环境

新建的 Python 环境被放到当前目录下的 venv 目录。有了 venv 这个 Python 环境,可以用 source 进入该环境:

$ source venv/bin/activate
(venv) $

以下命令会有相同效果:

$ . ./venv/bin/activate
(venv) $

注意到命令提示符变了,有个 (venv) 前缀,表示当前环境是一个名为 venv 的 Python 环境。

下面就可以正常安装各种第三方扩展包,并运行 python 命令:

(venv) $ pip3 install flask

在 venv 环境下,用 pip 安装的包都被安装到 venv 这个环境下,系统 Python 环境不受任何影响。也就是说,venv 环境是专门针对 myproject 这个应用创建的。

退出独立环境

退出当前的 venv 环境,使用 deactivate 命令:

(venv) $ deactivate
$

此时就回到了正常的环境,现在 pip 或 python 均是在系统 Python 环境下执行。

完全可以针对每个应用创建独立的 Python 运行环境,这样就可以对每个应用的 Python 环境进行隔离。

virtualenv 是如何创建“独立”的 Python 运行环境的呢?原理很简单,就是把系统 Python 复制一份到 virtualenv 的环境,用命令 source venv/bin/activate 进入一个 virtualenv 环境时,virtualenv 会修改相关环境变量,让命令 python 和 pip 均指向当前的 virtualenv 环境。

自动激活环境工具 autoenv

当你 cd 进入一个包含 .env 的目录中,就会 autoenv 自动激活那个环境。

使用 brew 在 Mac OS X上安装它:

$ brew install autoenv

在 Linux 上:

$ git clone git://github.com/kennethreitz/autoenv.git ~/.autoenv
$ echo 'source ~/.autoenv/activate.sh' >> ~/.bashrc

项目地址:https://github.com/kennethreitz/autoenv/

其它注意

运行带 –no-site-packages 选项的 virtualenv 将不会包括全局安装的包。 这可用于保持包列表干净,以防以后需要访问它。(这在 virtualenv 1.7及之后是默认行为)