├── .gitignore ├── MyShow ├── GetData_zhihu.py ├── MyShow.py ├── static │ ├── css │ │ └── dashboard.css │ ├── favicon.ico │ └── js │ │ ├── bootstrap-typeahead.min.js │ │ ├── bootstrap.min.js │ │ ├── echarts.min.js │ │ └── jquery-3.0.0.min.js └── templates │ ├── base.html │ ├── error.html │ └── index.html ├── Plotly ├── bar.ipynb ├── base.ipynb ├── box.ipynb ├── candlestick.ipynb ├── gantt.ipynb ├── gauge.ipynb ├── heatmaps.ipynb ├── histogram&distplot.ipynb ├── line.ipynb ├── pie.ipynb ├── radar.ipynb ├── sankey.ipynb ├── scatter.ipynb └── table.ipynb ├── README.md ├── Text ├── Obama.txt ├── Walden.txt └── Zarathustra.txt ├── python_aiohttp.py ├── python_base.py ├── python_celery.py ├── python_celery_test.py ├── python_context.py ├── python_coroutine.py ├── python_csv.py ├── python_datetime.py ├── python_decorator.py ├── python_flask.py ├── python_functional.py ├── python_lda.py ├── python_magic_methods.py ├── python_mail.py ├── python_markov_chain.py ├── python_metaclass.py ├── python_numpy.py ├── python_oneline.py ├── python_re.py ├── python_redis.py ├── python_requests.py ├── python_restful_api.py ├── python_schedule.py ├── python_socket.py ├── python_spider.py ├── python_splash.py ├── python_sqlalchemy.py ├── python_thread_multiprocess.py ├── python_version36.py ├── python_visual.py ├── python_visual_animation.py ├── python_wechat.py ├── python_weibo.py ├── test.png └── wxPython └── hello_world.py /.gitignore: -------------------------------------------------------------------------------- 1 | # Created by .ignore support plugin (hsz.mobi) 2 | *.[oa] 3 | *.py[co] 4 | *.exe 5 | *.log 6 | *.out 7 | *.dat 8 | *.temp 9 | *.png 10 | *.pkl 11 | *.mp3 12 | *.mp4 13 | *.csv 14 | .* 15 | 16 | venv/ 17 | test/ 18 | data/ 19 | build/ 20 | captcha.jpeg 21 | -------------------------------------------------------------------------------- /MyShow/GetData_zhihu.py: -------------------------------------------------------------------------------- 1 | # _*_ coding: utf-8 _*_ 2 | 3 | import pymysql 4 | 5 | con = pymysql.connect(host="xxxx", user="root", passwd="xxxx", db="xxxx", charset="utf8") 6 | cursor = con.cursor() 7 | con.autocommit(1) 8 | 9 | 10 | def get_all_topics(): 11 | cursor.execute("select distinct t_topic_id, t_topic_name from t_zhihutopics where t_topic_haschildren = 1;") 12 | return [item for item in cursor.fetchall() if item[0].strip()] 13 | 14 | 15 | def get_topic_data(topic_id, topic_name): 16 | data_dict = { 17 | "type": "force", 18 | "nodes": [ 19 | {"id": topic_id, "name": topic_name, "level": 0} 20 | ], 21 | "links": [] 22 | } 23 | 24 | nodes_set = set([topic_id]) 25 | dai_ids = set([topic_id]) 26 | while dai_ids: 27 | cursor.execute("select * from t_zhihutopics where t_topic_parentid = %s;", [dai_ids.pop()]) 28 | for item in cursor.fetchall(): 29 | _, t_id, t_name, t_pid, t_haschild, _ = item 30 | 31 | if t_id not in nodes_set: 32 | nodes_set.add(t_id) 33 | data_dict["nodes"].append({"id": t_id, "name": t_name, "level": 1 if t_pid == topic_id else 2}) 34 | data_dict["links"].append({"source": t_pid, "target": t_id}) 35 | 36 | if t_haschild == 1: 37 | dai_ids.add(t_id) 38 | return data_dict 39 | -------------------------------------------------------------------------------- /MyShow/MyShow.py: -------------------------------------------------------------------------------- 1 | # _*_ coding: utf-8 _*_ 2 | 3 | import logging 4 | import GetData_zhihu 5 | 6 | # flask 7 | from flask import Flask, session, request 8 | from flask import render_template, flash, redirect, url_for, jsonify 9 | 10 | # flask extends 11 | from flask_bootstrap import Bootstrap 12 | from flask_wtf import FlaskForm 13 | from wtforms import StringField, PasswordField, SubmitField 14 | from wtforms.validators import Length, Email 15 | 16 | # application 17 | app = Flask(__name__) 18 | app.config["SECRET_KEY"] = "hard to guess string" 19 | 20 | # manager and bootstrap 21 | bootstrap = Bootstrap(app=app) 22 | 23 | # global data 24 | zhihu_all_topics = GetData_zhihu.get_all_topics() 25 | zhihu_all_topics_key = {} 26 | zhihu_init_topics = GetData_zhihu.get_topic_data(topic_id="19559424", topic_name="数据分析") 27 | 28 | 29 | # form class 30 | class UserForm(FlaskForm): 31 | name = StringField("name", validators=[Email(message="邮箱格式不正确!")]) 32 | password = PasswordField("password", validators=[Length(min=6, message="密码长度至少6位!")]) 33 | submit = SubmitField("提 交") 34 | 35 | 36 | @app.route("/", methods=["GET", "POST"]) 37 | def temp(): 38 | return redirect(url_for("index")) 39 | 40 | 41 | @app.route("/index/", methods=["GET", "POST"]) 42 | def index(): 43 | user_form = UserForm() 44 | if request.method == "POST": 45 | if user_form.validate_on_submit(): 46 | session["username"] = user_form.name.data 47 | else: 48 | flash(user_form.errors["name"][0] if "name" in user_form.errors else user_form.errors["password"][0]) 49 | else: 50 | if request.args.get("action") == "login_out": 51 | flash("您已成功退出系统!") 52 | session["username"] = None 53 | return redirect(url_for("index")) 54 | elif request.args.get("action") == "overview": 55 | session["page_type"] = "overview" 56 | return redirect(url_for("index")) 57 | elif request.args.get("action") == "zhihu_topics": 58 | session["page_type"] = "zhihu_topics" 59 | return redirect(url_for("index")) 60 | return render_template("index.html", name=session.get("username"), page_type=session.get("page_type", "overview"), form=user_form) 61 | 62 | 63 | @app.route("/zhihu_get_topics_list/", methods=["post"]) 64 | def zhihu_get_topics_list(): 65 | key = request.form.get("key") 66 | result = {"success": 1, "data": []} 67 | if key: 68 | if key in zhihu_all_topics_key: 69 | result = zhihu_all_topics_key[key] 70 | else: 71 | for item in zhihu_all_topics: 72 | if item[1].find(key) >= 0: 73 | result["data"].append({"id": item[0], "name": item[1]}) 74 | if len(result["data"]) > 0: 75 | result["success"] = 1 76 | zhihu_all_topics_key[key] = result 77 | logging.debug("all_topics_key increase: %s", len(zhihu_all_topics_key)) 78 | return jsonify(result) 79 | 80 | 81 | @app.route("/zhihu_get_topics_data/", methods=["post"]) 82 | def zhihu_get_topics_data(): 83 | if request.form["id"] == "19554449": 84 | result = zhihu_init_topics 85 | else: 86 | result = GetData_zhihu.get_topic_data(request.form["id"], request.form["name"]) 87 | return jsonify(result) 88 | 89 | 90 | @app.errorhandler(404) 91 | def page_not_found(excep): 92 | return render_template("error.html", error=excep, name=session.get("username")), 404 93 | 94 | 95 | # main process 96 | if __name__ == "__main__": 97 | logging.basicConfig(level=logging.DEBUG, format="%(asctime)s\t%(levelname)s\t%(message)s") 98 | logging.debug("app url_map: %s", app.url_map) 99 | 100 | app.run() 101 | -------------------------------------------------------------------------------- /MyShow/static/css/dashboard.css: -------------------------------------------------------------------------------- 1 | /* 2 | * Base structure 3 | */ 4 | 5 | /* Move down content because we have a fixed navbar that is 50px tall */ 6 | body { 7 | padding-top: 50px; 8 | } 9 | 10 | 11 | /* 12 | * Global add-ons 13 | */ 14 | 15 | .sub-header { 16 | padding-bottom: 10px; 17 | border-bottom: 1px solid #eee; 18 | } 19 | 20 | /* 21 | * Top navigation 22 | * Hide default border to remove 1px line. 23 | */ 24 | .navbar-fixed-top { 25 | border: 0; 26 | } 27 | 28 | /* 29 | * Sidebar 30 | */ 31 | 32 | /* Hide for mobile, show later */ 33 | .sidebar { 34 | display: none; 35 | } 36 | @media (min-width: 768px) { 37 | .sidebar { 38 | position: fixed; 39 | top: 51px; 40 | bottom: 0; 41 | left: 0; 42 | z-index: 1000; 43 | display: block; 44 | padding: 20px; 45 | overflow-x: hidden; 46 | overflow-y: auto; /* Scrollable contents if viewport is shorter than content. */ 47 | background-color: #f5f5f5; 48 | border-right: 1px solid #eee; 49 | } 50 | } 51 | 52 | /* Sidebar navigation */ 53 | .nav-sidebar { 54 | margin-right: -21px; /* 20px padding + 1px border */ 55 | margin-bottom: 20px; 56 | margin-left: -20px; 57 | } 58 | .nav-sidebar > li > a { 59 | padding-right: 20px; 60 | padding-left: 20px; 61 | } 62 | .nav-sidebar > .active > a, 63 | .nav-sidebar > .active > a:hover, 64 | .nav-sidebar > .active > a:focus { 65 | color: #fff; 66 | background-color: #428bca; 67 | } 68 | 69 | 70 | /* 71 | * Main content 72 | */ 73 | 74 | .main { 75 | padding: 20px; 76 | } 77 | @media (min-width: 768px) { 78 | .main { 79 | padding-right: 40px; 80 | padding-left: 40px; 81 | } 82 | } 83 | .main .page-header { 84 | margin-top: 0; 85 | } 86 | 87 | 88 | /* 89 | * Placeholder dashboard ideas 90 | */ 91 | 92 | .placeholders { 93 | margin-bottom: 30px; 94 | text-align: center; 95 | } 96 | .placeholders h4 { 97 | margin-bottom: 0; 98 | } 99 | .placeholder { 100 | margin-bottom: 20px; 101 | } 102 | .placeholder img { 103 | display: inline-block; 104 | border-radius: 50%; 105 | } 106 | -------------------------------------------------------------------------------- /MyShow/static/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xianhu/LearnPython/0b2efbcd4c72fcbb78566b452f870d33a8d6ece6/MyShow/static/favicon.ico -------------------------------------------------------------------------------- /MyShow/static/js/bootstrap-typeahead.min.js: -------------------------------------------------------------------------------- 1 | (function(root,factory){"use strict";if(typeof module!=="undefined"&&module.exports){module.exports=factory(require("jquery"))}else if(typeof define==="function"&&define.amd){define(["jquery"],function($){return factory($)})}else{factory(root.jQuery)}})(this,function($){"use strict";var Typeahead=function(element,options){this.$element=$(element);this.options=$.extend({},$.fn.typeahead.defaults,options);this.matcher=this.options.matcher||this.matcher;this.sorter=this.options.sorter||this.sorter;this.select=this.options.select||this.select;this.autoSelect=typeof this.options.autoSelect=="boolean"?this.options.autoSelect:true;this.highlighter=this.options.highlighter||this.highlighter;this.render=this.options.render||this.render;this.updater=this.options.updater||this.updater;this.displayText=this.options.displayText||this.displayText;this.source=this.options.source;this.delay=this.options.delay;this.$menu=$(this.options.menu);this.$appendTo=this.options.appendTo?$(this.options.appendTo):null;this.fitToElement=typeof this.options.fitToElement=="boolean"?this.options.fitToElement:false;this.shown=false;this.listen();this.showHintOnFocus=typeof this.options.showHintOnFocus=="boolean"||this.options.showHintOnFocus==="all"?this.options.showHintOnFocus:false;this.afterSelect=this.options.afterSelect;this.addItem=false;this.value=this.$element.val()||this.$element.text()};Typeahead.prototype={constructor:Typeahead,select:function(){var val=this.$menu.find(".active").data("value");this.$element.data("active",val);if(this.autoSelect||val){var newVal=this.updater(val);if(!newVal){newVal=""}this.$element.val(this.displayText(newVal)||newVal).text(this.displayText(newVal)||newVal).change();this.afterSelect(newVal)}return this.hide()},updater:function(item){return item},setSource:function(source){this.source=source},show:function(){var pos=$.extend({},this.$element.position(),{height:this.$element[0].offsetHeight});var scrollHeight=typeof this.options.scrollHeight=="function"?this.options.scrollHeight.call():this.options.scrollHeight;var element;if(this.shown){element=this.$menu}else if(this.$appendTo){element=this.$menu.appendTo(this.$appendTo);this.hasSameParent=this.$appendTo.is(this.$element.parent())}else{element=this.$menu.insertAfter(this.$element);this.hasSameParent=true}if(!this.hasSameParent){element.css("position","fixed");var offset=this.$element.offset();pos.top=offset.top;pos.left=offset.left}var dropup=$(element).parent().hasClass("dropup");var newTop=dropup?"auto":pos.top+pos.height+scrollHeight;var right=$(element).hasClass("dropdown-menu-right");var newLeft=right?"auto":pos.left;element.css({top:newTop,left:newLeft}).show();if(this.options.fitToElement===true){element.css("width",this.$element.outerWidth()+"px")}this.shown=true;return this},hide:function(){this.$menu.hide();this.shown=false;return this},lookup:function(query){var items;if(typeof query!="undefined"&&query!==null){this.query=query}else{this.query=this.$element.val()||this.$element.text()||""}if(this.query.length0){this.$element.data("active",items[0])}else{this.$element.data("active",null)}if(this.options.addItem){items.push(this.options.addItem)}if(this.options.items=="all"){return this.render(items).show()}else{return this.render(items.slice(0,this.options.items)).show()}},matcher:function(item){var it=this.displayText(item);return~it.toLowerCase().indexOf(this.query.toLowerCase())},sorter:function(items){var beginswith=[];var caseSensitive=[];var caseInsensitive=[];var item;while(item=items.shift()){var it=this.displayText(item);if(!it.toLowerCase().indexOf(this.query.toLowerCase()))beginswith.push(item);else if(~it.indexOf(this.query))caseSensitive.push(item);else caseInsensitive.push(item)}return beginswith.concat(caseSensitive,caseInsensitive)},highlighter:function(item){var html=$("
");var query=this.query;var i=item.toLowerCase().indexOf(query.toLowerCase());var len=query.length;var leftPart;var middlePart;var rightPart;var strong;if(len===0){return html.text(item).html()}while(i>-1){leftPart=item.substr(0,i);middlePart=item.substr(i,len);rightPart=item.substr(i+len);strong=$("").text(middlePart);html.append(document.createTextNode(leftPart)).append(strong);item=rightPart;i=item.toLowerCase().indexOf(query.toLowerCase())}return html.append(document.createTextNode(item)).html()},render:function(items){var that=this;var self=this;var activeFound=false;var data=[];var _category=that.options.separator;$.each(items,function(key,value){if(key>0&&value[_category]!==items[key-1][_category]){data.push({__type:"divider"})}if(value[_category]&&(key===0||value[_category]!==items[key-1][_category])){data.push({__type:"category",name:value[_category]})}data.push(value)});items=$(data).map(function(i,item){if((item.__type||false)=="category"){return $(that.options.headerHtml).text(item.name)[0]}if((item.__type||false)=="divider"){return $(that.options.headerDivider)[0]}var text=self.displayText(item);i=$(that.options.item).data("value",item);i.find("a").html(that.highlighter(text,item));if(text==self.$element.val()){i.addClass("active");self.$element.data("active",item);activeFound=true}return i[0]});if(this.autoSelect&&!activeFound){items.filter(":not(.dropdown-header)").first().addClass("active");this.$element.data("active",items.first().data("value"))}this.$menu.html(items);return this},displayText:function(item){return typeof item!=="undefined"&&typeof item.name!="undefined"&&item.name||item},next:function(event){var active=this.$menu.find(".active").removeClass("active");var next=active.next();if(!next.length){next=$(this.$menu.find("li")[0])}next.addClass("active")},prev:function(event){var active=this.$menu.find(".active").removeClass("active");var prev=active.prev();if(!prev.length){prev=this.$menu.find("li").last()}prev.addClass("active")},listen:function(){this.$element.on("focus",$.proxy(this.focus,this)).on("blur",$.proxy(this.blur,this)).on("keypress",$.proxy(this.keypress,this)).on("input",$.proxy(this.input,this)).on("keyup",$.proxy(this.keyup,this));if(this.eventSupported("keydown")){this.$element.on("keydown",$.proxy(this.keydown,this))}this.$menu.on("click",$.proxy(this.click,this)).on("mouseenter","li",$.proxy(this.mouseenter,this)).on("mouseleave","li",$.proxy(this.mouseleave,this)).on("mousedown",$.proxy(this.mousedown,this))},destroy:function(){this.$element.data("typeahead",null);this.$element.data("active",null);this.$element.off("focus").off("blur").off("keypress").off("input").off("keyup");if(this.eventSupported("keydown")){this.$element.off("keydown")}this.$menu.remove();this.destroyed=true},eventSupported:function(eventName){var isSupported=eventName in this.$element;if(!isSupported){this.$element.setAttribute(eventName,"return;");isSupported=typeof this.$element[eventName]==="function"}return isSupported},move:function(e){if(!this.shown)return;switch(e.keyCode){case 9:case 13:case 27:e.preventDefault();break;case 38:if(e.shiftKey)return;e.preventDefault();this.prev();break;case 40:if(e.shiftKey)return;e.preventDefault();this.next();break}},keydown:function(e){this.suppressKeyPressRepeat=~$.inArray(e.keyCode,[40,38,9,13,27]);if(!this.shown&&e.keyCode==40){this.lookup()}else{this.move(e)}},keypress:function(e){if(this.suppressKeyPressRepeat)return;this.move(e)},input:function(e){var currentValue=this.$element.val()||this.$element.text();if(this.value!==currentValue){this.value=currentValue;this.lookup()}},keyup:function(e){if(this.destroyed){return}switch(e.keyCode){case 40:case 38:case 16:case 17:case 18:break;case 9:case 13:if(!this.shown)return;this.select();break;case 27:if(!this.shown)return;this.hide();break}},focus:function(e){if(!this.focused){this.focused=true;if(this.options.showHintOnFocus&&this.skipShowHintOnFocus!==true){if(this.options.showHintOnFocus==="all"){this.lookup("")}else{this.lookup()}}}if(this.skipShowHintOnFocus){this.skipShowHintOnFocus=false}},blur:function(e){if(!this.mousedover&&!this.mouseddown&&this.shown){this.hide();this.focused=false}else if(this.mouseddown){this.skipShowHintOnFocus=true;this.$element.focus();this.mouseddown=false}},click:function(e){e.preventDefault();this.skipShowHintOnFocus=true;this.select();this.$element.focus();this.hide()},mouseenter:function(e){this.mousedover=true;this.$menu.find(".active").removeClass("active");$(e.currentTarget).addClass("active")},mouseleave:function(e){this.mousedover=false;if(!this.focused&&this.shown)this.hide()},mousedown:function(e){this.mouseddown=true;this.$menu.one("mouseup",function(e){this.mouseddown=false}.bind(this))}};var old=$.fn.typeahead;$.fn.typeahead=function(option){var arg=arguments;if(typeof option=="string"&&option=="getActive"){return this.data("active")}return this.each(function(){var $this=$(this);var data=$this.data("typeahead");var options=typeof option=="object"&&option;if(!data)$this.data("typeahead",data=new Typeahead(this,options));if(typeof option=="string"&&data[option]){if(arg.length>1){data[option].apply(data,Array.prototype.slice.call(arg,1))}else{data[option]()}}})};$.fn.typeahead.defaults={source:[],items:8,menu:'',item:'
  • ',minLength:1,scrollHeight:0,autoSelect:true,afterSelect:$.noop,addItem:false,delay:0,separator:"category",headerHtml:'',headerDivider:''};$.fn.typeahead.Constructor=Typeahead;$.fn.typeahead.noConflict=function(){$.fn.typeahead=old;return this};$(document).on("focus.typeahead.data-api",'[data-provide="typeahead"]',function(e){var $this=$(this);if($this.data("typeahead"))return;$this.typeahead($this.data())})}); -------------------------------------------------------------------------------- /MyShow/templates/base.html: -------------------------------------------------------------------------------- 1 | {% extends "bootstrap/base.html" %} 2 | {% block title %}MyShow{% endblock %} 3 | 4 | {% block head %} 5 | {{ super() }} 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | {% endblock %} 20 | 21 | {% block navbar %} 22 | 53 | {% endblock %} 54 | 55 | {% block content %} 56 |
    57 | {% block page_content %} 58 | {% endblock %} 59 |
    60 | {% endblock %} 61 | -------------------------------------------------------------------------------- /MyShow/templates/error.html: -------------------------------------------------------------------------------- 1 | {% extends "base.html" %} 2 | {% block title %}数据展示 - Error{% endblock %} 3 | 4 | {% block page_content %} 5 | 8 | {% endblock %} 9 | -------------------------------------------------------------------------------- /MyShow/templates/index.html: -------------------------------------------------------------------------------- 1 | {% extends "base.html" %} 2 | {% import "bootstrap/wtf.html" as wtf %} 3 | 4 | {% block head %} 5 | {{ super() }} 6 | 7 | 123 | {% endblock %} 124 | 125 | {% block page_content %} 126 |
    127 | 137 | 138 |
    139 | {% for message in get_flashed_messages() %} 140 |
    141 | 142 | {{ message }} 143 |
    144 | {% endfor %} 145 | 146 | {% if page_type == "overview" %} 147 |

    数据展示,点击左边菜单栏即可查看各类数据展示页面

    148 | {% elif page_type == "zhihu_topics" %} 149 | 152 |
    153 | 154 | 157 | {% endif %} 158 |
    159 |
    160 | {% endblock %} 161 | 162 | {% block scripts %} 163 | 165 | {% endblock %} 166 | -------------------------------------------------------------------------------- /Plotly/box.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "code", 5 | "execution_count": 1, 6 | "metadata": {}, 7 | "outputs": [ 8 | { 9 | "data": { 10 | "text/html": [ 11 | "" 12 | ], 13 | "text/vnd.plotly.v1+html": [ 14 | "" 15 | ] 16 | }, 17 | "metadata": {}, 18 | "output_type": "display_data" 19 | } 20 | ], 21 | "source": [ 22 | "import plotly\n", 23 | "import plotly.graph_objs as go\n", 24 | "import numpy as np\n", 25 | "plotly.offline.init_notebook_mode(connected=True)" 26 | ] 27 | }, 28 | { 29 | "cell_type": "markdown", 30 | "metadata": {}, 31 | "source": [ 32 | "# Basic Box Plot" 33 | ] 34 | }, 35 | { 36 | "cell_type": "code", 37 | "execution_count": 4, 38 | "metadata": {}, 39 | "outputs": [ 40 | { 41 | "data": { 42 | "application/vnd.plotly.v1+json": { 43 | "config": { 44 | "linkText": "Export to plot.ly", 45 | "plotlyServerURL": "https://plot.ly", 46 | "showLink": true 47 | }, 48 | "data": [ 49 | { 50 | "type": "box", 51 | "uid": "56d15fca-a9ac-4293-9f60-f247d664da32", 52 | "y": [ 53 | 1.0339397830007564, 54 | -1.4173444497954462, 55 | -0.6070876057406958, 56 | 0.28268677288468336, 57 | -1.5247995332171327, 58 | -1.8096042168995483, 59 | -0.6324327777951443, 60 | -0.3375504795295271, 61 | -1.615444643209294, 62 | -1.5674650819767295, 63 | -0.05167273262967975, 64 | 0.19066384570549255, 65 | -1.716706131748142, 66 | -2.6027140027213758, 67 | -2.7794475093915536, 68 | -1.0633992118945768, 69 | -1.7823261860502488, 70 | -0.49946672554497173, 71 | -3.0936737830622305, 72 | 0.11338627420399461, 73 | -1.5084864248811527, 74 | 0.7952111254614838, 75 | 0.14366433638949627, 76 | -1.0423258223957919, 77 | 0.06827807146408005, 78 | 1.1460746777409496, 79 | -0.8644067404684217, 80 | -2.187499820565881, 81 | -3.5844198195229677, 82 | -1.110070847406223, 83 | -0.6254477641954751, 84 | 1.297319388114735, 85 | -1.8384686966445352, 86 | -3.38294071756488, 87 | -3.249810887030475, 88 | -0.5133500389078889, 89 | -1.3644311972648717, 90 | -0.34352939411764793, 91 | -1.096049284284127, 92 | -0.4234032523219948, 93 | -1.2448012738968122, 94 | -1.5306717174785198, 95 | -2.670833520363942, 96 | -0.7945802959699577, 97 | -0.023355698360847832, 98 | -1.5620178622977807, 99 | -0.5065841290662005, 100 | -2.8231129340715064, 101 | -0.6090574067098771, 102 | -1.4769710329084889 103 | ] 104 | }, 105 | { 106 | "type": "box", 107 | "uid": "1a6e9d58-281d-45ab-84df-c9ab8f8a917e", 108 | "y": [ 109 | 1.3047535901062441, 110 | -0.08379620656398479, 111 | -0.006647672426996154, 112 | 2.3911122302917227, 113 | -0.3791786796298735, 114 | -0.021640457566409532, 115 | 1.2973817897320743, 116 | 2.781549236492273, 117 | 0.3378772645254914, 118 | -0.41872691772447834, 119 | 1.2289098964222451, 120 | 2.201658847693984, 121 | -1.3074723357082343, 122 | 1.5629865643893859, 123 | 1.9384490712099702, 124 | 2.1108975568607686, 125 | 0.2284913591629938, 126 | 1.2323322857272831, 127 | 1.1582643638049248, 128 | 0.7525744906181078, 129 | 2.2393931875575928, 130 | 1.1496072213193245, 131 | 0.1773115144672449, 132 | 0.405371522304143, 133 | 0.9386835262917638, 134 | 2.5614977786358137, 135 | 1.1146056996297042, 136 | -1.0552001564407774, 137 | 1.9888130220488072, 138 | -0.30055451511689446, 139 | 1.6680284923489301, 140 | 0.33367132599842186, 141 | 0.47239992597044733, 142 | 0.8524558422291666, 143 | 1.0058898700280248, 144 | 2.153770399058179, 145 | 0.09425763050656244, 146 | -0.0611866187039527, 147 | 0.5582468709314331, 148 | 0.3923224996417254, 149 | -0.5102813277875677, 150 | 1.6358853947091139, 151 | 1.144888293061068, 152 | 1.1412587331494195, 153 | 2.1641816573609463, 154 | 1.6028173644888515, 155 | 0.30677342611139746, 156 | -0.2529723758098119, 157 | 2.0376838961028687, 158 | 1.851334012278981 159 | ] 160 | } 161 | ], 162 | "layout": {} 163 | }, 164 | "text/html": [ 165 | "
    " 166 | ], 167 | "text/vnd.plotly.v1+html": [ 168 | "
    " 169 | ] 170 | }, 171 | "metadata": {}, 172 | "output_type": "display_data" 173 | } 174 | ], 175 | "source": [ 176 | "_0 = np.random.randn(50)-1\n", 177 | "_1 = np.random.randn(50)+1\n", 178 | "\n", 179 | "# X轴\n", 180 | "# trace0 = go.Box(x=_0)\n", 181 | "# trace1 = go.Box(x=_1)\n", 182 | "\n", 183 | "# Y轴\n", 184 | "trace0 = go.Box(y=_0)\n", 185 | "trace1 = go.Box(y=_1)\n", 186 | "\n", 187 | "data = [trace0, trace1]\n", 188 | "plotly.offline.iplot(data)" 189 | ] 190 | }, 191 | { 192 | "cell_type": "markdown", 193 | "metadata": {}, 194 | "source": [ 195 | "# Grouped Box Plots" 196 | ] 197 | }, 198 | { 199 | "cell_type": "code", 200 | "execution_count": 5, 201 | "metadata": {}, 202 | "outputs": [ 203 | { 204 | "data": { 205 | "application/vnd.plotly.v1+json": { 206 | "config": { 207 | "linkText": "Export to plot.ly", 208 | "plotlyServerURL": "https://plot.ly", 209 | "showLink": true 210 | }, 211 | "data": [ 212 | { 213 | "marker": { 214 | "color": "#3D9970" 215 | }, 216 | "name": "kale", 217 | "type": "box", 218 | "uid": "56712f3e-4ad3-4bd3-8431-b303ef80e57e", 219 | "x": [ 220 | "day 1", 221 | "day 1", 222 | "day 1", 223 | "day 1", 224 | "day 1", 225 | "day 1", 226 | "day 2", 227 | "day 2", 228 | "day 2", 229 | "day 2", 230 | "day 2", 231 | "day 2" 232 | ], 233 | "y": [ 234 | 0.2, 235 | 0.2, 236 | 0.6, 237 | 1, 238 | 0.5, 239 | 0.4, 240 | 0.2, 241 | 0.7, 242 | 0.9, 243 | 0.1, 244 | 0.5, 245 | 0.3 246 | ] 247 | }, 248 | { 249 | "marker": { 250 | "color": "#FF4136" 251 | }, 252 | "name": "radishes", 253 | "type": "box", 254 | "uid": "8e0ad046-cd41-444e-a31d-38ac6e7aeb19", 255 | "x": [ 256 | "day 1", 257 | "day 1", 258 | "day 1", 259 | "day 1", 260 | "day 1", 261 | "day 1", 262 | "day 2", 263 | "day 2", 264 | "day 2", 265 | "day 2", 266 | "day 2", 267 | "day 2" 268 | ], 269 | "y": [ 270 | 0.6, 271 | 0.7, 272 | 0.3, 273 | 0.6, 274 | 0, 275 | 0.5, 276 | 0.7, 277 | 0.9, 278 | 0.5, 279 | 0.8, 280 | 0.7, 281 | 0.2 282 | ] 283 | }, 284 | { 285 | "marker": { 286 | "color": "#FF851B" 287 | }, 288 | "name": "carrots", 289 | "type": "box", 290 | "uid": "b1d35981-36a2-4683-81f3-9767fa9db745", 291 | "x": [ 292 | "day 1", 293 | "day 1", 294 | "day 1", 295 | "day 1", 296 | "day 1", 297 | "day 1", 298 | "day 2", 299 | "day 2", 300 | "day 2", 301 | "day 2", 302 | "day 2", 303 | "day 2" 304 | ], 305 | "y": [ 306 | 0.1, 307 | 0.3, 308 | 0.1, 309 | 0.9, 310 | 0.6, 311 | 0.6, 312 | 0.9, 313 | 1, 314 | 0.3, 315 | 0.6, 316 | 0.8, 317 | 0.5 318 | ] 319 | } 320 | ], 321 | "layout": { 322 | "boxmode": "group", 323 | "yaxis": { 324 | "title": "normalized moisture", 325 | "zeroline": false 326 | } 327 | } 328 | }, 329 | "text/html": [ 330 | "
    " 331 | ], 332 | "text/vnd.plotly.v1+html": [ 333 | "
    " 334 | ] 335 | }, 336 | "metadata": {}, 337 | "output_type": "display_data" 338 | } 339 | ], 340 | "source": [ 341 | "x = ['day 1', 'day 1', 'day 1', 'day 1', 'day 1', 'day 1', 'day 2', 'day 2', 'day 2', 'day 2', 'day 2', 'day 2']\n", 342 | "\n", 343 | "trace0 = go.Box(\n", 344 | " y=[0.2, 0.2, 0.6, 1.0, 0.5, 0.4, 0.2, 0.7, 0.9, 0.1, 0.5, 0.3],\n", 345 | " x=x,\n", 346 | " name='kale',\n", 347 | " marker=dict(color='#3D9970')\n", 348 | ")\n", 349 | "trace1 = go.Box(\n", 350 | " y=[0.6, 0.7, 0.3, 0.6, 0.0, 0.5, 0.7, 0.9, 0.5, 0.8, 0.7, 0.2],\n", 351 | " x=x,\n", 352 | " name='radishes',\n", 353 | " marker=dict(color='#FF4136')\n", 354 | ")\n", 355 | "trace2 = go.Box(\n", 356 | " y=[0.1, 0.3, 0.1, 0.9, 0.6, 0.6, 0.9, 1.0, 0.3, 0.6, 0.8, 0.5],\n", 357 | " x=x,\n", 358 | " name='carrots',\n", 359 | " marker=dict(color='#FF851B')\n", 360 | ")\n", 361 | "\n", 362 | "data = [trace0, trace1, trace2]\n", 363 | "layout = go.Layout(\n", 364 | " yaxis=dict(\n", 365 | " title='normalized moisture',\n", 366 | " zeroline=False\n", 367 | " ),\n", 368 | " boxmode='group'\n", 369 | ")\n", 370 | "fig = go.Figure(data=data, layout=layout)\n", 371 | "plotly.offline.iplot(fig)" 372 | ] 373 | } 374 | ], 375 | "metadata": { 376 | "kernelspec": { 377 | "display_name": "Python 3", 378 | "language": "python", 379 | "name": "python3" 380 | }, 381 | "language_info": { 382 | "codemirror_mode": { 383 | "name": "ipython", 384 | "version": 3 385 | }, 386 | "file_extension": ".py", 387 | "mimetype": "text/x-python", 388 | "name": "python", 389 | "nbconvert_exporter": "python", 390 | "pygments_lexer": "ipython3", 391 | "version": "3.6.5" 392 | } 393 | }, 394 | "nbformat": 4, 395 | "nbformat_minor": 2 396 | } 397 | -------------------------------------------------------------------------------- /Plotly/pie.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "code", 5 | "execution_count": 3, 6 | "metadata": {}, 7 | "outputs": [ 8 | { 9 | "data": { 10 | "text/html": [ 11 | "" 12 | ], 13 | "text/vnd.plotly.v1+html": [ 14 | "" 15 | ] 16 | }, 17 | "metadata": {}, 18 | "output_type": "display_data" 19 | } 20 | ], 21 | "source": [ 22 | "import plotly\n", 23 | "import plotly.graph_objs as go\n", 24 | "plotly.offline.init_notebook_mode(connected=True)" 25 | ] 26 | }, 27 | { 28 | "cell_type": "markdown", 29 | "metadata": {}, 30 | "source": [ 31 | "# Basic Pie Chart" 32 | ] 33 | }, 34 | { 35 | "cell_type": "code", 36 | "execution_count": 4, 37 | "metadata": {}, 38 | "outputs": [ 39 | { 40 | "data": { 41 | "application/vnd.plotly.v1+json": { 42 | "config": { 43 | "linkText": "Export to plot.ly", 44 | "plotlyServerURL": "https://plot.ly", 45 | "showLink": true 46 | }, 47 | "data": [ 48 | { 49 | "labels": [ 50 | "Oxygen", 51 | "Hydrogen", 52 | "Carbon_Dioxide", 53 | "Nitrogen" 54 | ], 55 | "type": "pie", 56 | "uid": "2e574503-a57d-4ea2-aa41-b770f8461ff6", 57 | "values": [ 58 | 4500, 59 | 2500, 60 | 1053, 61 | 500 62 | ] 63 | } 64 | ], 65 | "layout": {} 66 | }, 67 | "text/html": [ 68 | "
    " 69 | ], 70 | "text/vnd.plotly.v1+html": [ 71 | "
    " 72 | ] 73 | }, 74 | "metadata": {}, 75 | "output_type": "display_data" 76 | } 77 | ], 78 | "source": [ 79 | "labels = ['Oxygen','Hydrogen','Carbon_Dioxide','Nitrogen']\n", 80 | "values = [4500,2500,1053,500]\n", 81 | "\n", 82 | "trace = go.Pie(labels=labels, values=values)\n", 83 | "plotly.offline.iplot([trace], filename='basic_pie_chart')" 84 | ] 85 | }, 86 | { 87 | "cell_type": "markdown", 88 | "metadata": {}, 89 | "source": [ 90 | "# Styled Pie Chart" 91 | ] 92 | }, 93 | { 94 | "cell_type": "code", 95 | "execution_count": 5, 96 | "metadata": {}, 97 | "outputs": [ 98 | { 99 | "data": { 100 | "application/vnd.plotly.v1+json": { 101 | "config": { 102 | "linkText": "Export to plot.ly", 103 | "plotlyServerURL": "https://plot.ly", 104 | "showLink": true 105 | }, 106 | "data": [ 107 | { 108 | "hoverinfo": "label+percent", 109 | "labels": [ 110 | "Oxygen", 111 | "Hydrogen", 112 | "Carbon_Dioxide", 113 | "Nitrogen" 114 | ], 115 | "marker": { 116 | "colors": [ 117 | "#FEBFB3", 118 | "#E1396C", 119 | "#96D38C", 120 | "#D0F9B1" 121 | ], 122 | "line": { 123 | "color": "#000000", 124 | "width": 2 125 | } 126 | }, 127 | "textfont": { 128 | "size": 20 129 | }, 130 | "textinfo": "value", 131 | "type": "pie", 132 | "uid": "595b33b4-b572-44f5-9a18-99eeea5b0286", 133 | "values": [ 134 | 4500, 135 | 2500, 136 | 1053, 137 | 500 138 | ] 139 | } 140 | ], 141 | "layout": {} 142 | }, 143 | "text/html": [ 144 | "
    " 145 | ], 146 | "text/vnd.plotly.v1+html": [ 147 | "
    " 148 | ] 149 | }, 150 | "metadata": {}, 151 | "output_type": "display_data" 152 | } 153 | ], 154 | "source": [ 155 | "labels = ['Oxygen','Hydrogen','Carbon_Dioxide','Nitrogen']\n", 156 | "values = [4500,2500,1053,500]\n", 157 | "colors = ['#FEBFB3', '#E1396C', '#96D38C', '#D0F9B1']\n", 158 | "\n", 159 | "trace = go.Pie(\n", 160 | " labels=labels, values=values,\n", 161 | " hoverinfo='label+percent', \n", 162 | " textinfo='value', \n", 163 | " textfont=dict(size=20),\n", 164 | " marker=dict(\n", 165 | " colors=colors, \n", 166 | " line=dict(color='#000000', width=2)\n", 167 | " )\n", 168 | ")\n", 169 | "plotly.offline.iplot([trace], filename='styled_pie_chart')" 170 | ] 171 | }, 172 | { 173 | "cell_type": "markdown", 174 | "metadata": {}, 175 | "source": [ 176 | "# Donut Chart" 177 | ] 178 | }, 179 | { 180 | "cell_type": "code", 181 | "execution_count": 14, 182 | "metadata": {}, 183 | "outputs": [ 184 | { 185 | "data": { 186 | "application/vnd.plotly.v1+json": { 187 | "config": { 188 | "linkText": "Export to plot.ly", 189 | "plotlyServerURL": "https://plot.ly", 190 | "showLink": true 191 | }, 192 | "data": [ 193 | { 194 | "domain": { 195 | "x": [ 196 | 0, 197 | 0.48 198 | ], 199 | "y": [ 200 | 0, 201 | 1 202 | ] 203 | }, 204 | "hole": 0.4, 205 | "hoverinfo": "label+percent+name", 206 | "labels": [ 207 | "US", 208 | "China", 209 | "European Union", 210 | "Russian Federation", 211 | "Brazil", 212 | "India", 213 | "Rest of World" 214 | ], 215 | "name": "GHG Emissions", 216 | "type": "pie", 217 | "uid": "32fa5d30-977f-4fa3-bec9-30b7cdd52d19", 218 | "values": [ 219 | 16, 220 | 15, 221 | 12, 222 | 6, 223 | 5, 224 | 4, 225 | 42 226 | ] 227 | }, 228 | { 229 | "domain": { 230 | "x": [ 231 | 0.52, 232 | 1 233 | ], 234 | "y": [ 235 | 0, 236 | 1 237 | ] 238 | }, 239 | "hole": 0.4, 240 | "hoverinfo": "label+percent+name", 241 | "labels": [ 242 | "US", 243 | "China", 244 | "European Union", 245 | "Russian Federation", 246 | "Brazil", 247 | "India", 248 | "Rest of World" 249 | ], 250 | "name": "CO2 Emissions", 251 | "text": [ 252 | "CO2", 253 | "CO2", 254 | "CO2", 255 | "CO2", 256 | "CO2", 257 | "CO2", 258 | "CO2" 259 | ], 260 | "textposition": "inside", 261 | "type": "pie", 262 | "uid": "e7b3bdb8-1c4e-4aec-a46b-e836aa8747cc", 263 | "values": [ 264 | 27, 265 | 11, 266 | 25, 267 | 8, 268 | 1, 269 | 3, 270 | 25 271 | ] 272 | } 273 | ], 274 | "layout": { 275 | "annotations": [ 276 | { 277 | "font": { 278 | "size": 20 279 | }, 280 | "showarrow": false, 281 | "text": "GHG", 282 | "x": 0.2, 283 | "y": 0.5 284 | }, 285 | { 286 | "font": { 287 | "size": 20 288 | }, 289 | "showarrow": false, 290 | "text": "CO2", 291 | "x": 0.8, 292 | "y": 0.5 293 | } 294 | ], 295 | "title": "Global Emissions 1990-2011" 296 | } 297 | }, 298 | "text/html": [ 299 | "
    " 300 | ], 301 | "text/vnd.plotly.v1+html": [ 302 | "
    " 303 | ] 304 | }, 305 | "metadata": {}, 306 | "output_type": "display_data" 307 | } 308 | ], 309 | "source": [ 310 | "# 使用字典形式\n", 311 | "fig = {\n", 312 | " \"data\": [\n", 313 | " {\n", 314 | " \"values\": [16, 15, 12, 6, 5, 4, 42],\n", 315 | " \"labels\": [\"US\", \"China\", \"European Union\", \"Russian Federation\", \"Brazil\", \"India\", \"Rest of World\"],\n", 316 | " # 设置显示区域占左半部分\n", 317 | " \"domain\": {\n", 318 | " \"x\": [0, .48],\n", 319 | " \"y\": [0, 1],\n", 320 | " },\n", 321 | " \"name\": \"GHG Emissions\",\n", 322 | " \"hoverinfo\":\"label+percent+name\",\n", 323 | " # 设置空心的大小\n", 324 | " \"hole\": .4,\n", 325 | " \"type\": \"pie\"\n", 326 | " },\n", 327 | " {\n", 328 | " \"values\": [27, 11, 25, 8, 1, 3, 25],\n", 329 | " \"labels\": [\"US\", \"China\", \"European Union\", \"Russian Federation\", \"Brazil\", \"India\", \"Rest of World\"],\n", 330 | " \"text\":[\"CO2\"] * 7,\n", 331 | " \"textposition\":\"inside\",\n", 332 | " # 设置显示区域占右半部分\n", 333 | " \"domain\": {\n", 334 | " \"x\": [.52, 1],\n", 335 | " \"y\": [0, 1],\n", 336 | " },\n", 337 | " \"name\": \"CO2 Emissions\",\n", 338 | " \"hoverinfo\":\"label+percent+name\",\n", 339 | " # 设置空心的大小\n", 340 | " \"hole\": .4,\n", 341 | " \"type\": \"pie\"\n", 342 | " }\n", 343 | " ],\n", 344 | " \"layout\": {\n", 345 | " \"title\":\"Global Emissions 1990-2011\",\n", 346 | " \"annotations\": [\n", 347 | " {\n", 348 | " \"font\": {\"size\": 20},\n", 349 | " \"showarrow\": False,\n", 350 | " \"text\": \"GHG\",\n", 351 | " \"x\": 0.20,\n", 352 | " \"y\": 0.5\n", 353 | " },\n", 354 | " {\n", 355 | " \"font\": {\"size\": 20},\n", 356 | " \"showarrow\": False,\n", 357 | " \"text\": \"CO2\",\n", 358 | " \"x\": 0.8,\n", 359 | " \"y\": 0.5\n", 360 | " }\n", 361 | " ]\n", 362 | " }\n", 363 | "}\n", 364 | "plotly.offline.iplot(fig, filename='donut')" 365 | ] 366 | } 367 | ], 368 | "metadata": { 369 | "kernelspec": { 370 | "display_name": "Python 3", 371 | "language": "python", 372 | "name": "python3" 373 | }, 374 | "language_info": { 375 | "codemirror_mode": { 376 | "name": "ipython", 377 | "version": 3 378 | }, 379 | "file_extension": ".py", 380 | "mimetype": "text/x-python", 381 | "name": "python", 382 | "nbconvert_exporter": "python", 383 | "pygments_lexer": "ipython3", 384 | "version": "3.6.5" 385 | } 386 | }, 387 | "nbformat": 4, 388 | "nbformat_minor": 2 389 | } 390 | -------------------------------------------------------------------------------- /Plotly/radar.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "code", 5 | "execution_count": 2, 6 | "metadata": {}, 7 | "outputs": [ 8 | { 9 | "data": { 10 | "text/html": [ 11 | "" 12 | ], 13 | "text/vnd.plotly.v1+html": [ 14 | "" 15 | ] 16 | }, 17 | "metadata": {}, 18 | "output_type": "display_data" 19 | } 20 | ], 21 | "source": [ 22 | "import plotly\n", 23 | "import plotly.graph_objs as go\n", 24 | "plotly.offline.init_notebook_mode(connected=True)" 25 | ] 26 | }, 27 | { 28 | "cell_type": "markdown", 29 | "metadata": {}, 30 | "source": [ 31 | "# Basic Radar Chart" 32 | ] 33 | }, 34 | { 35 | "cell_type": "code", 36 | "execution_count": 3, 37 | "metadata": {}, 38 | "outputs": [ 39 | { 40 | "data": { 41 | "application/vnd.plotly.v1+json": { 42 | "config": { 43 | "linkText": "Export to plot.ly", 44 | "plotlyServerURL": "https://plot.ly", 45 | "showLink": true 46 | }, 47 | "data": [ 48 | { 49 | "fill": "toself", 50 | "name": "Group A", 51 | "r": [ 52 | 39, 53 | 28, 54 | 8, 55 | 7, 56 | 28, 57 | 39 58 | ], 59 | "theta": [ 60 | "A", 61 | "B", 62 | "C", 63 | "D", 64 | "E", 65 | "A" 66 | ], 67 | "type": "scatterpolar", 68 | "uid": "c020ecab-86d1-431d-b944-21e3ac8fd0a3" 69 | }, 70 | { 71 | "fill": "toself", 72 | "name": "Group B", 73 | "r": [ 74 | 1.5, 75 | 10, 76 | 39, 77 | 31, 78 | 15, 79 | 1.5 80 | ], 81 | "theta": [ 82 | "A", 83 | "B", 84 | "C", 85 | "D", 86 | "E", 87 | "A" 88 | ], 89 | "type": "scatterpolar", 90 | "uid": "7a262f24-0679-474e-b6d1-21ef9c9130ac" 91 | } 92 | ], 93 | "layout": { 94 | "polar": { 95 | "radialaxis": { 96 | "range": [ 97 | 0, 98 | 50 99 | ], 100 | "visible": true 101 | } 102 | }, 103 | "showlegend": false 104 | } 105 | }, 106 | "text/html": [ 107 | "
    " 108 | ], 109 | "text/vnd.plotly.v1+html": [ 110 | "
    " 111 | ] 112 | }, 113 | "metadata": {}, 114 | "output_type": "display_data" 115 | } 116 | ], 117 | "source": [ 118 | "data = [\n", 119 | " go.Scatterpolar(\n", 120 | " r = [39, 28, 8, 7, 28, 39],\n", 121 | " theta = ['A','B','C', 'D', 'E', 'A'],\n", 122 | " fill = 'toself',\n", 123 | " name = 'Group A'\n", 124 | " ),\n", 125 | " go.Scatterpolar(\n", 126 | " r = [1.5, 10, 39, 31, 15, 1.5],\n", 127 | " theta = ['A','B','C', 'D', 'E', 'A'],\n", 128 | " fill = 'toself',\n", 129 | " name = 'Group B'\n", 130 | " )\n", 131 | "]\n", 132 | "\n", 133 | "layout = go.Layout(\n", 134 | " polar = dict(\n", 135 | " radialaxis = dict(\n", 136 | " visible = True,\n", 137 | " range = [0, 50]\n", 138 | " )\n", 139 | " ),\n", 140 | " showlegend = False\n", 141 | ")\n", 142 | "fig = go.Figure(data=data, layout=layout)\n", 143 | "plotly.offline.iplot(fig, filename = \"radar\")" 144 | ] 145 | } 146 | ], 147 | "metadata": { 148 | "kernelspec": { 149 | "display_name": "Python 3", 150 | "language": "python", 151 | "name": "python3" 152 | }, 153 | "language_info": { 154 | "codemirror_mode": { 155 | "name": "ipython", 156 | "version": 3 157 | }, 158 | "file_extension": ".py", 159 | "mimetype": "text/x-python", 160 | "name": "python", 161 | "nbconvert_exporter": "python", 162 | "pygments_lexer": "ipython3", 163 | "version": "3.6.5" 164 | } 165 | }, 166 | "nbformat": 4, 167 | "nbformat_minor": 2 168 | } 169 | -------------------------------------------------------------------------------- /Plotly/sankey.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "code", 5 | "execution_count": 1, 6 | "metadata": {}, 7 | "outputs": [ 8 | { 9 | "data": { 10 | "text/html": [ 11 | "" 12 | ], 13 | "text/vnd.plotly.v1+html": [ 14 | "" 15 | ] 16 | }, 17 | "metadata": {}, 18 | "output_type": "display_data" 19 | } 20 | ], 21 | "source": [ 22 | "import plotly\n", 23 | "plotly.offline.init_notebook_mode(connected=True)" 24 | ] 25 | }, 26 | { 27 | "cell_type": "markdown", 28 | "metadata": {}, 29 | "source": [ 30 | "# Basic Sankey Chart" 31 | ] 32 | }, 33 | { 34 | "cell_type": "code", 35 | "execution_count": 6, 36 | "metadata": {}, 37 | "outputs": [ 38 | { 39 | "data": { 40 | "application/vnd.plotly.v1+json": { 41 | "config": { 42 | "linkText": "Export to plot.ly", 43 | "plotlyServerURL": "https://plot.ly", 44 | "showLink": true 45 | }, 46 | "data": [ 47 | { 48 | "link": { 49 | "source": [ 50 | 0, 51 | 0, 52 | 1, 53 | 2, 54 | 3, 55 | 3 56 | ], 57 | "target": [ 58 | 2, 59 | 3, 60 | 3, 61 | 4, 62 | 4, 63 | 5 64 | ], 65 | "value": [ 66 | 8, 67 | 4, 68 | 2, 69 | 8, 70 | 4, 71 | 2 72 | ] 73 | }, 74 | "node": { 75 | "color": [ 76 | "#e03636", 77 | "#edd08e", 78 | "#ff534d", 79 | "#23d58e", 80 | "#25c6fc", 81 | "#0000ff" 82 | ], 83 | "label": [ 84 | "A1", 85 | "A2", 86 | "B1", 87 | "B2", 88 | "C1", 89 | "C2" 90 | ], 91 | "line": { 92 | "color": "black", 93 | "width": 1 94 | }, 95 | "thickness": 20 96 | }, 97 | "type": "sankey" 98 | } 99 | ], 100 | "layout": { 101 | "font": { 102 | "size": 20 103 | }, 104 | "title": "基础桑吉图" 105 | } 106 | }, 107 | "text/html": [ 108 | "
    " 109 | ], 110 | "text/vnd.plotly.v1+html": [ 111 | "
    " 112 | ] 113 | }, 114 | "metadata": {}, 115 | "output_type": "display_data" 116 | } 117 | ], 118 | "source": [ 119 | "data = dict(\n", 120 | " type = 'sankey',\n", 121 | " # 设置每个柱状条的颜色,宽度,边框等信息\n", 122 | " node = dict(\n", 123 | " thickness = 20,\n", 124 | " line = dict(color = \"black\", width = 1),\n", 125 | " label = [\"A1\", \"A2\", \"B1\", \"B2\", \"C1\", \"C2\"],\n", 126 | " color = [\"#e03636\", \"#edd08e\", \"#ff534d\", \"#23d58e\", \"#25c6fc\", \"#0000ff\"]\n", 127 | " ),\n", 128 | " # 设置能量流动条的宽度值\n", 129 | " link = dict(\n", 130 | " source = [0, 0, 1, 2, 3, 3],\n", 131 | " target = [2, 3, 3, 4, 4, 5],\n", 132 | " value = [8, 4, 2, 8, 4, 2]\n", 133 | " )\n", 134 | ")\n", 135 | "\n", 136 | "layout = dict(\n", 137 | " title = \"基础桑吉图\",\n", 138 | " font = dict(size = 20)\n", 139 | ")\n", 140 | "fig = dict(data=[data], layout=layout)\n", 141 | "plotly.offline.iplot(fig, validate=False)" 142 | ] 143 | }, 144 | { 145 | "cell_type": "markdown", 146 | "metadata": {}, 147 | "source": [ 148 | "# Advance Sankey Chart" 149 | ] 150 | }, 151 | { 152 | "cell_type": "code", 153 | "execution_count": 5, 154 | "metadata": {}, 155 | "outputs": [ 156 | { 157 | "data": { 158 | "application/vnd.plotly.v1+json": { 159 | "config": { 160 | "linkText": "Export to plot.ly", 161 | "plotlyServerURL": "https://plot.ly", 162 | "showLink": true 163 | }, 164 | "data": [ 165 | { 166 | "link": { 167 | "source": [ 168 | 0, 169 | 0, 170 | 1, 171 | 1, 172 | 2, 173 | 2, 174 | 3, 175 | 3, 176 | 4, 177 | 4, 178 | 6, 179 | 6, 180 | 6, 181 | 6, 182 | 5, 183 | 5, 184 | 5, 185 | 5 186 | ], 187 | "target": [ 188 | 5, 189 | 6, 190 | 5, 191 | 6, 192 | 5, 193 | 6, 194 | 5, 195 | 6, 196 | 5, 197 | 6, 198 | 7, 199 | 8, 200 | 9, 201 | 10, 202 | 7, 203 | 8, 204 | 9, 205 | 10 206 | ], 207 | "value": [ 208 | 5, 209 | 25, 210 | 6, 211 | 25, 212 | 4, 213 | 40, 214 | 7, 215 | 42, 216 | 6, 217 | 40, 218 | 62, 219 | 37, 220 | 70, 221 | 3, 222 | 5, 223 | 15, 224 | 7, 225 | 1 226 | ] 227 | }, 228 | "node": { 229 | "label": [ 230 | "专业A", 231 | "专业B", 232 | "专业C", 233 | "专业D", 234 | "专业E", 235 | "转到其他学院", 236 | "留在本学院", 237 | "国内升学", 238 | "国外深造", 239 | "直接就业", 240 | "待就业" 241 | ], 242 | "line": { 243 | "color": "black", 244 | "width": 0.5 245 | }, 246 | "pad": 15, 247 | "thickness": 15 248 | }, 249 | "type": "sankey" 250 | } 251 | ], 252 | "layout": { 253 | "font": { 254 | "color": "black", 255 | "size": 15 256 | }, 257 | "title": "学院学生转专业统计 & 毕业去向统计" 258 | } 259 | }, 260 | "text/html": [ 261 | "
    " 262 | ], 263 | "text/vnd.plotly.v1+html": [ 264 | "
    " 265 | ] 266 | }, 267 | "metadata": {}, 268 | "output_type": "display_data" 269 | } 270 | ], 271 | "source": [ 272 | "data_trace = dict(\n", 273 | " type = 'sankey',\n", 274 | " node = dict(\n", 275 | " pad = 15,\n", 276 | " thickness = 15,\n", 277 | " line = dict(color = \"black\", width = 0.5),\n", 278 | " label = [\"专业A\", \"专业B\", \"专业C\", \"专业D\", \"专业E\", \"转到其他学院\",\"留在本学院\",\"国内升学\",\"国外深造\",\"直接就业\",\"待就业\"]\n", 279 | " ),\n", 280 | " link = dict(\n", 281 | " source = [0,0,1,1,2,2,3,3,4,4,6,6,6,6,5,5,5,5],\n", 282 | " target = [5,6,5,6,5,6,5,6,5,6,7,8,9,10,7,8,9,10],\n", 283 | " value = [5,25,6,25,4,40,7,42,6,40,62,37,70,3,5,15,7,1]\n", 284 | " )\n", 285 | ")\n", 286 | "\n", 287 | "layout = dict(\n", 288 | " title = \"学院学生转专业统计 & 毕业去向统计\",\n", 289 | " font = dict(\n", 290 | " size = 15,\n", 291 | " color = 'black'\n", 292 | " ),\n", 293 | " # 修改视图背景色\n", 294 | " # plot_bgcolor = 'black',\n", 295 | " # paper_bgcolor = 'black'\n", 296 | ")\n", 297 | "fig = dict(data=[data_trace], layout=layout)\n", 298 | "plotly.offline.iplot(fig, validate=False)" 299 | ] 300 | } 301 | ], 302 | "metadata": { 303 | "kernelspec": { 304 | "display_name": "Python 3", 305 | "language": "python", 306 | "name": "python3" 307 | }, 308 | "language_info": { 309 | "codemirror_mode": { 310 | "name": "ipython", 311 | "version": 3 312 | }, 313 | "file_extension": ".py", 314 | "mimetype": "text/x-python", 315 | "name": "python", 316 | "nbconvert_exporter": "python", 317 | "pygments_lexer": "ipython3", 318 | "version": "3.6.5" 319 | } 320 | }, 321 | "nbformat": 4, 322 | "nbformat_minor": 2 323 | } 324 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # LearnPython 2 | 以撸代码的形式学习Python, 具体说明在[知乎专栏-撸代码,学知识](https://zhuanlan.zhihu.com/pythoner) 3 | 4 | =================================================================================================== 5 | ### python_base.py: 千行代码入门Python 6 | 7 | ### python_visual.py: 15张图入门Matplotlib 8 | 9 | ### python_visual_animation.py: 使用Matplotlib画动态图实例 10 | 11 | ### python_spider.py: 一个很“水”的Python爬虫入门代码文件 12 | 13 | ### python_weibo.py: “史上最详细”的Python模拟登录新浪微博流程 14 | 15 | ### python_lda.py: 玩点高级的--带你入门Topic模型LDA(小改进+附源码) 16 | 17 | ### python_sqlalchemy.py: 作为一个Pythoner, 不会SQLAlchemy都不好意思跟同行打招呼! 18 | 19 | ### python_oneline.py: 几个小例子告诉你, 一行Python代码能干哪些事 20 | 21 | ### python_requests.py: Python中最好用的爬虫库Requests代码实例 22 | 23 | ### python_functional.py: Python进阶: 函数式编程实例(附代码) 24 | 25 | ### python_decorator.py: Python进阶: 通过实例详解装饰器(附代码) 26 | 27 | ### python_datetime.py: 你真的了解Python中的日期时间处理吗? 28 | 29 | ### python_metaclass.py: Python进阶: 一步步理解Python中的元类metaclass 30 | 31 | ### python_coroutine.py: Python进阶: 理解Python中的异步IO和协程(Coroutine), 并应用在爬虫中 32 | 33 | ### python_aiohttp.py: Python中最好用的异步爬虫库Aiohttp代码实例 34 | 35 | ### python_thread_multiprocess.py: Python进阶: 聊聊IO密集型任务、计算密集型任务,以及多线程、多进程 36 | 37 | ### python_version36.py: Python3.6正式版要来了, 你期待哪些新特性? 38 | 39 | ### python_magic_methods: Python进阶: 实例讲解Python中的魔法函数(Magic Methods) 40 | 41 | ### python_restful_api.py: 利用Python和Flask快速开发RESTful API 42 | 43 | ### python_restful_api.py: RESTful API进阶: 连接数据库、添加参数、Token认证、返回代码说明等 44 | 45 | ### python_context.py: With语句和上下文管理器ContextManager 46 | 47 | ### python_flask.py: Flask相关说明 48 | 49 | ### MyShow: 玩点好玩的--知乎全部话题关系可视化 50 | 51 | ### python_markov_chain.py: 玩点好玩的--使用马尔可夫模型自动生成文章 52 | 53 | ### python_wechat.py: 玩点好玩的--自己写一个微信小助手 54 | 55 | ### python_csv.py: Python中CSV文件的简单读写 56 | 57 | ### python_numpy.py: 使用numpy进行矩阵操作 58 | 59 | ### python_mail.py: 使用Python自动发送邮件,包括发送HTML以及图片、附件等 60 | 61 | ### python_redis.py: Python操作Redis实现消息的发布与订阅 62 | 63 | ### python_schedule.py: Python进行调度开发 64 | 65 | ### python_socket.py: Python的socket开发实例 66 | 67 | ### python_re.py:Python的re模块的主要功能以及如何使用它们进行字符串匹配和替换 68 | 69 | ### Plotly目录: 一些plotly画图的实例,使用jupyter notebook编写 70 | 71 | =================================================================================================== 72 | 73 | ### 您可以fork该项目, 并在修改后提交Pull request, 看到后会尽量进行代码合并 74 | -------------------------------------------------------------------------------- /python_aiohttp.py: -------------------------------------------------------------------------------- 1 | # _*_ coding: utf-8 _*_ 2 | 3 | """ 4 | python_aiohttp.py by xianhu 5 | """ 6 | 7 | import asyncio 8 | import aiohttp 9 | 10 | 11 | # 简单实例 12 | async def aiohttp_test01(url): 13 | async with aiohttp.ClientSession() as session: 14 | async with session.get(url) as resp: 15 | print(resp.status) 16 | print(await resp.text()) 17 | 18 | loop = asyncio.get_event_loop() 19 | tasks = [aiohttp_test01("https://api.github.com/events")] 20 | loop.run_until_complete(asyncio.wait(tasks)) 21 | loop.close() 22 | 23 | # 其他Http方法 24 | # session.post('http://httpbin.org/post', data=b'data') 25 | # session.put('http://httpbin.org/put', data=b'data') 26 | # session.delete('http://httpbin.org/delete') 27 | # session.head('http://httpbin.org/get') 28 | # session.options('http://httpbin.org/get') 29 | # session.patch('http://httpbin.org/patch', data=b'data') 30 | 31 | # 自定义Headers 32 | # payload = {'some': 'data'} 33 | # headers = {'content-type': 'application/json'} 34 | # await session.post(url, data=json.dumps(payload), headers=headers) 35 | 36 | # 自定义Cookie 37 | # cookies = {'cookies_are': 'working'} 38 | # async with ClientSession(cookies=cookies) as session: 39 | # 访问Cookie: session.cookie_jar 40 | 41 | # 在URLs中传递参数 42 | # 1. params = {'key1': 'value1', 'key2': 'value2'} 43 | # 2. params = [('key', 'value1'), ('key', 'value2')] 44 | # async with session.get('http://httpbin.org/get', params=params) as resp: 45 | # assert resp.url == 'http://httpbin.org/get?key2=value2&key1=value1' 46 | 47 | # 发送数据 48 | # payload = {'key1': 'value1', 'key2': 'value2'} 49 | # async with session.post('http://httpbin.org/post', data=payload) as resp: 50 | # async with session.post(url, data=json.dumps(payload)) as resp: 51 | # print(await resp.text()) 52 | 53 | # 发送文件(1) 54 | # files = {'file': open('report.xls', 'rb')} 55 | # await session.post(url, data=files) 56 | 57 | # 发送数据(2) 58 | # data = FormData() 59 | # data.add_field('file', 60 | # open('report.xls', 'rb'), 61 | # filename='report.xls', 62 | # content_type='application/vnd.ms-excel') 63 | # await session.post(url, data=data) 64 | 65 | # 超时设置 66 | # aync with session.get('https://github.com', timeout=60) as r: 67 | 68 | # 代理支持 69 | # async with aiohttp.ClientSession() as session: 70 | # async with session.get("http://python.org", proxy="http://some.proxy.com") as resp: 71 | # print(resp.status) 72 | 73 | # async with aiohttp.ClientSession() as session: 74 | # proxy_auth = aiohttp.BasicAuth('user', 'pass') 75 | # async with session.get("http://python.org", proxy="http://some.proxy.com", proxy_auth=proxy_auth) as resp: 76 | # print(resp.status) 77 | # session.get("http://python.org", proxy="http://user:pass@some.proxy.com") 78 | 79 | # 返回的内容 80 | # async with session.get('https://api.github.com/events') as resp: 81 | # print(await resp.text()) 82 | # print(await resp.text(encoding='gbk')) 83 | # print(await resp.read()) 84 | # print(await resp.json()) 85 | 86 | # 返回内容较大 87 | # with open(filename, 'wb') as fd: 88 | # while True: 89 | # chunk = await resp.content.read(chunk_size) 90 | # if not chunk: 91 | # break 92 | # fd.write(chunk) 93 | 94 | # 返回的其他变量 95 | # async with session.get('http://httpbin.org/get') as resp: 96 | # print(resp.status) # 状态码 97 | # print(resp.headers) # Headers 98 | # print(resp.raw_headers) # 原始Headers 99 | # print(resp.cookies) # 返回的Cookie 100 | 101 | # 访问历史History 102 | # resp = await session.get('http://example.com/some/redirect/') 103 | # resp: 104 | # resp.history: (,) 105 | 106 | # 释放返回的Response 107 | # 1. async with session.get(url) as resp: pass 108 | # 2. await resp.release() 109 | 110 | # 连接器: Connectors 111 | # conn = aiohttp.TCPConnector() 112 | # session = aiohttp.ClientSession(connector=conn) 113 | 114 | # 限制连接池大小: 115 | # conn = aiohttp.TCPConnector(limit=30) 116 | # conn = aiohttp.TCPConnector(limit=None) 117 | -------------------------------------------------------------------------------- /python_celery.py: -------------------------------------------------------------------------------- 1 | # _*_ coding: utf-8 _*_ 2 | 3 | """ 4 | 测试celery 5 | 终端运行:celery -A python_celery:app worker -l INFO 6 | """ 7 | 8 | import time 9 | 10 | from celery import Celery 11 | 12 | broker = "redis://localhost:6379/10" # 用redis做broker,中间件 13 | backend = "redis://localhost:6379/11" # 用redis做broken,用来保存结果 14 | 15 | app = Celery("tasks", broker=broker, backend=backend) 16 | 17 | 18 | @app.task 19 | def add(x, y): 20 | print(time.time(), x, y) 21 | time.sleep(3) 22 | print(time.time(), x, y, "--") 23 | return x + y 24 | -------------------------------------------------------------------------------- /python_celery_test.py: -------------------------------------------------------------------------------- 1 | # _*_ coding: utf-8 _*_ 2 | 3 | """ 4 | 测试 5 | """ 6 | 7 | import time 8 | 9 | from python_celery import add 10 | 11 | if __name__ == "__main__": 12 | result = [] 13 | for i in range(10): 14 | result.append(add.delay(i, i)) 15 | print("----", time.time()) 16 | for index, item in enumerate(result): 17 | print(index, item.get()) 18 | print("----", time.time()) 19 | -------------------------------------------------------------------------------- /python_context.py: -------------------------------------------------------------------------------- 1 | # _*_ coding: utf-8 _*_ 2 | 3 | """ 4 | python_context.py by xianhu 5 | """ 6 | 7 | import contextlib 8 | 9 | 10 | # 自定义打开文件操作 11 | class MyOpen(object): 12 | 13 | def __init__(self, file_name): 14 | """初始化方法""" 15 | self.file_name = file_name 16 | self.file_handler = None 17 | return 18 | 19 | def __enter__(self): 20 | """enter方法,返回file_handler""" 21 | print("enter:", self.file_name) 22 | self.file_handler = open(self.file_name, "r") 23 | return self.file_handler 24 | 25 | def __exit__(self, exc_type, exc_val, exc_tb): 26 | """exit方法,关闭文件并返回True""" 27 | print("exit:", exc_type, exc_val, exc_tb) 28 | if self.file_handler: 29 | self.file_handler.close() 30 | return True 31 | 32 | # 使用实例 33 | with MyOpen("python_base.py") as file_in: 34 | for line in file_in: 35 | print(line) 36 | raise ZeroDivisionError 37 | # 代码块中主动引发一个除零异常,但整个程序不会引发异常 38 | 39 | 40 | # 内置库contextlib的使用 41 | @contextlib.contextmanager 42 | def open_func(file_name): 43 | # __enter__方法 44 | print("open file:", file_name, "in __enter__") 45 | file_handler = open(file_name, "r") 46 | 47 | yield file_handler 48 | 49 | # __exit__方法 50 | print("close file:", file_name, "in __exit__") 51 | file_handler.close() 52 | return 53 | 54 | # 使用实例 55 | with open_func("python_base.py") as file_in: 56 | for line in file_in: 57 | print(line) 58 | break 59 | 60 | 61 | # 内置库contextlib的使用 62 | class MyOpen2(object): 63 | 64 | def __init__(self, file_name): 65 | """初始化方法""" 66 | self.file_handler = open(file_name, "r") 67 | return 68 | 69 | def close(self): 70 | """关闭文件,会被自动调用""" 71 | print("call close in MyOpen2") 72 | if self.file_handler: 73 | self.file_handler.close() 74 | return 75 | 76 | # 使用实例 77 | with contextlib.closing(MyOpen2("python_base.py")) as file_in: 78 | pass 79 | -------------------------------------------------------------------------------- /python_coroutine.py: -------------------------------------------------------------------------------- 1 | # _*_ coding: utf-8 _*_ 2 | 3 | """ 4 | python_coroutine.py by xianhu 5 | """ 6 | 7 | import asyncio 8 | import aiohttp 9 | import threading 10 | 11 | 12 | # 生产者、消费者例子 13 | def consumer(): # 定义消费者,由于有yeild关键词,此消费者为一个生成器 14 | print("[Consumer] Init Consumer ......") 15 | r = "init ok" # 初始化返回结果,并在启动消费者时,返回给生产者 16 | while True: 17 | n = yield r # 消费者通过yield关键词接收生产者产生的消息,同时返回结果给生产者 18 | print("[Consumer] conusme n = %s, r = %s" % (n, r)) 19 | r = "consume %s OK" % n # 消费者消费结果,下个循环返回给生产者 20 | 21 | 22 | def produce(c): # 定义生产者,此时的 c 为一个生成器 23 | print("[Producer] Init Producer ......") 24 | r = c.send(None) # 启动消费者生成器,同时第一次接收返回结果 25 | print("[Producer] Start Consumer, return %s" % r) 26 | n = 0 27 | while n < 5: 28 | n += 1 29 | print("[Producer] While, Producing %s ......" % n) 30 | r = c.send(n) # 向消费者发送消息,同时准备接收结果。此时会切换到消费者执行 31 | print("[Producer] Consumer return: %s" % r) 32 | c.close() # 关闭消费者生成器 33 | print("[Producer] Close Producer ......") 34 | 35 | # produce(consumer()) 36 | 37 | 38 | # 异步IO例子:适配Python3.4,使用asyncio库 39 | @asyncio.coroutine 40 | def hello(index): # 通过装饰器asyncio.coroutine定义协程 41 | print('Hello world! index=%s, thread=%s' % (index, threading.currentThread())) 42 | yield from asyncio.sleep(1) # 模拟IO任务 43 | print('Hello again! index=%s, thread=%s' % (index, threading.currentThread()))@asyncio.coroutine 44 | 45 | loop = asyncio.get_event_loop() # 得到一个事件循环模型 46 | tasks = [hello(1), hello(2)] # 初始化任务列表 47 | loop.run_until_complete(asyncio.wait(tasks)) # 执行任务 48 | loop.close() # 关闭事件循环列表 49 | 50 | 51 | # 异步IO例子:适配Python3.5,使用async和await关键字 52 | async def hello1(index): # 通过关键字async定义协程 53 | print('Hello world! index=%s, thread=%s' % (index, threading.currentThread())) 54 | await asyncio.sleep(1) # 模拟IO任务 55 | print('Hello again! index=%s, thread=%s' % (index, threading.currentThread())) 56 | 57 | loop = asyncio.get_event_loop() # 得到一个事件循环模型 58 | tasks = [hello1(1), hello1(2)] # 初始化任务列表 59 | loop.run_until_complete(asyncio.wait(tasks)) # 执行任务 60 | loop.close() # 关闭事件循环列表 61 | 62 | 63 | # aiohttp 实例 64 | async def get(url): 65 | async with aiohttp.ClientSession() as session: 66 | async with session.get(url) as resp: 67 | print(url, resp.status) 68 | print(url, await resp.text()) 69 | 70 | loop = asyncio.get_event_loop() # 得到一个事件循环模型 71 | tasks = [ # 初始化任务列表 72 | get("http://zhushou.360.cn/detail/index/soft_id/3283370"), 73 | get("http://zhushou.360.cn/detail/index/soft_id/3264775"), 74 | get("http://zhushou.360.cn/detail/index/soft_id/705490") 75 | ] 76 | loop.run_until_complete(asyncio.wait(tasks)) # 执行任务 77 | loop.close() # 关闭事件循环列表 78 | -------------------------------------------------------------------------------- /python_csv.py: -------------------------------------------------------------------------------- 1 | # _*_ coding: utf-8 _*_ 2 | 3 | """ 4 | python_csv.py by xianhu 5 | """ 6 | 7 | import csv 8 | import datetime 9 | 10 | # 数据 11 | data = [ 12 | [1, "a,bc", 19.353, datetime.datetime(2001, 3, 17)], 13 | [2, "ei,f", 13.287, datetime.datetime(2011, 4, 27)], 14 | [3, 'q"ij', 15.852, datetime.datetime(2003, 7, 14)], 15 | [4, "zh'n", 11.937, datetime.datetime(2012, 1, 9)], 16 | [5, "i'op", 12.057, datetime.datetime(2009, 5, 18)], 17 | ] 18 | 19 | # 自己创建dialect 20 | csv.register_dialect( 21 | "mydialect", 22 | delimiter=',', # 字段分隔符 23 | escapechar='\\', # 转义字符 24 | quotechar='"', # 包裹字符 25 | doublequote=False, # 使转义字符生效 26 | lineterminator='\n', # 行与行之间的分隔符 27 | quoting=csv.QUOTE_ALL # 包裹模式 28 | ) 29 | 30 | # 写文件 31 | with open("test.csv", "w") as file: 32 | writer = csv.writer(file, dialect="mydialect") 33 | # writer.writerows(data) 34 | for item in data: 35 | writer.writerow(item) 36 | exit() 37 | 38 | # 读文件 39 | with open("test.csv", "r") as file: 40 | reader = csv.reader(file, dialect="excel") 41 | for item in reader: 42 | print(item) 43 | 44 | # 读文件 45 | with open("test.csv", "r") as file: 46 | reader = csv.DictReader(file, fieldnames=["id", "name", "float", "datetime"], dialect="excel") 47 | data = [item for item in reader] 48 | print(data) 49 | 50 | # 写文件 51 | with open("test.csv", "w") as file: 52 | writer = csv.DictWriter(file, fieldnames=["id", "name", "float", "datetime"], dialect="excel") 53 | writer.writeheader() 54 | for item in data: 55 | writer.writerow(item) 56 | -------------------------------------------------------------------------------- /python_datetime.py: -------------------------------------------------------------------------------- 1 | # _*_ coding: utf-8 _*_ 2 | 3 | import time 4 | import calendar 5 | import datetime 6 | 7 | 8 | # time模块中的三种时间形式 9 | print("time stamp:", time.time()) # 时间戳 10 | print("local time:", time.localtime()) # struct_time类型的本地时间 11 | print("utc time:", time.gmtime()) # struct_time类型的utc时间 12 | 13 | # time模块中,三种时间形式之间的转换 14 | time_stamp = time.time() # 时间戳 15 | local_time = time.localtime(time_stamp) # 时间戳转struct_time类型的本地时间 16 | utc_time = time.gmtime(time_stamp) # 时间戳转struct_time类型的utc时间 17 | 18 | time_stamp_1 = time.mktime(local_time) # struct_time类型的本地时间转时间戳 19 | time_stamp_2 = calendar.timegm(utc_time) # struct_time类型的utc时间转时间戳 20 | print(time_stamp, time_stamp_1, time_stamp_2) 21 | 22 | 23 | # time模块中,三种时间形式和字符串之间的转换 24 | print(time.ctime(time_stamp)) # 时间戳转字符串(本地时间字符串) 25 | 26 | print(time.asctime(local_time)) # struct_time类型的本地时间转字符串 27 | print(time.asctime(utc_time)) # struct_time类型的utc时间转字符串 28 | 29 | print(time.strftime("%Y-%m-%d, %H:%M:%S, %w", local_time)) # struct_time类型的本地时间转字符串:自定义格式 30 | print(time.strftime("%Y-%m-%d, %H:%M:%S, %w", utc_time)) # struct_time类型的utc时间转字符串:自定义格式 31 | 32 | struct_time = time.strptime("2016-11-15, 15:32:12, 2", "%Y-%m-%d, %H:%M:%S, %w") # 字符串转struct_time类型 33 | 34 | 35 | # datetime模块中datetime类的用法 36 | a_datetime_local = datetime.datetime.now() # 获取datetime.datetime类型的本地时间 37 | a_datetime_utc = datetime.datetime.utcnow() # 获取datetime.datetime类型的utc时间 38 | 39 | print(a_datetime_local.strftime("%Y-%m-%d, %H:%M:%S, %w")) # datetime.datetime类型转字符串 40 | print(a_datetime_utc.strftime("%Y-%m-%d, %H:%M:%S, %w")) # datetime.datetime类型转字符串 41 | 42 | a_datetime = datetime.datetime.strptime("2016-11-15, 15:32:12, 2", "%Y-%m-%d, %H:%M:%S, %w") # 字符串转datetime.datetime格式 43 | 44 | 45 | # datetime.datetime类和时间戳、struct_time类型之间的转换 46 | time_stamp = a_datetime_local.timestamp() # datetime类型转时间戳 47 | print(time_stamp) 48 | 49 | a_datetime_local = datetime.datetime.fromtimestamp(time.time()) # 时间戳转datetime.datetime类型的本地时间 50 | a_datetime_utc = datetime.datetime.utcfromtimestamp(time.time()) # 时间戳转datetime.datetime类型的utc时间 51 | print(a_datetime_local, a_datetime_utc) 52 | 53 | print(a_datetime_local.timetuple()) # datetime类型转struct_time类型 54 | print(a_datetime_utc.utctimetuple()) # datetime类型转struct_time类型 55 | -------------------------------------------------------------------------------- /python_decorator.py: -------------------------------------------------------------------------------- 1 | # _*_ coding: utf-8 _*_ 2 | 3 | """ 4 | python_decorator.py by xianhu 5 | """ 6 | 7 | import functools 8 | 9 | 10 | # 构建不带参数的装饰器 11 | def logging(func): 12 | @functools.wraps(func) 13 | def decorator(*args, **kwargs): 14 | print("%s called" % func.__name__) 15 | result = func(*args, **kwargs) 16 | print("%s end" % func.__name__) 17 | return result 18 | return decorator 19 | 20 | 21 | # 使用装饰器 22 | @logging 23 | def test01(a, b): 24 | print("in function test01, a=%s, b=%s" % (a, b)) 25 | return 1 26 | 27 | 28 | # 使用装饰器 29 | @logging 30 | def test02(a, b, c=1): 31 | print("in function test02, a=%s, b=%s, c=%s" % (a, b, c)) 32 | return 1 33 | 34 | 35 | # 构建带参数的装饰器 36 | def params_chack(*types, **kwtypes): 37 | def _outer(func): 38 | @functools.wraps(func) 39 | def _inner(*args, **kwargs): 40 | result = [isinstance(_param, _type) for _param, _type in zip(args, types)] 41 | assert all(result), "params_chack: invalid parameters" 42 | result = [isinstance(kwargs[_param], kwtypes[_param]) for _param in kwargs if _param in kwtypes] 43 | assert all(result), "params_chack: invalid parameters" 44 | return func(*args, **kwargs) 45 | return _inner 46 | return _outer 47 | 48 | 49 | # 使用装饰器 50 | @params_chack(int, (list, tuple)) 51 | def test03(a, b): 52 | print("in function test03, a=%s, b=%s" % (a, b)) 53 | return 1 54 | 55 | 56 | # 使用装饰器 57 | @params_chack(int, str, c=(int, str)) 58 | def test04(a, b, c): 59 | print("in function test04, a=%s, b=%s, c=%s" % (a, b, c)) 60 | return 1 61 | 62 | 63 | # 在类的成员方法中使用装饰器 64 | class ATest(object): 65 | @params_chack(object, int, str) 66 | def test(self, a, b): 67 | print("in function test of ATest, a=%s, b=%s" % (a, b)) 68 | return 1 69 | 70 | 71 | # 同时使用多个装饰器 72 | @logging 73 | @params_chack(int, str, (list, tuple)) 74 | def test05(a, b, c): 75 | print("in function test05, a=%s, b=%s, c=%s" % (a, b, c)) 76 | return 1 77 | 78 | 79 | # 构建不带参数的装饰器类 80 | class Decorator(object): 81 | 82 | def __init__(self, func): 83 | self.func = func 84 | return 85 | 86 | def __call__(self, *args, **kwargs): 87 | print("%s called" % self.func.__name__) 88 | result = self.func(*args, **kwargs) 89 | print("%s end" % self.func.__name__) 90 | return result 91 | 92 | 93 | # 使用装饰器 94 | @Decorator 95 | def test06(a, b, c): 96 | print("in function test06, a=%s, b=%s, c=%s" % (a, b, c)) 97 | return 1 98 | 99 | 100 | # 构建带参数的装饰器类 101 | class ParamCheck(object): 102 | 103 | def __init__(self, *types, **kwtypes): 104 | self.types = types 105 | self.kwtypes = kwtypes 106 | return 107 | 108 | def __call__(self, func): 109 | @functools.wraps(func) 110 | def _inner(*args, **kwargs): 111 | result = [isinstance(_param, _type) for _param, _type in zip(args, self.types)] 112 | assert all(result), "params_chack: invalid parameters" 113 | result = [isinstance(kwargs[_param], self.kwtypes[_param]) for _param in kwargs if _param in self.kwtypes] 114 | assert all(result), "params_chack: invalid parameters" 115 | return func(*args, **kwargs) 116 | return _inner 117 | 118 | 119 | # 使用装饰器 120 | @ParamCheck(int, str, (list, tuple)) 121 | def test07(a, b, c): 122 | print("in function test06, a=%s, b=%s, c=%s" % (a, b, c)) 123 | return 1 124 | 125 | 126 | # 装饰器实例: 函数缓存 127 | def funccache(func): 128 | cache = {} 129 | 130 | @functools.wraps(func) 131 | def _inner(*args): 132 | if args not in cache: 133 | cache[args] = func(*args) 134 | return cache[args] 135 | return _inner 136 | 137 | 138 | # 使用装饰器 139 | @funccache 140 | def test08(a, b, c): 141 | # 其他复杂或耗时计算 142 | return a + b + c 143 | 144 | 145 | # 使用Python自带的装饰器 @property 146 | class Person(object): 147 | 148 | def __init__(self): 149 | self._name = None 150 | return 151 | 152 | def get_name(self): 153 | print("get_name") 154 | return self._name 155 | 156 | def set_name(self, name): 157 | print("set_name") 158 | self._name = name 159 | return 160 | 161 | name = property(fget=get_name, fset=set_name, doc="person name") 162 | 163 | 164 | # 使用Python自带的装饰器 @property 165 | class People(object): 166 | 167 | def __init__(self): 168 | self._name = None 169 | self._age = None 170 | return 171 | 172 | @property 173 | def name(self): 174 | return self._name 175 | 176 | @name.setter 177 | def name(self, name): 178 | self._name = name 179 | return 180 | 181 | @property 182 | def age(self): 183 | return self._age 184 | 185 | @age.setter 186 | def age(self, age): 187 | assert 0 < age < 120 188 | self._age = age 189 | return 190 | 191 | 192 | # 类静态方法和类方法 193 | class A(object): 194 | var = 1 195 | 196 | def func(self): 197 | print(self.var) 198 | return 199 | 200 | @staticmethod 201 | def static_func(): 202 | print(A.var) 203 | return 204 | 205 | @classmethod 206 | def class_func(cls): 207 | print(cls.var) 208 | cls().func() 209 | return 210 | -------------------------------------------------------------------------------- /python_flask.py: -------------------------------------------------------------------------------- 1 | # _*_ coding: utf-8 _*_ 2 | 3 | # Flask中的一些定义 4 | # ============================================================================================================================= 5 | # WSGI: Web服务器网关接口,是一种Web服务使用的协议。 6 | # 路由: 处理URL和函数之间关系的程序称为"路由"。 7 | # 视图函数: 类似于index()这样的,被app.route装饰器注册为路由的函数,或者通过app.add_url_rule()添加路由映射关系的函数,被称为视图函数。 8 | # app.route(): 路由装饰器,可以带参数,参数可以指定数据类型:int/float/path。path类似于字符串,但不将反斜线/当做分隔符。 9 | # ============================================================================================================================= 10 | 11 | # Flask上下文全局变量 12 | # ============================================================================================================================= 13 | # current_app: 程序上下文,当前激活程序的程序实例,所有线程公用一个该实例。 14 | # g: 程序上下文,处理请求时用作临时存储的对象,每次请求都会重设这个变量。 15 | # request: 请求上下文,请求对象,封装了客户端发出的 HTTP 请求中的内容,不同线程之间互不干扰。 16 | # session: 请求上下问,用户会话,用于存储请求之间需要“记住”的值的词典。 17 | # ============================================================================================================================= 18 | 19 | # Flask支持的4种钩子函数 20 | # ============================================================================================================================= 21 | # before_first_request: 注册一个函数,在处理第一个请求之前运行。 22 | # before_request: 注册一个函数,在每次请求之前运行。 23 | # after_request: 注册一个函数,如果没有未处理的异常抛出,在每次请求之后运行。 24 | # teardown_request:注册一个函数,即使有未处理的异常抛出,也在每次请求之后运行。 25 | # ============================================================================================================================= 26 | 27 | # Jinja2模板使用 28 | # ============================================================================================================================= 29 | # 渲染模板: render_template("user.html", name=name) 30 | # (1) 变量: {{ name | capitalize }} 31 | # (2) 控制结构: 32 | # {% if user %} 33 | # Hello, {{ user }}! 34 | # {% else %} 35 | # Hello, Stranger! 36 | # {% endif %} 37 | # 38 | #
      39 | # {% for comment in comments %} 40 | #
    • {{ comment }}
    • {% endfor %} 41 | #
    42 | # (3) 宏-类似于函数: 43 | # {% macro render_comment(comment) %} 44 | #
  • {{ comment }}
  • 45 | # {% endmacro %} 46 | # 47 | #
      48 | # {% for comment in comments %} 49 | # {{ render_comment(comment) }} 50 | # {% endfor %} 51 | #
    52 | # ============================================================================================================================= 53 | 54 | # Jinja2变量过滤器 55 | # ============================================================================================================================= 56 | # safe: 渲染值时不转义 57 | # capitalize: 把值的首字母转换成大写,其他字母转换成小写 58 | # lower: 把值转换成小写形式 59 | # upper: 把值转换成大写形式 60 | # title: 把值中每个单词的首字母都转换成大写 61 | # trim: 把值的首尾空格去掉 62 | # striptags: 渲染之前把值中所有的 HTML 标签都删掉 63 | # ============================================================================================================================= 64 | 65 | # Flask-Bootstrap基模板中定义的块 66 | # ============================================================================================================================= 67 | # doc: 整个 HTML 文档 68 | # html_attribs: 标签的属性 69 | # html: 标签中的内容 70 | # head: 标签中的内容 71 | # title: 标签中的内容 72 | # metas: 一组 <meta> 标签 73 | # styles: 层叠样式表定义 74 | # body_attribs: <body> 标签的属性 75 | # body: <body> 标签中的内容 76 | # navbar: 用户定义的导航条 77 | # content: 用户定义的页面内容 78 | # scripts: 文档底部的 JavaScript 声明 79 | # ============================================================================================================================= 80 | 81 | # WTForms支持的HTML标准字段,注意添加app.config['SECRET_KEY'] = 'hard to guess string' 82 | # ============================================================================================================================= 83 | # StringField 文本字段 84 | # TextAreaField 多行文本字段 85 | # PasswordField 密码文本字段 86 | # HiddenField 隐藏文本字段 87 | # DateField 值为datatime.data格式的文本字段 88 | # DateTimeField 值为datatime.datatime格式的文本字段 89 | # DecimalField 值为decimal.Decimal格式的文本字段 90 | # IntegerField 值为整数的文本字段 91 | # FloatField 值为浮点数的文本字段 92 | # BooleanField 值为True或False的复选框 93 | # RadioField 一组单选框 94 | # SelectField 值唯一的下拉列表 95 | # SelectMultipleField 可选多个值得下拉列表 96 | # FileField 文件上传字段 97 | # SubmitField 表单提交按钮 98 | # FormField 把表单作为字段嵌入另一个表单 99 | # FieldList 一组指定类型的字段 100 | # ============================================================================================================================= 101 | 102 | # WTForms验证函数 103 | # ============================================================================================================================= 104 | # Email 验证电子邮件地址 105 | # EqualTo 比较两个字段的值;常用于要求输入两次密码进行确认的情况 106 | # IPAddress 验证 IPv4 网络地址 107 | # Length 验证输入字符串的长度 108 | # NumberRange 验证输入的值在数字范围内 109 | # Optional 无输入值时跳过其他验证函数 110 | # Required / DataRequired 确保字段中有数据 111 | # Regexp 使用正则表达式验证输入值 112 | # URL 验证 URL 113 | # AnyOf 确保输入值在可选值列表中 114 | # NoneOf 确保输入值不在可选值列表中 115 | # ============================================================================================================================= 116 | 117 | # uWSGI配置和nginx配置 118 | # ============================================================================================================================= 119 | # uwsgi -s /tmp/uwsgi.sock -w MyShow:app --chmod-socket=666 120 | # server { 121 | # listen 80; 122 | # server_name wangluopachong.com; 123 | # 124 | # charset utf-8; 125 | # 126 | # location / { 127 | # include uwsgi_params; 128 | # uwsgi_pass unix:/tmp/uwsgi.sock; 129 | # } 130 | # ============================================================================================================================= 131 | -------------------------------------------------------------------------------- /python_functional.py: -------------------------------------------------------------------------------- 1 | # _*_ coding: utf-8 _*_ 2 | 3 | from fn import _ 4 | from operator import add 5 | from functools import partial, reduce 6 | 7 | # 列表解析 8 | a_list = [item**2 for item in range(5)] 9 | print(a_list) 10 | 11 | # 字典解析 12 | a_dict = {"%d^2" % item: item**2 for item in range(5)} 13 | print(a_dict) 14 | 15 | # 生成器 16 | a_generator = (item**2 for item in range(5)) 17 | print(a_generator) 18 | print(next(a_generator)) 19 | print(next(a_generator)) 20 | 21 | # iter函数和next函数 22 | a_list_generator = iter(a_list) 23 | print(next(a_list_generator)) 24 | print(next(a_list_generator)) 25 | print(type(a_list), type(a_list_generator)) 26 | 27 | # lambda表达式 28 | a_func = lambda x, y: x**y 29 | print(a_func(2, 3)) 30 | 31 | # map函数 32 | print(map(abs, range(-4, 5))) 33 | print(list(map(abs, range(-4, 5)))) 34 | print(list(map(lambda x: x**2, range(5)))) 35 | print(list(map(lambda x, y: x**y, range(1, 5), range(1, 5)))) 36 | 37 | # reduce函数 38 | print(reduce(lambda x, y: x+y, range(10))) 39 | print(reduce(lambda x, y: x+y, range(10), 100)) 40 | print(reduce(lambda x, y: x+y, [[1, 2], [3, 4]], [0])) 41 | 42 | # filter函数 43 | print(filter(None, range(-4, 5))) 44 | print(list(filter(None, range(-4, 5)))) 45 | print(list(filter(lambda x: x > 0, range(-4, 5)))) 46 | 47 | # all、any函数 48 | print(all([0, 1, 2])) 49 | print(any([0, 1, 2])) 50 | 51 | # enumerate函数 52 | for index, item in enumerate(range(5)): 53 | print("%d: %d" % (index, item)) 54 | 55 | # zip函数 56 | for a, b in zip([1, 2, 3], ["a", "b", "c"]): 57 | print(a, b) 58 | a_dict = dict(zip([1, 2, 3], ["a", "b", "c"])) 59 | print(a_dict) 60 | 61 | # partial函数 62 | print(int("10010", base=2)) 63 | int_base_2 = partial(int, base=2) 64 | print(int_base_2("10010")) 65 | 66 | # operator.add函数 67 | print(reduce(lambda x, y: x+y, range(10))) 68 | print(reduce(add, range(10))) 69 | 70 | # fn的使用 71 | add_func_1 = (_ + 2) 72 | print(add_func_1(1)) 73 | add_func_2 = (_ + _ * _) 74 | print(add_func_2(1, 2, 3)) 75 | -------------------------------------------------------------------------------- /python_magic_methods.py: -------------------------------------------------------------------------------- 1 | # _*_ coding: utf-8 _*_ 2 | 3 | """ 4 | python_magic_methods.py by xianhu 5 | """ 6 | 7 | 8 | # 定义一个能够自动比较大小的People类 9 | class People(object): 10 | 11 | def __init__(self, name, age): 12 | self.name = name 13 | self.age = age 14 | return 15 | 16 | def __str__(self): 17 | return self.name + ":" + str(self.age) 18 | 19 | def __lt__(self, other): 20 | return self.name < other.name if self.name != other.name else self.age < other.age 21 | 22 | print("\t".join([str(item) for item in sorted([People("abc", 18), People("abe", 19), People("abe", 12), People("abc", 17)])])) 23 | 24 | 25 | # Python实现任意深度的赋值 例如a[0] = 'value1'; a[1][2] = 'value2'; a[3][4][5] = 'value3' 26 | class MyDict(dict): 27 | 28 | def __setitem__(self, key, value): # 该函数不做任何改动 这里只是为了输出 29 | print("setitem:", key, value, self) 30 | super().__setitem__(key, value) 31 | return 32 | 33 | def __getitem__(self, item): # 主要技巧在该函数 34 | print("getitem:", item, self) 35 | # 基本思路: a[1][2]赋值时 需要先取出a[1] 然后给a[1]的[2]赋值 36 | if item not in self: # 如果a[1]不存在 37 | temp = MyDict() # 则需要新建一个dict 38 | super().__setitem__(item, temp) # 并使得a[1] = dict 39 | return temp # 返回a[1] 使得a[1][2] = value有效 40 | return super().__getitem__(item) # 如果a[1]存在 则直接返回a[1] 41 | 42 | # 使用例子: 43 | test = MyDict() 44 | test[0] = 'test' 45 | test[1][2] = 'test1' 46 | test[3][4][5] = 'test2' 47 | print("==========================") 48 | -------------------------------------------------------------------------------- /python_mail.py: -------------------------------------------------------------------------------- 1 | # _*_ coding: utf-8 _*_ 2 | 3 | """ 4 | python发送邮件 5 | """ 6 | 7 | import smtplib 8 | from email.header import Header 9 | from email.mime.text import MIMEText 10 | from email.mime.image import MIMEImage 11 | from email.mime.multipart import MIMEMultipart 12 | 13 | # 第三方 SMTP 服务(以腾讯企业邮件和QQ邮箱为例) 14 | mail_host = "smtp.exmail.qq.com" 15 | # mail_host = "smtp.qq.com" 16 | mail_user = "from@from.com.cn" 17 | # mail_user = "from@qq.com" 18 | mail_pass = "授权码" 19 | mail_sender = mail_user 20 | mail_port = 465 21 | mail_receivers = ["to@to.com", "to@qq.com"] 22 | 23 | # 设置邮件格式、内容等 -- 普通格式 ================================================ 24 | message = MIMEText("邮件内容", "plain", "utf-8") 25 | 26 | # 设置邮件格式、内容等 -- HTML格式 =============================================== 27 | msg_html = """ 28 | <p>Python 邮件发送测试...</p> 29 | <p><a href="http://www.runoob.com">这是一个链接</a></p> 30 | <table border="1"> 31 | <tr><th>Month</th><th>Savings</th></tr> 32 | <tr><td>January</td><td>$100</td></tr> 33 | <tr><td>February</td><td>$80</td></tr> 34 | </table> 35 | """ 36 | message = MIMEText(msg_html, "html", "utf-8") 37 | 38 | # 设置邮件格式、内容等 -- HTML格式(带有图片和附件)================================== 39 | msg_html = """ 40 | <p>Python 邮件发送测试...</p> 41 | <p><a href="http://www.runoob.com">这是一个链接</a></p> 42 | <p>图片演示:</p> 43 | <p><img src="cid:image_id_1"></p> 44 | """ 45 | msg_content = MIMEText(msg_html, "html", "utf-8") 46 | msg_image = MIMEImage(open("test.png", "rb").read()) 47 | msg_image.add_header("Content-ID", "<image_id_1>") 48 | 49 | msg_file = MIMEText(open("test.csv", "rb").read(), "base64", "utf-8") 50 | msg_file["Content-Type"] = "application/octet-stream" 51 | msg_file["Content-Disposition"] = "attachment; filename=\"test.csv\"" 52 | 53 | message = MIMEMultipart("related") 54 | message.attach(msg_content) 55 | message.attach(msg_image) 56 | message.attach(msg_file) 57 | # ============================================================================== 58 | 59 | # 设置邮件的收发件、标题等 60 | message["From"] = mail_sender 61 | message["To"] = ";".join(mail_receivers) 62 | message["Subject"] = Header("邮件标题", "utf-8") 63 | 64 | try: 65 | # 登录,并发送邮件 66 | smtpObj = smtplib.SMTP_SSL(mail_host, mail_port) 67 | smtpObj.login(mail_user, mail_pass) 68 | smtpObj.sendmail(mail_sender, mail_receivers, message.as_string()) 69 | print("success") 70 | except smtplib.SMTPException as excep: 71 | print("error", excep) 72 | -------------------------------------------------------------------------------- /python_markov_chain.py: -------------------------------------------------------------------------------- 1 | # _*_ coding: utf-8 _*_ 2 | 3 | import nltk 4 | import random 5 | 6 | file = open('Text/Walden.txt', 'r') 7 | walden = file.read() 8 | walden = walden.split() 9 | 10 | 11 | def makePairs(arr): 12 | pairs = [] 13 | for i in range(len(arr)): 14 | if i < len(arr) - 1: 15 | temp = (arr[i], arr[i + 1]) 16 | pairs.append(temp) 17 | return pairs 18 | 19 | 20 | def generate(cfd, word='the', num=500): 21 | for i in range(num): 22 | # make an array with the words shown by proper count 23 | arr = [] 24 | for j in cfd[word]: 25 | for k in range(cfd[word][j]): 26 | arr.append(j) 27 | print(word, end=' ') 28 | 29 | # choose the word randomly from the conditional distribution 30 | word = arr[int((len(arr)) * random.random())] 31 | 32 | pairs = makePairs(walden) 33 | cfd = nltk.ConditionalFreqDist(pairs) 34 | generate(cfd) 35 | -------------------------------------------------------------------------------- /python_metaclass.py: -------------------------------------------------------------------------------- 1 | # _*_ coding: utf-8 _*_ 2 | 3 | """ 4 | python_metaclass.py by xianhu 5 | """ 6 | 7 | 8 | class Foo(object): 9 | def hello(self): 10 | print("hello world!") 11 | return 12 | 13 | foo = Foo() 14 | print(type(foo)) # <class '__main__.Foo'> 15 | print(type(foo.hello)) # <class 'method'> 16 | print(type(Foo)) # <class 'type'> 17 | 18 | temp = Foo # 赋值给其他变量 19 | Foo.var = 11 # 增加参数 20 | print(Foo) # 作为函数参数 21 | 22 | 23 | # ======================================================================== 24 | def init(self, name): 25 | self.name = name 26 | return 27 | 28 | 29 | def hello(self): 30 | print("hello %s" % self.name) 31 | return 32 | 33 | Foo = type("Foo", (object,), {"__init__": init, "hello": hello, "cls_var": 10}) 34 | foo = Foo("xianhu") 35 | print(foo.hello()) 36 | print(Foo.cls_var) 37 | 38 | print(foo.__class__) 39 | print(Foo.__class__) 40 | print(type.__class__) 41 | # ======================================================================== 42 | 43 | 44 | class Author(type): 45 | def __new__(mcs, name, bases, dict): 46 | # 添加作者属性 47 | dict["author"] = "xianhu" 48 | return super(Author, mcs).__new__(mcs, name, bases, dict) 49 | 50 | 51 | class Foo(object, metaclass=Author): 52 | pass 53 | 54 | foo = Foo() 55 | print(foo.author) 56 | -------------------------------------------------------------------------------- /python_numpy.py: -------------------------------------------------------------------------------- 1 | # _*_coding:utf-8-*_ 2 | import numpy as np 3 | # 定义矩阵变量并输出变量的一些属性 4 | # 用np.array()生成矩阵 5 | arr=np.array([[1,2,3], 6 | [4,5,6]]) 7 | 8 | print(arr) 9 | print('number of arr dimensions: ',arr.ndim) 10 | print('~ ~ ~ shape: ',arr.shape) 11 | print('~ ~ ~ size: ', arr.size) 12 | 13 | # 输出结果: 14 | [[1 2 3] 15 | [4 5 6]] 16 | number of arr dimensions: 2 17 | ~ ~ ~ shape: (2, 3) 18 | ~ ~ ~ size: 6 19 | 20 | # 定义一些特殊矩阵 21 | # 指定矩阵数据类型 22 | arr=np.array([[1,2,3], 23 | [4,5,6]], 24 | dtype=np.float64) # 我的电脑np.int是int32,还可以使用np.int32/np.int64/np.float32/np.float64 25 | print(arr.dtype) 26 | 27 | # 用np.zeros()生成全零矩阵 28 | arr_zeros=np.zeros( (2,3) ) 29 | print(arr_zeros) 30 | 31 | # 用np.ones()生成全一矩阵 32 | arr_ones=np.ones( (2,3) ) 33 | print(arr_ones) 34 | 35 | # 生成随机矩阵np.random.random() 36 | arr_random=np.random.random((2,3)) 37 | print(arr_random) 38 | 39 | # 用np.arange()生成数列 40 | arr=np.arange(6,12) 41 | print(arr) 42 | 43 | # 用np.arange().reshape()将数列转成矩阵 44 | arr=np.arange(6,12).reshape( (2,3) ) 45 | print(arr) 46 | 47 | # 用np.linspace(开始,结束,多少点划分线段),同样也可以用reshape() 48 | arr=np.linspace(1,5,3) 49 | print(arr) 50 | 51 | # 矩阵运算 52 | arr1=np.array([1,2,3,6]) 53 | arr2=np.arange(4) 54 | 55 | # 矩阵减法,加法同理 56 | arr_sub=arr1-arr2 57 | print(arr1) 58 | print(arr2) 59 | print(arr_sub) 60 | 61 | # 矩阵乘法 62 | arr_multi=arr1**3 # 求每个元素的立方,在python中幂运算用**来表示 63 | print(arr_multi) 64 | 65 | arr_multi=arr1*arr2 # 元素逐个相乘 66 | print(arr_multi) 67 | 68 | arr_multi=np.dot(arr1, arr2.reshape((4,1))) # 维度1*4和4*1矩阵相乘 69 | print(arr_multi) 70 | 71 | arr_multi=np.dot(arr1.reshape((4,1)), arr2.reshape((1,4))) # 维度4*1和1*4矩阵相乘 72 | print(arr_multi) 73 | 74 | arr_multi=arr1.dot(arr2.reshape((4,1))) # 也可以使用矩阵名.doc(矩阵名) 75 | print(arr_multi) 76 | 77 | # 三角运算:np.sin()/np.cos()/np.tan() 78 | arr_sin=np.sin(arr1) 79 | print(arr_sin) 80 | 81 | # 逻辑运算 82 | print(arr1<3) # 查看arr1矩阵中哪些元素小于3,返回[ True True False False] 83 | 84 | # 矩阵求和,求矩阵最大最小值 85 | arr1=np.array([[1,2,3], 86 | [4,5,6]]) 87 | print(arr1) 88 | print(np.sum(arr1)) # 矩阵求和 89 | print(np.sum(arr1,axis=0)) # 矩阵每列求和 90 | print(np.sum(arr1,axis=1).reshape(2,1)) # 矩阵每行求和 91 | 92 | print(np.min(arr1)) # 求矩阵最小值 93 | print(np.min(arr1,axis=0)) 94 | print(np.min(arr1,axis=1)) 95 | 96 | print(np.max(arr1)) # 求矩阵最大值 97 | 98 | print(np.mean(arr1)) # 输出矩阵平均值,也可以用arr1.mean() 99 | print(np.median(arr1)) # 输出矩阵中位数 100 | 101 | # 输出矩阵某些值的位置 102 | arr1=np.arange(2,14).reshape((3,4)) 103 | print(arr1) 104 | 105 | print(np.argmin(arr1)) # 输出矩阵最小值的位置,0 106 | print(np.argmax(arr1)) # 输出矩阵最大值的位置,11 107 | 108 | print(np.cumsum(arr1)) # 输出前一个数的和,前两个数的和,等等 109 | print(np.diff(arr1)) # 输出相邻两个数的差值 110 | 111 | arr_zeros=np.zeros((3,4)) 112 | print(np.nonzero(arr_zeros)) #输出矩阵非零元素位置,返回多个行向量,第i个行向量表示第i个维度 113 | print(np.nonzero(arr1)) 114 | 115 | print(np.sort(arr1)) # 矩阵逐行排序 116 | print(np.transpose(arr1)) # 矩阵转置,也可以用arr1.T 117 | 118 | print(np.clip(arr1,5,9)) #将矩阵中小于5的数置5,大于9的数置9 119 | 120 | # numpy索引 121 | arr1=np.array([1,2,3,6]) 122 | arr2=np.arange(2,8).reshape(2,3) 123 | 124 | print(arr1) 125 | print(arr1[0]) # 索引从0开始计数 126 | 127 | print(arr2) 128 | print(arr2[0][2]) # arr[行][列],也可以用arr[行,列] 129 | print(arr2[0,:]) # 用:来代表所有元素的意思 130 | print(arr2[0,0:3]) # 表示输出第0行,从第0列到第2列所有元素 131 | # 注意python索引一般是左闭右开 132 | 133 | # 通过for循环每次输出矩阵的一行 134 | for row in arr2: 135 | print(row) 136 | 137 | # 如果要每次输出矩阵的一列,就先将矩阵转置 138 | arr2_T=arr2.T 139 | print(arr2_T) 140 | for row in arr2_T: 141 | print(row) 142 | 143 | # 将矩阵压成一行逐个输出元素 144 | arr2_flat=arr2.flatten() 145 | print(arr2_flat) 146 | 147 | for i in arr2.flat: # 也可以用arr2.flatten() 148 | print(i) 149 | 150 | # 矩阵合并与分割 151 | # 矩阵合并 152 | arr1=np.array([1,2,3,6]) 153 | arr2=np.arange(4) 154 | arr3=np.arange(2,16+1,2).reshape(2,4) 155 | print(arr1) 156 | print(arr2) 157 | print(arr3) 158 | 159 | arr_hor=np.hstack((arr1,arr2)) # 水平合并,horizontal 160 | arr_ver=np.vstack((arr1,arr3)) # 垂直合并,vertical 161 | print(arr_hor) 162 | print(arr_ver) 163 | 164 | # 矩阵分割 165 | print('arr3: ',arr3) 166 | print(np.split(arr3,4,axis=1)) # 将矩阵按列均分成4块 167 | print(np.split(arr3,2,axis=0)) # 将矩阵按行均分成2块 168 | print(np.hsplit(arr3,4)) # 将矩阵按列均分成4块 169 | print(np.vsplit(arr3,2)) # 将矩阵按行均分成2块 170 | print(np.array_split(arr3,3,axis=1)) # 将矩阵进行不均等划分 171 | 172 | # numpy复制:浅复制,深复制 173 | # 浅复制 174 | arr1=np.array([3,1,2,3]) 175 | print(arr1) 176 | a1=arr1 177 | b1=a1 178 | # 通过上述赋值运算,arr1,a1,b1都指向了同一个地址(浅复制) 179 | print(a1 is arr1) 180 | print(b1 is arr1) 181 | print(id(a1)) 182 | print(id(b1)) 183 | print(id(arr1)) 184 | 185 | # 会发现通过b1[0]改变内容,arr1,a1,b1的内容都改变了 186 | b1[0]=6 187 | print(b1) 188 | print(a1) 189 | print(arr1) 190 | 191 | # 深复制 192 | arr2=np.array([3,1,2,3]) 193 | print('\n') 194 | print(arr2) 195 | b2=arr2.copy() # 深复制,此时b2拥有不同于arr2的空间 196 | a2=b2.copy() 197 | # 通过上述赋值运算,arr1,a1,b1都指向了不同的地址(深复制) 198 | print(id(arr2)) 199 | print(id(a2)) 200 | print(id(b2)) 201 | # 此时改变b2,a2的值,互不影响 202 | b2[0]=1 203 | a2[0]=2 204 | print(b2) 205 | print(a2) 206 | print(arr2) 207 | 208 | # 线性代数模块(linalg) 209 | # 求范数 210 | a=np.array([5,12]) 211 | print(a) 212 | b=np.linalg.norm(a) # norm表示范数,默认求2范数,ord=1求1范数,ord=np.inf求无穷范数 213 | print(b) 214 | 215 | # 求矩阵的迹、行列式、秩、特征值、特征向量 216 | b = np.array([ 217 | [1, 2, 3], 218 | [4, 5, 6], 219 | [7, 8, 9] 220 | ]) 221 | 222 | print(np.trace(b)) # 15,求矩阵的迹(主对角线上各个元素的总和) 223 | 224 | c=np.linalg.det(b) 225 | print(c) # 输出一个很小的值6.66133814775e-16,求矩阵的行列式值 226 | # 如果希望输出为0,使用round(c, 2),四舍五入保留小数点后两位 227 | # 不过对精度要求高可以使用decimal模块 228 | 229 | c=np.linalg.matrix_rank(b) 230 | print(c) # 2,求矩阵的秩 231 | 232 | u,v=np.linalg.eig(b) # u为特征值 233 | print(u) 234 | print(v) 235 | 236 | # 矩阵分解 237 | # Cholesky分解并重建 238 | d = np.array([ 239 | [2, 1], 240 | [1, 2] 241 | ]) 242 | 243 | l = np.linalg.cholesky(d) 244 | print(l) # 得到下三角矩阵 245 | e=np.dot(l, l.T) 246 | print(e) # 重建得到矩阵d 247 | 248 | 249 | # 对不正定矩阵,进行SVD分解并重建 250 | U, s, V = np.linalg.svd(d) 251 | 252 | S = np.array([ 253 | [s[0], 0], 254 | [0, s[1]] 255 | ]) 256 | 257 | print(np.dot(U, np.dot(S, V))) # 重建得到矩阵d 258 | 259 | # 矩阵乘法 260 | # https://docs.scipy.org/doc/numpy/reference/generated/numpy.dot.html#numpy.dot 261 | print(np.dot(3, 4)) # 12,0-D矩阵相乘(也就是标量相乘) 262 | 263 | print(np.dot([2j, 3j], [2j, 3j])) # (-13+0j),1-D矩阵相乘(实际上是向量做点积) 264 | 265 | a=[[1, 0], [0, 1]] 266 | b=[[4, 1, 0], [2, 2, 0]] 267 | print(np.dot(a, b)) 268 | ''' 269 | array([[4, 1], 270 | [2, 2]]) 271 | 2-D矩阵相乘 272 | 这里是2*2矩阵和2*3矩阵相乘,结果为2*3矩阵 273 | ''' 274 | 275 | a=[[1, 0], [1, 2]] 276 | b=[2,2] 277 | c=np.dot(a,b) 278 | print(c) 279 | ''' 280 | [2 6] 281 | 注意这里b是向量 282 | numpy处理时并不是按照矩阵乘法规则计算 283 | 而是向量点积 284 | 也就是np.dot([1, 0],[1, 2])和np.dot([1, 2],[2,2]) 285 | ''' 286 | 287 | # 再做个实验来区别向量乘法和矩阵乘法 288 | b=np.array([ 289 | [1, 2, 3], 290 | [4, 5, 6], 291 | [7, 8, 9] 292 | ]) 293 | 294 | # 这里插播一下,np.array([1,0,1])是3维向量,而不是1*3的矩阵 295 | c1=np.array([[1,0,2]]) 296 | print(c1.shape) # (1, 3),这是一个1*3的矩阵 297 | c2=np.array([1,0,2]) 298 | print(c2.shape) # (3,),这是一个3维向量 299 | 300 | # print(np.dot(b,c1)) # 报错,不符合矩阵乘法规则 301 | print(np.dot(b,c2)) # [ 7 16 25],点积运算 302 | 303 | print(np.dot(c1,b)) # [[15 18 21]],矩阵乘法运算规则 304 | print(np.dot(c2,b)) # [15 18 21],点积运算 305 | 306 | # 还要补充一下,如果是用python自带的*运算符计算则是广播机制 307 | print(b*c1) # print(b*c2)结果一样 308 | ''' 309 | [[ 1 0 6] 310 | [ 4 0 12] 311 | [ 7 0 18]] 312 | ''' 313 | print(b+c1) # print(b*c2)结果一样 314 | ''' 315 | [[ 2 2 5] 316 | [ 5 5 8] 317 | [ 8 8 11]] 318 | ''' 319 | -------------------------------------------------------------------------------- /python_oneline.py: -------------------------------------------------------------------------------- 1 | # _*_ coding: utf-8 _*_ 2 | 3 | """ 4 | python_oneline.py by xianhu 5 | """ 6 | 7 | 8 | # 首先来个python之禅 9 | # python -c "import this" 10 | """ 11 | The Zen of Python, by Tim Peters 12 | 13 | Beautiful is better than ugly. 14 | Explicit is better than implicit. 15 | Simple is better than complex. 16 | Complex is better than complicated. 17 | Flat is better than nested. 18 | Sparse is better than dense. 19 | Readability counts. 20 | Special cases aren't special enough to break the rules. 21 | Although practicality beats purity. 22 | Errors should never pass silently. 23 | Unless explicitly silenced. 24 | In the face of ambiguity, refuse the temptation to guess. 25 | There should be one-- and preferably only one --obvious way to do it. 26 | Although that way may not be obvious at first unless you're Dutch. 27 | Now is better than never. 28 | Although never is often better than *right* now. 29 | If the implementation is hard to explain, it's a bad idea. 30 | If the implementation is easy to explain, it may be a good idea. 31 | Namespaces are one honking great idea -- let's do more of those! 32 | """ 33 | 34 | 35 | # 一行代码启动一个Web服务 36 | # python -m SimpleHTTPServer 8080 37 | # python3 -m http.server 8080 38 | 39 | 40 | # 一行代码实现变量值互换 41 | a, b = 1, 2; a, b = b, a 42 | 43 | 44 | # 一行代码解决FizzBuzz问题: 打印数字1到100, 3的倍数打印“Fizz”来替换这个数, 5的倍数打印“Buzz”, 既是3又是5的倍数的打印“FizzBuzz” 45 | print(' '.join(["fizz"[x % 3 * 4:]+"buzz"[x % 5 * 4:] or str(x) for x in range(1, 101)])) 46 | 47 | 48 | # 一行代码输出特定字符"Love"拼成的心形 49 | print('\n'.join([''.join([('Love'[(x-y) % len('Love')] if ((x*0.05)**2+(y*0.1)**2-1)**3-(x*0.05)**2*(y*0.1)**3 <= 0 else ' ') for x in range(-30, 30)]) for y in range(30, -30, -1)])) 50 | 51 | 52 | # 一行代码输出Mandelbrot图像: Mandelbrot图像中的每个位置都对应于公式N=x+y*i中的一个复数 53 | print('\n'.join([''.join(['*'if abs((lambda a: lambda z, c, n: a(a, z, c, n))(lambda s, z, c, n: z if n == 0 else s(s, z*z+c, c, n-1))(0, 0.02*x+0.05j*y, 40)) < 2 else ' ' for x in range(-80, 20)]) for y in range(-20, 20)])) 54 | 55 | 56 | # 一行代码打印九九乘法表 57 | print('\n'.join([' '.join(['%s*%s=%-2s' % (y, x, x*y) for y in range(1, x+1)]) for x in range(1, 10)])) 58 | 59 | 60 | # 一行代码计算出1-100之间的素数(两个版本) 61 | print(' '.join([str(item) for item in filter(lambda x: not [x % i for i in range(2, x) if x % i == 0], range(2, 101))])) 62 | print(' '.join([str(item) for item in filter(lambda x: all(map(lambda p: x % p != 0, range(2, x))), range(2, 101))])) 63 | 64 | 65 | # 一行代码输出斐波那契数列 66 | print([x[0] for x in [(a[i][0], a.append([a[i][1], a[i][0]+a[i][1]])) for a in ([[1, 1]], ) for i in range(30)]]) 67 | 68 | 69 | # 一行代码实现快排算法 70 | qsort = lambda arr: len(arr) > 1 and qsort(list(filter(lambda x: x <= arr[0], arr[1:]))) + arr[0:1] + qsort(list(filter(lambda x: x > arr[0], arr[1:]))) or arr 71 | 72 | 73 | # 一行代码解决八皇后问题 74 | [__import__('sys').stdout.write('\n'.join('.' * i + 'Q' + '.' * (8-i-1) for i in vec) + "\n========\n") for vec in __import__('itertools').permutations(range(8)) if 8 == len(set(vec[i]+i for i in range(8))) == len(set(vec[i]-i for i in range(8)))] 75 | 76 | 77 | # 一行代码实现数组的flatten功能: 将多维数组转化为一维 78 | flatten = lambda x: [y for l in x for y in flatten(l)] if isinstance(x, list) else [x] 79 | 80 | 81 | # 一行代码实现list, 有点类似与上个功能的反功能 82 | array = lambda x: [x[i:i+3] for i in range(0, len(x), 3)] 83 | 84 | 85 | # 一行代码实现求解2的1000次方的各位数之和 86 | print(sum(map(int, str(2**1000)))) 87 | 88 | 89 | # 最后推荐一篇文章: [Python One-liner Games](http://arunrocks.com/python-one-liner-games/) 90 | exit() 91 | -------------------------------------------------------------------------------- /python_re.py: -------------------------------------------------------------------------------- 1 | import re 2 | 3 | #-- 基本正则表达式语法 4 | ''' 5 | .:匹配除换行符以外的任意字符。 6 | ^:匹配字符串的开始。 7 | $:匹配字符串的结束。 8 | *:匹配前一个字符0次或多次。 9 | +:匹配前一个字符1次或多次。 10 | ?:匹配前一个字符0次或1次。 11 | {m}:匹配前一个字符m次。 12 | {m,n}:匹配前一个字符至少m次,至多n次。 13 | [abc]:匹配字符集合中的任意一个字符(例如a、b或c)。 14 | [^abc]:匹配不在字符集合中的任意字符。 15 | |:表示“或”关系,匹配符号前后的任意一个表达式。 16 | ():用于分组,可以提取匹配的部分。 17 | \d:匹配任意数字,等价于[0-9]。 18 | \D:匹配任意非数字字符,等价于[^0-9]。 19 | \w:匹配任意字母数字字符,包括下划线,等价于[a-zA-Z0-9_]。 20 | \W:匹配任意非字母数字字符,等价于[^a-zA-Z0-9_]。 21 | \s:匹配任意空白字符,包括空格、制表符、换行符等。 22 | \S:匹配任意非空白字符。 23 | ''' 24 | 25 | #-- re 模块的主要函数 26 | re.match(pattern, string, flags=0) # 尝试从字符串的起始位置匹配正则表达式,如果匹配成功,返回一个匹配对象;否则返回None。 27 | re.search(pattern, string, flags=0) # 扫描整个字符串,返回第一个成功匹配的对象;否则返回None。 28 | re.findall(pattern, string, flags=0) # 在字符串中找到所有与正则表达式匹配的非重叠匹配项,并返回一个列表。 29 | re.finditer(pattern, string, flags=0) # 与findall类似,但返回的是一个迭代器,每个迭代元素都是一个匹配对象。 30 | re.sub(pattern, repl, string, count=0, flags=0) # 使用repl替换string中所有与pattern匹配的子串,count表示替换的最大次数。 31 | re.subn(pattern, repl, string, count=0, flags=0) # 功能与sub相同,但返回一个元组,包含替换后的字符串和替换的总次数。 32 | re.split(pattern, string, maxsplit=0, flags=0) # 根据正则表达式的模式分割字符串,maxsplit表示分割的最大次数。 33 | re.escape(string) # 对字符串中的非字母数字字符进行转义,使其可以安全地用于正则表达式中。 34 | 35 | #-- 示例代码1 36 | # 匹配字符串的开始 37 | match_obj = re.match(r'^Hello', 'Hello World') 38 | if match_obj: 39 | print("Match found:", match_obj.group()) 40 | else: 41 | print("No match") 42 | 43 | # 搜索字符串 44 | search_obj = re.search(r'World', 'Hello World') 45 | if search_obj: 46 | print("Search found:", search_obj.group()) 47 | else: 48 | print("No search match") 49 | 50 | # 查找所有匹配项 51 | findall_result = re.findall(r'\d+', 'There are 42 apples and 33 oranges') 52 | print("Findall result:", findall_result) 53 | 54 | # 替换匹配项 55 | sub_result = re.sub(r'\d+', 'many', 'There are 42 apples and 33 oranges') 56 | print("Sub result:", sub_result) 57 | 58 | # 分割字符串 59 | split_result = re.split(r'\s+', 'Hello World this is Python') 60 | print("Split result:", split_result) 61 | 62 | # 转义字符串 63 | escaped_string = re.escape('Hello? World!') 64 | print("Escaped string:", escaped_string) 65 | 66 | #-- 标志位(flags) 67 | re.IGNORECASE # 忽略大小写。 68 | re.MULTILINE # 多行模式,改变^和$的行为。 69 | re.DOTALL # 让.匹配包括换行符在内的所有字符。 70 | re.VERBOSE # 允许正则表达式包含空白和注释,使其更易于阅读。 71 | 72 | #-- 示例代码2 73 | pattern = re.compile(r''' 74 | \d+ # 匹配一个或多个数字 75 | \. # 匹配小数点 76 | \d+ # 匹配一个或多个数字 77 | ''', re.VERBOSE) 78 | 79 | match_obj = pattern.match('123.456') 80 | if match_obj: 81 | print("Match found:", match_obj.group()) 82 | else: 83 | print("No match") -------------------------------------------------------------------------------- /python_redis.py: -------------------------------------------------------------------------------- 1 | # _*_ coding: utf-8 _*_ 2 | 3 | """ 4 | Python操作Redis实现消息的发布与订阅 5 | """ 6 | 7 | import sys 8 | import time 9 | import redis 10 | 11 | # 全局变量 12 | conn_pool = redis.ConnectionPool(host="localhost", port=6379, db=1) 13 | conn_inst = redis.Redis(connection_pool=conn_pool) 14 | channel_name = "fm-101.1" 15 | 16 | 17 | def public_test(): 18 | while True: 19 | # 发布消息 20 | conn_inst.publish(channel_name, "hello " + str(time.time())) 21 | if int(time.time()) % 10 == 1: 22 | conn_inst.publish(channel_name, "over") 23 | time.sleep(1) 24 | 25 | 26 | def subscribe_test(_type=0): 27 | pub = conn_inst.pubsub() 28 | pub.subscribe(channel_name) 29 | 30 | if _type == 0: 31 | # 订阅消息 32 | for item in pub.listen(): 33 | print("Listen on channel: %s" % item) 34 | if item["type"] == "message" and item["data"].decode() == "over": 35 | print(item["channel"].decode(), "已停止发布") 36 | break 37 | else: 38 | # 另一种订阅模式 39 | while True: 40 | item = pub.parse_response() 41 | print("Listen on channel: %s" % item) 42 | if item[0].decode() == "message" and item[2].decode() == "over": 43 | print(item[1].decode(), "已停止发布") 44 | break 45 | 46 | # 取消订阅 47 | pub.unsubscribe() 48 | return 49 | 50 | 51 | if __name__ == '__main__': 52 | if sys.argv[1] == "public": 53 | public_test() 54 | else: 55 | subscribe_test(int(sys.argv[2])) 56 | -------------------------------------------------------------------------------- /python_requests.py: -------------------------------------------------------------------------------- 1 | # _*_ coding: utf-8 _*_ 2 | 3 | """ 4 | python_requests.py by xianhu 5 | """ 6 | 7 | import requests.adapters 8 | 9 | # 不同方式获取网页内容, 返回一个Response对象, 请求的参数可以为url或Request对象 10 | r0 = requests.get("https://github.com/timeline.json") 11 | r1 = requests.post("http://httpbin.org/post") 12 | r2 = requests.put("http://httpbin.org/put") 13 | r3 = requests.delete("http://httpbin.org/delete") 14 | r4 = requests.head("http://httpbin.org/get") 15 | r5 = requests.options("http://httpbin.org/get") 16 | r6 = requests.patch("http://httpbin.org/get") 17 | 18 | # Request对象: 19 | # class requests.Request(method=None, url=None, headers=None, files=None, data=None, params=None, auth=None, cookies=None, hooks=None, json=None) 20 | 21 | # 上边所有的获取方式都调用底层的request方法, 所以request方法有的参数, 上边几个函数都应该有: 22 | # requests.request(method, url, **kwargs) 23 | # kwargs包括: params / data / json / headers / cookies / files / auth / timeout / allow_redirects(bool) / proxies / verify(bool) / stream / cert 24 | 25 | # Response对象: class requests.Response 26 | # 包含的主要属性: content / cookies / encoding / headers / history / is_permanent_redirect / is_redirect / reason / status_code / text / url 等 27 | # 包含的主要方法: iter_content(chunk_size=1, decode_unicode=False) / iter_lines(chunk_size=512, decode_unicode=None, delimiter=None) 28 | # 包含的主要方法: close() / json(**kwargs) / raise_for_status() 等 29 | 30 | # 以字典的形式传递URL参数, 也可以直接以?xx=xx&xx=xx的形式将其放在url后 31 | params = {"key1": "value1", "key2": "value2"} 32 | r = requests.get("http://httpbin.org/get", params=params) 33 | print(r.url) # http://httpbin.org/get?key2=value2&key1=value1 34 | 35 | # 以字典的形式传递URL参数: 字典里带有列表 36 | params = {"key1": "value1", "key2": ["value2", "value3"]} 37 | r = requests.get("http://httpbin.org/get", params=params) 38 | print(r.url) # http://httpbin.org/get?key1=value1&key2=value2&key2=value3 39 | 40 | # 获取网页内容 41 | r = requests.get("https://github.com/timeline.json") 42 | print(r.text) # 返回正常的网页内容, 即解压解码之后的内容 43 | print(r.content) # 返回byte类型的网页内容, 即值解压, 没有解码 44 | print(r.json()) # 如果网页内容为json, 直接返回一个json对象 45 | print(r.encoding) # 返回网页的编码: "utf-8" 46 | 47 | # Requests会自动解码来自服务器的内容, 也可以自己更改 48 | r.encoding = "ISO-8859-1" 49 | print(r.text) # 此时使用新的r.encoding解码后的新值 50 | 51 | # 编码的其他操作 52 | # requests.utils.get_encodings_from_content(content): Returns encodings from given content string. 53 | # requests.utils.get_encoding_from_headers(headers): Returns encodings from given HTTP Header Dict. 54 | # requests.utils.get_unicode_from_response(r): Returns the requested content back in unicode. 55 | 56 | # 原始响应内容: 获取来自服务器的原始套接字响应 57 | r = requests.get("https://github.com/timeline.json", stream=True) 58 | print(r.raw) # <requests.packages.urllib3.response.HTTPResponse object at 0x101194810> 59 | print(r.raw.read(10)) # "\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\x03" 60 | 61 | # 一般情况下, 应该以下面的模式将文本流保存到文件 62 | with open("test", "wb") as fd: 63 | for chunk in r.iter_content(chunk_size=256): 64 | fd.write(chunk) 65 | # 注意: 设置的timeout对connect和read起作用. 但一旦和服务器建立连接, r.content或r.iter_content就处于一个read的状态, 不受timeout影响 66 | 67 | # 定制请求头: 一个字典 68 | headers = {"user-agent": "my-app/0.0.1"} 69 | r = requests.get("https://api.github.com/some/endpoint", headers=headers) 70 | print(r.request.headers) # 获取request的头部 71 | print(r.headers) # 获取response的头部 72 | # { 73 | # "content-encoding": "gzip", 74 | # "transfer-encoding": "chunked", 75 | # "connection": "close", 76 | # "server": "nginx/1.0.4", 77 | # "x-runtime": "148ms", 78 | # "etag": "e1ca502697e5c9317743dc078f67693f", 79 | # "content-type": "application/json" 80 | # } 81 | print(r.headers["Content-Type"]) # "application/json" 82 | print(r.headers.get("content-type")) # "application/json" 83 | 84 | # 更加复杂的POST请求: 表单 85 | post_dict = {"key1": "value1", "key2": "value2"} 86 | r = requests.post("http://httpbin.org/post", data=post_dict) 87 | print(r.text) 88 | 89 | # POST一个多部分编码(Multipart-Encoded)的文件 90 | files = {"file": open("report.xls", "rb")} 91 | r = requests.post("http://httpbin.org/post", files=files) 92 | print(r.text) 93 | 94 | # 你可以显式地设置文件名, 文件类型和请求头 95 | files = {"file": ("report.xls", open("report.xls", "rb"), "application/vnd.ms-excel", {"Expires": "0"})} 96 | r = requests.post("http://httpbin.org/post", files=files) 97 | print(r.text) 98 | 99 | # 你也可以发送文本字符串 100 | files = {"file": ("report.csv", "some,data,to,send\nanother,row,to,send\n")} 101 | r = requests.post("http://httpbin.org/post", files=files) 102 | print(r.text) 103 | 104 | # 响应状态码 105 | r = requests.get("http://httpbin.org/get") 106 | print(r.status_code) # 200 107 | print(r.status_code == requests.codes.ok) # True 响应状态码查询 108 | 109 | # 如果发送了一个错误请求(4XX客户端错误, 或5XX服务器错误响应), 可以通过 Response.raise_for_status() 来抛出异常: 110 | bad_r = requests.get("http://httpbin.org/status/404") 111 | print(bad_r.status_code) # 404 112 | bad_r.raise_for_status() # 引发异常 113 | 114 | # Cookie: 如果某个响应中包含一些cookie, 则会被放到response.cookies(CookieJar类型)中 115 | r = requests.get("http://example.com/some/cookie/setting/url") 116 | print(r.cookies["example_cookie_name"]) # "example_cookie_value" 117 | 118 | # 要想发送你的cookies到服务器, 可以使用cookies参数(一个字典) 119 | cookies = {"cookies_are": "working"} 120 | r = requests.get("http://httpbin.org/cookies", cookies=cookies) 121 | print(r.text) 122 | 123 | # cookie的其他操作 124 | # requests.utils.dict_from_cookiejar(cj): Returns a key/value dictionary from a CookieJar. 125 | # requests.utils.cookiejar_from_dict(cookie_dict, cookiejar=None, overwrite=True): Returns a CookieJar from a key/value dictionary. 126 | # requests.utils.add_dict_to_cookiejar(cj, cookie_dict): Returns a CookieJar from a key/value dictionary. 127 | 128 | # 通用CookieJar类, 一个cookielib.CookieJar, 但是提供一个dict接口 129 | # class requests.cookies.RequestsCookieJar(policy=None): Compatibility class; is a cookielib.CookieJar, but exposes a dict interface. 130 | 131 | # 会话对象: 会话对象让你能够跨请求保持某些参数, 它也会在同一个Session实例发出的所有请求之间保持cookie 132 | s = requests.Session() 133 | s.get("http://httpbin.org/cookies/set/sessioncookie/123456789") 134 | s.get("http://httpbin.org/cookies") 135 | for cookie in s.cookies: 136 | print(cookie) 137 | 138 | # 如果你要手动为会话添加cookie, 就是用Cookie utility函数来操纵Session.cookies 139 | requests.utils.add_dict_to_cookiejar(s.cookies, {"cookie_key": "cookie_value"}) 140 | 141 | # 会话也可用来为请求方法提供缺省数据, 这是通过为会话对象的属性提供数据来实现的 142 | s.auth = ("user", "pass") 143 | s.headers.update({"x-test": "true"}) 144 | s.get("http://httpbin.org/headers", headers={"x-test2": "true"}) # both "x-test" and "x-test2" are sent 145 | 146 | # 不过需要注意, 就算使用了会话, 方法级别的参数也不会被跨请求保持, 下面的例子只会给第一个请求发送cookie 147 | s.get("http://httpbin.org/cookies", cookies={"from-my": "browser"}) # 带有cookie 148 | s.get("http://httpbin.org/cookies") # 不带cookie 149 | 150 | # 会话还可以用作前后文管理器 151 | with requests.Session() as s: 152 | s.get("http://httpbin.org/cookies/set/sessioncookie/123456789") 153 | # class requests.Session类, 和requests外层有的函数/属性基本一致, 只不过是封装了一层跨域请求的功能 154 | 155 | # 重定向与请求历史, 默认情况下, 除了HEAD, Requests会自动处理所有重定向, 可以通过allow_redirects参数禁用重定向处理 156 | # 可以使用响应对象的history方法来追踪重定向, Response.history 是一个Response对象的列表, 按照从最老到最近的请求进行排序 157 | r = requests.get("http://github.com", allow_redirects=True) 158 | print(r.status_code) # 200 159 | print(r.history) # [<Response [301]>] 160 | r = requests.get("http://github.com", allow_redirects=False) 161 | print(r.status_code) # 301 162 | print(r.history) # [] 163 | 164 | # 超时, 设置timeout参数 165 | requests.get("http://github.com", timeout=0.001) 166 | # Traceback (most recent call last): 167 | # File "<stdin>", line 1, in <module> 168 | # requests.exceptions.Timeout: HTTPConnectionPool(host="github.com", port=80): Request timed out. (timeout=0.001) 169 | 170 | # 注意: timeout仅对连接过程有效, 与响应体的下载无关 171 | # timeout并不是整个下载响应的时间限制, 而是如果服务器在timeout秒内没有应答, 将会引发一个异常 172 | # 更精确地说, 是在timeout秒内没有从基础套接字上接收到任何字节的数据时 173 | requests.get("https://github.com", timeout=5) 174 | 175 | # 上边的timeout值将会用作 connect 和 read 二者的timeout, 如果要分别制定, 就传入一个元组 176 | requests.get("https://github.com", timeout=(3.05, 27)) 177 | 178 | # 错误与异常: 遇到网络问题(如: DNS 查询失败、拒绝连接等)时, Requests 会抛出一个 ConnectionError 异常 179 | # 如果 HTTP 请求返回了不成功的状态码, Response.raise_for_status() 会抛出一个 HTTPError 异常 180 | # 若请求超时, 则抛出一个 Timeout 异常 181 | # 若请求超过了设定的最大重定向次数, 则会抛出一个 TooManyRedirects 异常 182 | # 所有Requests显式抛出的异常都继承自 requests.exceptions.RequestException 183 | 184 | # 所有异常: 185 | # exception requests.RequestException(*args, **kwargs): There was an ambiguous exception that occurred while handling your request. 186 | # exception requests.ConnectionError(*args, **kwargs): A Connection error occurred. 187 | # exception requests.HTTPError(*args, **kwargs): An HTTP error occurred. 188 | # exception requests.URLRequired(*args, **kwargs): A valid URL is required to make a request. 189 | # exception requests.TooManyRedirects(*args, **kwargs): Too many redirects. 190 | # exception requests.ConnectTimeout(*args, **kwargs): The request timed out while trying to connect to the remote server. 191 | # exception requests.ReadTimeout(*args, **kwargs): The server did not send any data in the allotted amount of time. 192 | # exception requests.Timeout(*args, **kwargs): The request timed out. 193 | 194 | # SSL证书验证, verify设置为True表示检查证书, 设置为False表示忽略证书 195 | requests.get("https://kennethreitz.com", verify=True) # 未设置SSL证书, 抛出异常 196 | # requests.exceptions.SSLError: hostname "kennethreitz.com" doesn"t match either of "*.herokuapp.com", "herokuapp.com" 197 | requests.get("https://github.com", verify=True) # <Response [200]>, 已设置SSL证书 198 | # 对于私有证书,你也可以传递一个 CA_BUNDLE 文件的路径给 verify 199 | 200 | # 你也可以指定一个本地证书用作客户端证书, 可以是单个文件(包含密钥和证书)或一个包含两个文件路径的元组: 201 | requests.get("https://kennethreitz.com", cert=("/path/server.crt", "/path/key")) 202 | requests.get("https://kennethreitz.com", cert="/wrong_path/server.pem") 203 | # SSLError: [Errno 336265225] _ssl.c:347: error:140B0009:SSL routines:SSL_CTX_use_PrivateKey_file:PEM lib 204 | # 警告: 本地证书的私有 key 必须是解密状态. 目前Requests不支持使用加密的 key 205 | 206 | # 流式上传, 允许你发送大的数据流或文件而无需先把它们读入内存 207 | with open("massive-body") as f: 208 | requests.post("http://some.url/streamed", data=f) 209 | 210 | # 事件挂钩, 可用的钩子: response(从一个请求产生的响应) 211 | # 你可以通过传递一个 {hook_name: callback_function} 字典给 hooks 请求参数为每个请求分配一个钩子函数 212 | def print_url(resp): 213 | print(resp.url) 214 | return 215 | requests.get("http://httpbin.org", hooks=dict(response=print_url)) 216 | 217 | # 代理 218 | proxies = { 219 | "http": "http://10.10.1.10:3128", 220 | "https": "http://10.10.1.10:1080", 221 | } 222 | requests.get("http://example.org", proxies=proxies) 223 | # 若代理需要使用HTTP Basic Auth, 可以使用http://user:password@host:port/, 比如"http": "http://user:pass@10.10.1.10:3128/" 224 | 225 | # 除了基本的 HTTP 代理, Request 还支持 SOCKS 协议的代理, 此时需要单独安装: 226 | # $ pip install requests[socks] 227 | proxies = { 228 | "http": "socks5://user:pass@host:port", 229 | "https": "socks5://user:pass@host:port" 230 | } 231 | requests.get("http://example.org", proxies=proxies) 232 | 233 | # Requests 传输适配器 234 | # 从 v1.0.0 以后,Requests 的内部采用了模块化设计。部分原因是为了实现传输适配器(Transport Adapter)。 235 | # 传输适配器提供了一个机制,让你可以为 HTTP 服务定义交互方法。尤其是它允许你应用服务前的配置。 236 | # Requests 自带了一个传输适配器,也就是 HTTPAdapter。 这个适配器使用了强大的 urllib3,为 Requests 提供了默认的 HTTP 和 HTTPS 交互。 237 | # 每当 Session 被初始化,就会有适配器附着在 Session 上,其中一个供 HTTP 使用,另一个供 HTTPS 使用。 238 | # Request 允许用户创建和使用他们自己的传输适配器,实现他们需要的特殊功能。创建好以后,传输适配器可以被加载到一个会话对象上,附带着一个说明,告诉会话适配器应该应用在哪个 web 服务上。 239 | s = requests.Session() 240 | s.mount("http://baidu.com", requests.adapters.HTTPAdapter()) 241 | 242 | # 出现错误: Connection pool is full, discarding connection: xxxx.com 243 | s.mount('https://', requests.adapters.HTTPAdapter(pool_connections=100, pool_maxsize=100)) 244 | 245 | # 关闭InsecurePlatformWarning 246 | # requests.packages.urllib3.disable_warnings() 247 | -------------------------------------------------------------------------------- /python_restful_api.py: -------------------------------------------------------------------------------- 1 | # _*_ coding: utf-8 _*_ 2 | 3 | """ 4 | python_restful_api.py by xianhu 5 | """ 6 | 7 | import sqlalchemy 8 | import sqlalchemy.orm 9 | import sqlalchemy.ext.declarative 10 | from flask import Flask, g 11 | from flask_restful import reqparse, Api, Resource 12 | from flask_httpauth import HTTPTokenAuth 13 | 14 | 15 | # Flask相关变量声明 16 | app = Flask(__name__) 17 | api = Api(app) 18 | 19 | # 认证相关 20 | auth = HTTPTokenAuth(scheme="token") 21 | TOKENS = { 22 | "fejiasdfhu", 23 | "fejiuufjeh" 24 | } 25 | 26 | 27 | @auth.verify_token 28 | def verify_token(token): 29 | if token in TOKENS: 30 | g.current_user = token 31 | return True 32 | return False 33 | 34 | 35 | # 数据库相关变量声明 36 | engine = sqlalchemy.create_engine("mysql+pymysql://username:password@ip/db_name", encoding="utf8", echo=False) 37 | BaseModel = sqlalchemy.ext.declarative.declarative_base() 38 | 39 | 40 | # 构建数据模型User 41 | class User(BaseModel): 42 | __tablename__ = "Users" 43 | __table_args__ = { 44 | "mysql_engine": "InnoDB", 45 | "mysql_charset": "utf8", 46 | } 47 | 48 | # 表结构,具体更多的数据类型自行百度 49 | id = sqlalchemy.Column("id", sqlalchemy.Integer, primary_key=True, autoincrement=True) 50 | name = sqlalchemy.Column("name", sqlalchemy.String(50), nullable=False) 51 | age = sqlalchemy.Column("age", sqlalchemy.Integer, nullable=False) 52 | 53 | 54 | # 构建数据模型的json格式 55 | def get_json(user): 56 | return {"id": user.id, "name": user.name, "age": user.age} 57 | 58 | 59 | # 利用Session对象连接数据库 60 | DBSessinon = sqlalchemy.orm.sessionmaker(bind=engine) 61 | session = DBSessinon() 62 | BaseModel.metadata.drop_all(engine) 63 | BaseModel.metadata.create_all(engine) 64 | 65 | # RESTfulAPI的参数解析 -- put / post参数解析 66 | parser_put = reqparse.RequestParser() 67 | parser_put.add_argument("name", type=str, required=True, help="need name data") 68 | parser_put.add_argument("age", type=int, required=True, help="need age data") 69 | 70 | # RESTfulAPI的参数解析 -- get参数解析 71 | parser_get = reqparse.RequestParser() 72 | parser_get.add_argument("limit", type=int, required=False) 73 | parser_get.add_argument("offset", type=int, required=False) 74 | parser_get.add_argument("sortby", type=str, required=False) 75 | 76 | 77 | # 操作(put / get / delete)单一资源 78 | class Todo(Resource): 79 | # 添加认证 80 | decorators = [auth.login_required] 81 | 82 | def put(self, user_id): 83 | """ 84 | 更新用户数据: curl http://127.0.0.1:5000/users/1 -X PUT -d "name=Allen&age=20" -H "Authorization: token fejiasdfhu" 85 | """ 86 | args = parser_put.parse_args() 87 | user_ids_set = set([user.id for user in session.query(User.id)]) 88 | print(user_ids_set) 89 | 90 | # 用户不存在,返回404 91 | if user_id not in user_ids_set: 92 | return None, 404 93 | 94 | # 更新用户数据 95 | user = session.query(User).filter(User.id == user_id)[0] 96 | user.name = args["name"] 97 | user.age = args["age"] 98 | session.merge(user) 99 | session.commit() 100 | 101 | # 更新成功,返回201 102 | return get_json(user), 201 103 | 104 | def get(self, user_id): 105 | """ 106 | 获取用户数据: curl http://127.0.0.1:5000/users/1 -X GET -H "Authorization: token fejiasdfhu" 107 | """ 108 | users = session.query(User).filter(User.id == user_id) 109 | 110 | # 用户不存在,返回404 111 | if users.count() == 0: 112 | return None, 404 113 | 114 | # 返回用户数据 115 | return get_json(users[0]), 200 116 | 117 | def delete(self, user_id): 118 | """ 119 | 删除用户数据: curl http://127.0.0.1:5000/users/1 -X DELETE -H "Authorization: token fejiasdfhu" 120 | """ 121 | session.query(User).filter(User.id == user_id).delete() 122 | return None, 204 123 | 124 | 125 | # 操作(post / get)资源列表 126 | class TodoList(Resource): 127 | # 添加认证 128 | decorators = [auth.login_required] 129 | 130 | def get(self): 131 | """ 132 | 获取全部用户数据: curl http://127.0.0.1:5000/users -X GET -d "limit=2&offset=0&sortby=name" -H "Authorization: token fejiasdfhu" 133 | """ 134 | args = parser_get.parse_args() 135 | users = session.query(User) 136 | 137 | # 根据条件查询 138 | if "sortby" in args: 139 | users = users.order_by(User.name if args["sortby"] == "name" else User.age) 140 | if "offset" in args: 141 | users = users.offset(args["offset"]) 142 | if "limit" in args: 143 | users = users.limit(args["limit"]) 144 | 145 | # 返回结果 146 | return [get_json(user) for user in users], 200 147 | 148 | def post(self): 149 | """ 150 | 添加一个新用户: curl http://127.0.0.1:5000/users -X POST -d "name=Brown&age=20" -H "Authorization: token fejiasdfhu" 151 | """ 152 | args = parser_put.parse_args() 153 | 154 | # 构建新用户 155 | user = User(name=args["name"], age=args["age"]) 156 | session.add(user) 157 | session.commit() 158 | 159 | # 资源添加成功,返回201 160 | return get_json(user), 201 161 | 162 | 163 | # 设置路由 164 | api.add_resource(TodoList, "/users") 165 | api.add_resource(Todo, "/users/<int:user_id>") 166 | 167 | 168 | if __name__ == "__main__": 169 | app.run(debug=True) 170 | 171 | 172 | """ 常见返回代码 173 | 200 OK - [GET]:服务器成功返回用户请求的数据 174 | 201 CREATED - [POST/PUT/PATCH]:用户新建或修改数据成功 175 | 202 Accepted - [*]:表示一个请求已经进入后台排队(异步任务) 176 | 204 NO CONTENT - [DELETE]:用户删除数据成功 177 | 400 INVALID REQUEST - [POST/PUT/PATCH]:用户发出的请求有错误,服务器没有进行新建或修改数据的操作 178 | 401 Unauthorized - [*]:表示用户没有权限(令牌、用户名、密码错误) 179 | 403 Forbidden - [*] 表示用户得到授权(与401错误相对),但是访问是被禁止的 180 | 404 NOT FOUND - [*]:用户发出的请求针对的是不存在的记录,服务器没有进行操作 181 | 406 Not Acceptable - [GET]:用户请求的格式不可得 182 | 410 Gone -[GET]:用户请求的资源被永久删除,且不会再得到的 183 | 422 Unprocesable entity - [POST/PUT/PATCH] 当创建一个对象时,发生一个验证错误 184 | 500 INTERNAL SERVER ERROR - [*]:服务器发生错误,用户将无法判断发出的请求是否成功 185 | """ 186 | -------------------------------------------------------------------------------- /python_schedule.py: -------------------------------------------------------------------------------- 1 | # _*_ coding: utf-8 _*_ 2 | 3 | """ 4 | 调度的使用 5 | """ 6 | 7 | import time 8 | import datetime 9 | from threading import Timer 10 | from apscheduler.schedulers.blocking import BlockingScheduler 11 | from apscheduler.schedulers.background import BackgroundScheduler 12 | 13 | 14 | def print_hello(): 15 | print("TimeNow in func: %s" % (datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S"))) 16 | return 17 | 18 | 19 | if __name__ == "__main__": 20 | # 1. 使用Threading模块中的Timer 21 | # t = Timer(2, print_hello) 22 | # 23 | # print("TimeNow start: %s" % (datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S"))) 24 | # t.start() 25 | # print("TimeNow end: %s" % (datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S"))) 26 | # exit() 27 | 28 | # 2. BlockingScheduler:在进程中运行单个任务,调度器是唯一运行的东西, 采用阻塞的方式 29 | scheduler = BlockingScheduler() 30 | 31 | # 采用固定时间间隔(interval)的方式,每隔5秒钟执行一次 32 | scheduler.add_job(print_hello, "interval", seconds=5) 33 | 34 | # 采用date的方式,在特定时间只执行一次 35 | # scheduler.add_job(print_hello, "date", run_date=datetime.datetime.now() + datetime.timedelta(seconds=5)) 36 | 37 | # print("TimeNow start: %s" % (datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S"))) 38 | # scheduler.start() 39 | # print("TimeNow end: %s" % (datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S"))) 40 | # exit() 41 | 42 | # 3. BackgroundScheduler: 适合于要求任何在程序后台运行的情况,当希望调度器在应用后台执行时使用。采用非阻塞的方式 43 | scheduler = BackgroundScheduler() 44 | 45 | # 采用固定时间间隔(interval)的方式,每隔3秒钟执行一次 46 | scheduler.add_job(print_hello, "interval", seconds=5) 47 | 48 | # 这是一个独立的线程 49 | # print("TimeNow start: %s" % (datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S"))) 50 | # scheduler.start() 51 | # print("TimeNow end: %s" % (datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S"))) 52 | # while True: 53 | # time.sleep(2) 54 | -------------------------------------------------------------------------------- /python_socket.py: -------------------------------------------------------------------------------- 1 | # _*_ coding: utf-8 _*_ 2 | 3 | """ 4 | Socket编程 5 | """ 6 | 7 | import sys 8 | import socket 9 | 10 | 11 | def server_func(port): 12 | """ 13 | 服务端 14 | """ 15 | # 1. 创建socket对象 16 | server = socket.socket() 17 | 18 | # 2. 绑定ip和端口 19 | server.bind(("127.0.0.1", port)) 20 | 21 | # 3. 监听是否有客户端连接 22 | server.listen(10) 23 | print("服务端已经启动%s端口......" % port) 24 | 25 | # 4. 接收客户端连接 26 | sock_obj, address = server.accept() 27 | sock_obj.settimeout(3) 28 | print("客户端:%s,超时时间:%s" % (address, sock_obj.gettimeout())) 29 | 30 | while True: 31 | try: 32 | # 5. 接收客户端发送的消息 33 | recv_data = sock_obj.recv(1024).decode("utf-8") 34 | print("客户端端 -> 服务端: %s" % recv_data) 35 | if recv_data == "quit": 36 | break 37 | 38 | # 6. 给客户端回复消息 39 | send_data = "received[%s]" % recv_data 40 | sock_obj.send(send_data.encode("utf-8")) 41 | print("服务端 -> 客户端: %s" % send_data) 42 | except Exception as excep: 43 | print("error: ", excep) 44 | 45 | # 7. 关闭socket对象 46 | sock_obj.close() 47 | server.close() 48 | 49 | 50 | def client_func(port): 51 | """ 52 | 客户端 53 | """ 54 | # 1. 创建客户端的socket对象 55 | client = socket.socket() 56 | 57 | # 2. 连接服务端, 需要指定端口和IP 58 | client.connect(("127.0.0.1", port)) 59 | 60 | while True: 61 | # 3. 给服务端发送数据 62 | send_data = input("客户端>").strip() 63 | client.send(send_data.encode("utf-8")) 64 | if send_data == "quit": 65 | break 66 | 67 | # 4. 获取服务端返回的消息 68 | recv_data = client.recv(1024).decode("utf-8") 69 | print("服务端 -> 客户端: %s" % recv_data) 70 | 71 | # 5. 关闭socket连接 72 | client.close() 73 | 74 | 75 | if __name__ == '__main__': 76 | flag = sys.argv[1] 77 | if flag == "server": 78 | server_func(9901) 79 | else: 80 | client_func(9901) 81 | -------------------------------------------------------------------------------- /python_spider.py: -------------------------------------------------------------------------------- 1 | # _*_ coding: utf-8 _*_ 2 | 3 | """ 4 | python_spider.py by xianhu 5 | """ 6 | 7 | import requests 8 | import urllib.error 9 | import urllib.parse 10 | import urllib.request 11 | import http.cookiejar 12 | 13 | # 首先定义下边可能需要的变量 14 | url = "https://www.baidu.com" 15 | headers = {"User-Agent": "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT)"} 16 | 17 | # 最简单的网页抓取方式 18 | response = urllib.request.urlopen(url, timeout=10) 19 | html = response.read().decode("utf-8") 20 | 21 | 22 | # 使用Request实例代替url 23 | request = urllib.request.Request(url, data=None, headers={}) 24 | response = urllib.request.urlopen(request, timeout=10) 25 | 26 | 27 | # 发送数据,即在Request()中添加data参数 28 | data = urllib.parse.urlencode({"act": "login", "email": "xianhu@qq.com", "password": "123456"}) 29 | request1 = urllib.request.Request(url, data=data) # POST方法 30 | request2 = urllib.request.Request(url+"?%s" % data) # GET方法 31 | response = urllib.request.urlopen(request, timeout=10) 32 | 33 | 34 | # 发送Header,即在Request()中添加headers参数 35 | request = urllib.request.Request(url, data=data, headers=headers) # 参数中添加header参数 36 | request.add_header("Referer", "http://www.baidu.com") # 另一种添加header的方式,添加Referer是为了应对"反盗链" 37 | response = urllib.request.urlopen(request, timeout=10) 38 | 39 | 40 | # 网页抓取引发异常:urllib.error.HTTPError, urllib.error.URLError, 两者存在继承关系 41 | try: 42 | urllib.request.urlopen(request, timeout=10) 43 | except urllib.error.HTTPError as e: 44 | print(e.code, e.reason) 45 | except urllib.error.URLError as e: 46 | print(e.errno, e.reason) 47 | 48 | 49 | # 使用代理,以防止IP被封或IP次数受限: 50 | proxy_handler = urllib.request.ProxyHandler(proxies={"http": "111.123.76.12:8080"}) 51 | 52 | opener = urllib.request.build_opener(proxy_handler) # 利用代理创建opener实例 53 | response = opener.open(url) # 直接利用opener实例打开url 54 | 55 | urllib.request.install_opener(opener) # 安装全局opener,然后利用urlopen打开url 56 | response = urllib.request.urlopen(url) 57 | 58 | 59 | # 使用cookie和cookiejar,应对服务器检查 60 | cookie_jar = http.cookiejar.CookieJar() 61 | cookie_jar_handler = urllib.request.HTTPCookieProcessor(cookiejar=cookie_jar) 62 | opener = urllib.request.build_opener(cookie_jar_handler) 63 | response = opener.open(url) 64 | 65 | 66 | # 发送在浏览器中获取的cookie,两种方式: 67 | # (1)直接放到headers里 68 | headers = { 69 | "User-Agent": "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT)", 70 | "Cookie": "PHPSESSID=btqkg9amjrtoeev8coq0m78396; USERINFO=n6nxTHTY%2BJA39z6CpNB4eKN8f0KsYLjAQTwPe%2BhLHLruEbjaeh4ulhWAS5RysUM%2B; " 71 | } 72 | request = urllib.request.Request(url, headers=headers) 73 | 74 | # (2)构建cookie,添加到cookiejar中 75 | cookie = http.cookiejar.Cookie(name="xx", value="xx", domain="xx", ...) 76 | cookie_jar.set_cookie(cookie) 77 | response = opener.open(url) 78 | 79 | 80 | # 同时使用代理和cookiejar 81 | opener = urllib.request.build_opener(cookie_jar_handler) 82 | opener.add_handler(proxy_handler) 83 | response = opener.open("https://www.baidu.com/") 84 | 85 | 86 | # 抓取网页中的图片:同样适用于抓取网络上的文件。右击鼠标,找到图片属性中的地址,然后进行保存。 87 | response = urllib.request.urlopen("http://ww3.sinaimg.cn/large/7d742c99tw1ee7dac2766j204q04qmxq.jpg", timeout=120) 88 | with open("test.jpg", "wb") as file_img: 89 | file_img.write(response.read()) 90 | 91 | 92 | # HTTP认证:即HTTP身份验证 93 | password_mgr = urllib.request.HTTPPasswordMgrWithDefaultRealm() # 创建一个PasswordMgr 94 | password_mgr.add_password(realm=None, uri=url, user='username', passwd='password') # 添加用户名和密码 95 | handler = urllib.request.HTTPBasicAuthHandler(password_mgr) # 创建HTTPBasicAuthHandler 96 | opener = urllib.request.build_opener(handler) # 创建opner 97 | response = opener.open(url, timeout=10) # 获取数据 98 | 99 | 100 | # 使用Sockets代理 101 | import socks 102 | import socket 103 | 104 | socks.setdefaultproxy(socks.PROXY_TYPE_SOCKS5, "127.0.0.1", 1080) 105 | socket.socket =socks.socksocket 106 | requests.get("http://www.baidu.com/s?ie=utf-8&wd=ip") 107 | -------------------------------------------------------------------------------- /python_splash.py: -------------------------------------------------------------------------------- 1 | # _*_ coding: utf-8 _*_ 2 | 3 | """ 4 | 使用Splash服务器抓取Ajax渲染页面 5 | """ 6 | 7 | import json 8 | import requests 9 | 10 | # Docker安装: https://splash.readthedocs.io/en/latest/install.html 11 | CRAWLER_URL = "http://weixin.sogou.com/weixin?page=1&type=2&query=%E4%B8%AD%E5%9B%BD" 12 | 13 | 14 | # render.html 15 | def test_1(url): 16 | render = "http://xx.xx.xx.xx:8050/render.html" 17 | body = json.dumps({ 18 | "url": url, 19 | "wait": 0.5, # 设定页面加载等待时间 20 | "images": 0, # 是否抓取图片 21 | "timeout": 3, # 设置过期时间 22 | # "allowed_domains": ["sogou.com", ], # 设置允许的域 23 | "allowed_content_types": "text/html; charset=utf-8" 24 | }) 25 | headers = {"Content-Type": "application/json"} 26 | 27 | response = requests.post(url=render, headers=headers, data=body) 28 | print(url, response.status_code) 29 | print(response.text) 30 | return 31 | 32 | # test_1(CRAWLER_URL) 33 | 34 | 35 | # render.png 36 | def test_2(url): 37 | render = "http://xx.xx.xx.xx:8050/render.png?url=%s&timeout=5" % url 38 | response = requests.get(url=render) 39 | print(url, response.status_code) 40 | return 41 | 42 | # test_2(CRAWLER_URL) 43 | -------------------------------------------------------------------------------- /python_sqlalchemy.py: -------------------------------------------------------------------------------- 1 | # _*_ coding: utf-8 _*_ 2 | 3 | """ 4 | python_sqlalchemy.py by xianhu 5 | """ 6 | 7 | import sqlalchemy 8 | import sqlalchemy.orm 9 | import sqlalchemy.ext.declarative 10 | 11 | # 利用数据库字符串构造engine, echo为True将打印所有的sql语句, 其他数据库的链接方式可自行百度 12 | # engine = sqlalchemy.create_engine("mysql+pymysql://username:password@hostname/dbname", encoding="utf8", echo=True) 13 | engine = sqlalchemy.create_engine("mysql+pymysql://dba_0:mimadba_0@101.200.174.172/data_secret", encoding="utf8", echo=False) 14 | 15 | """ 16 | # 利用engine创建connection,因为使用了with所以不需要close操作,这部分不是重点 17 | with engine.connect() as conn: 18 | # 最基础的用法 19 | result = conn.execute("select * from tablename limit 10;") 20 | for item in result: 21 | print(item) 22 | 23 | # execute的几种用法,这里具体还是得参考pymysql的用法,不需要执行commit操作 24 | conn.execute("insert into tablename(id, url, title) values(1, 'url1', 'title1');") 25 | conn.execute("insert into tablename(id, url, title) values(%s, %s, %s);", 2, "url2", "title2") 26 | conn.execute("insert into tablename(id, url, title) values(%s, %s, %s)", (3, "url3", "title3")) 27 | conn.execute("insert into tablename(id, url, title) values(%s, %s, %s)", [(31, "url31", "title31"), (32, "url32", "title32")]) 28 | 29 | # 使用事务可以进行批量提交和回滚 30 | trans = conn.begin() 31 | try: 32 | conn.execute("insert into tablename(id, url, title) values(%s, %s, %s)", [(4, "url4", "title4"), (5, "url5", "title5")]) 33 | trans.commit() 34 | except Exception as excep: 35 | trans.rollback() 36 | raise 37 | trans.close() 38 | """ 39 | 40 | # 首先需要生成一个BaseModel类,作为所有模型类的基类 41 | BaseModel = sqlalchemy.ext.declarative.declarative_base() 42 | 43 | 44 | # 构建数据模型User 45 | class User(BaseModel): 46 | __tablename__ = "Users" # 表名 47 | __table_args__ = { 48 | "mysql_engine": "InnoDB", # 表的引擎 49 | "mysql_charset": "utf8", # 表的编码格式 50 | } 51 | 52 | # 表结构,具体更多的数据类型自行百度 53 | id = sqlalchemy.Column("id", sqlalchemy.Integer, primary_key=True, autoincrement=True) 54 | name = sqlalchemy.Column("name", sqlalchemy.String(50), nullable=False) 55 | age = sqlalchemy.Column("age", sqlalchemy.Integer, default=0) 56 | 57 | # 添加角色id外键,关联到表Roles的id属性 58 | role_id = sqlalchemy.Column("role_id", sqlalchemy.Integer, sqlalchemy.ForeignKey("Roles.id")) 59 | 60 | # 添加关系属性,关联到本实例的role_id外键属性上 61 | role = sqlalchemy.orm.relationship("Role", foreign_keys="User.role_id") 62 | 63 | # 添加关系属性,关联到本实例的role_id外键属性上,如果使用了这种方式,Role模型中的users可以省略 64 | # role = sqlalchemy.orm.relationship("Role", foreign_keys="User.role_id", backref=sqlalchemy.orm.backref("users")) 65 | 66 | 67 | # 构建数据模型Role 68 | class Role(BaseModel): 69 | __tablename__ = "Roles" # 表名 70 | __table_args__ = { 71 | "mysql_engine": "InnoDB", # 表的引擎 72 | "mysql_charset": "utf8", # 表的编码格式 73 | } 74 | 75 | # 表结构,具体更多的数据类型自行百度 76 | id = sqlalchemy.Column("id", sqlalchemy.Integer, primary_key=True) 77 | name = sqlalchemy.Column("name", sqlalchemy.String(50), unique=True) 78 | 79 | # 添加关系属性,关联到实例User的role_id外键属性上 80 | users = sqlalchemy.orm.relationship("User", foreign_keys="User.role_id") 81 | 82 | 83 | # 利用Session对象连接数据库 84 | DBSessinon = sqlalchemy.orm.sessionmaker(bind=engine) # 创建会话类 85 | session = DBSessinon() # 创建会话对象 86 | 87 | 88 | # 删除所有表 89 | BaseModel.metadata.drop_all(engine) 90 | # 创建所有表,如果表已经存在,则不会创建 91 | BaseModel.metadata.create_all(engine) 92 | 93 | try: 94 | # 清空数据,不需要commit操作 95 | session.query(User).filter(User.id != -1).delete() 96 | session.query(Role).filter(Role.id != -1).delete() 97 | # 删除数据的另外一种形式:session.delete() 98 | 99 | # 插入数据,这里的一个实例只插入一次,第二次插入不生效 100 | session.add(Role(id=1, name="student")) 101 | session.add(Role(id=2, name="teacher")) 102 | session.commit() 103 | 104 | session.add(User(name="James", age=20, role_id=1)) 105 | session.add(User(name="Wade", age=40, role_id=2)) 106 | session.commit() 107 | 108 | user = User(name="Kobe", age=24, role_id=1) 109 | session.add(user) 110 | session.commit() 111 | 112 | # 修改数据 113 | user.name = "Allen" 114 | session.merge(user) # 使用merge方法,如果存在则修改,如果不存在则插入 115 | session.query(User).filter(User.id == user.id).update({User.name: "Allen"}) # 使用update方法 116 | session.query(User).filter(User.id == user.id).update({User.age: User.age + 1}) # 使用update方法,自增操作 117 | 118 | # 查询数据 119 | roles = session.query(Role) # 返回全部结果 120 | for role in roles: 121 | print("Role:", role.id, role.name) 122 | 123 | users = session.query(User) # 返回全部结果 124 | for user in users: 125 | print("User:", user.id, user.name, user.age, user.role_id) 126 | 127 | # 其他获取数据的方式 128 | print("get(id):", session.query(User).get(1)) # 返回结果集中id为1的项 129 | print("get[1:3]:", session.query(User)[1:3]) # 返回结果集中的第2-3项 130 | 131 | # 其他高级查询,这里以Users表为例 132 | users = session.query(User).filter(User.id > 6) # 条件查询 133 | users = session.query(User).filter(User.id > 6).all() # 条件查询,返回查询的全部数据 134 | user = session.query(User).filter(User.id > 6).first() # 条件查询,返回查询数据的第一项 135 | users = session.query(User).filter(User.id > 6).limit(10) # 条件查询,返回最多10条数据 136 | users = session.query(User).filter(User.id > 6).offset(2) # 条件查询,从第3条数据开始返回 137 | 138 | users = session.query(User).filter(User.id > 6, User.name == "Kobe") # 条件查询,and操作 139 | users = session.query(User).filter(User.id > 6).filter(User.name == "Kobe") # 条件查询,and操作 140 | users = session.query(User).filter(sqlalchemy.or_(User.id > 6, User.name == "Kobe")) # 条件查询,or操作 141 | users = session.query(User).filter(User.id.in_((1, 2))) # 条件查询,in操作 142 | users = session.query(User).filter(sqlalchemy.not_(User.name)) # 条件查询,not操作 143 | 144 | user_count = session.query(User.id).count() # 统计全部user的数量 145 | user_count = session.query(sqlalchemy.func.count(User.id)).scalar() # scalar操作返回第一行数据的第一个字段 146 | session.query(sqlalchemy.func.count("*")).select_from(User).scalar() # scalar操作返回第一行数据的第一个字段 147 | session.query(sqlalchemy.func.count(1)).select_from(User).scalar() # scalar操作返回第一行数据的第一个字段 148 | session.query(sqlalchemy.func.count(User.id)).filter(User.id > 0).scalar() # filter() 中包含 User,因此不需要指定表 149 | 150 | session.query(sqlalchemy.func.sum(User.age)).scalar() # 求和运算,运用scalar函数 151 | session.query(sqlalchemy.func.avg(User.age)).scalar() # 求均值运算,运用scalar函数 152 | session.query(sqlalchemy.func.md5(User.name)).filter(User.id == 1).scalar() # 运用md5函数 153 | 154 | users = session.query(sqlalchemy.distinct(User.name)) # 去重查询,根据name进行去重 155 | users = session.query(User).order_by(User.name) # 排序查询,正序查询 156 | users = session.query(User).order_by(User.name.desc()) # 排序查询,倒序查询 157 | users = session.query(User).order_by(sqlalchemy.desc(User.name)) # 排序查询,倒序查询的另外一种形式 158 | 159 | users = session.query(User.id, User.name) # 只查询部分属性 160 | users = session.query(User.name.label("user_name")) # 结果集的列取别名 161 | for user in users: 162 | print("label test:", user.user_name) # 这里使用别名 163 | 164 | users = session.query(sqlalchemy.func.count(User.name).label("count"), User.age).group_by(User.age) # 分组查询 165 | for user in users: 166 | print("age:{0}, count:{1}".format(user.age, user.count)) 167 | 168 | # 多表查询 169 | result = session.query(User, Role).filter(User.role_id == Role.id) 170 | for user, role in result: 171 | print("user %s's role is %s" % (user.name, role.name)) 172 | users = session.query(User).join(Role, User.role_id == Role.id) 173 | for user in users: 174 | print("user join, name:", user.name) 175 | 176 | # 关联属性的用法 177 | roles = session.query(Role) 178 | for role in roles: 179 | print("role:%s users:" % role.name) 180 | for user in role.users: 181 | print("\t%s" % user.name) 182 | users = session.query(User) 183 | for user in users: 184 | print("user %s's role is %s" % (user.name, user.role.name)) 185 | 186 | except Exception as excep: 187 | session.rollback() 188 | raise 189 | 190 | session.close() 191 | -------------------------------------------------------------------------------- /python_thread_multiprocess.py: -------------------------------------------------------------------------------- 1 | # _*_ coding: utf-8 _*_ 2 | 3 | """ 4 | python_thread_multiprocee.py by xianhu 5 | """ 6 | 7 | import time 8 | import threading 9 | import multiprocessing 10 | 11 | # 定义全局变量Queue 12 | g_queue = multiprocessing.Queue() 13 | g_search_list = list(range(10000)) 14 | 15 | 16 | # 定义一个IO密集型任务:利用time.sleep() 17 | def task_io(task_id): 18 | print("IOTask[%s] start" % task_id) 19 | while not g_queue.empty(): 20 | time.sleep(1) 21 | try: 22 | data = g_queue.get(block=True, timeout=1) 23 | print("IOTask[%s] get data: %s" % (task_id, data)) 24 | except Exception as excep: 25 | print("IOTask[%s] error: %s" % (task_id, str(excep))) 26 | print("IOTask[%s] end" % task_id) 27 | return 28 | 29 | 30 | # 定义一个计算密集型任务:利用一些复杂加减乘除、列表查找等 31 | def task_cpu(task_id): 32 | print("CPUTask[%s] start" % task_id) 33 | while not g_queue.empty(): 34 | count = 0 35 | for i in range(10000): 36 | count += pow(3*2, 3*2) if i in g_search_list else 0 37 | try: 38 | data = g_queue.get(block=True, timeout=1) 39 | print("CPUTask[%s] get data: %s" % (task_id, data)) 40 | except Exception as excep: 41 | print("CPUTask[%s] error: %s" % (task_id, str(excep))) 42 | print("CPUTask[%s] end" % task_id) 43 | return task_id 44 | 45 | 46 | def init_queue(): 47 | print("init g_queue start") 48 | while not g_queue.empty(): 49 | g_queue.get() 50 | for _index in range(10): 51 | g_queue.put(_index) 52 | print("init g_queue end") 53 | return 54 | 55 | 56 | if __name__ == '__main__': 57 | print("cpu count:", multiprocessing.cpu_count(), "\n") 58 | 59 | print("========== 直接执行IO密集型任务 ==========") 60 | init_queue() 61 | time_0 = time.time() 62 | task_io(0) 63 | print("结束:", time.time() - time_0, "\n") 64 | 65 | print("========== 多线程执行IO密集型任务 ==========") 66 | init_queue() 67 | time_0 = time.time() 68 | thread_list = [threading.Thread(target=task_io, args=(i,)) for i in range(5)] 69 | for t in thread_list: 70 | t.start() 71 | for t in thread_list: 72 | if t.is_alive(): 73 | t.join() 74 | print("结束:", time.time() - time_0, "\n") 75 | 76 | print("========== 多进程执行IO密集型任务 ==========") 77 | init_queue() 78 | time_0 = time.time() 79 | process_list = [multiprocessing.Process(target=task_io, args=(i,)) for i in range(multiprocessing.cpu_count())] 80 | for p in process_list: 81 | p.start() 82 | for p in process_list: 83 | if p.is_alive(): 84 | p.join() 85 | print("结束:", time.time() - time_0, "\n") 86 | 87 | print("========== 直接执行CPU密集型任务 ==========") 88 | init_queue() 89 | time_0 = time.time() 90 | task_cpu(0) 91 | print("结束:", time.time() - time_0, "\n") 92 | 93 | print("========== 多线程执行CPU密集型任务 ==========") 94 | init_queue() 95 | time_0 = time.time() 96 | thread_list = [threading.Thread(target=task_cpu, args=(i,)) for i in range(5)] 97 | for t in thread_list: 98 | t.start() 99 | for t in thread_list: 100 | if t.is_alive(): 101 | t.join() 102 | print("结束:", time.time() - time_0, "\n") 103 | 104 | print("========== 多进程执行cpu密集型任务 ==========") 105 | init_queue() 106 | time_0 = time.time() 107 | process_list = [multiprocessing.Process(target=task_cpu, args=(i,)) for i in range(multiprocessing.cpu_count())] 108 | for p in process_list: 109 | p.start() 110 | for p in process_list: 111 | if p.is_alive(): 112 | p.join() 113 | print("结束:", time.time() - time_0, "\n") 114 | 115 | exit() 116 | -------------------------------------------------------------------------------- /python_version36.py: -------------------------------------------------------------------------------- 1 | # _*_ coding: utf-8 _*_ 2 | 3 | """ 4 | python_version36.py by xianhu 5 | """ 6 | 7 | import asyncio 8 | import decimal 9 | from typing import List, Dict 10 | 11 | # Formatted string literals 12 | name = "Fred" 13 | print(f"He said his name is {name}.") # 'He said his name is Fred.' 14 | print("He said his name is {name}.".format(**locals())) 15 | 16 | width = 10 17 | precision = 4 18 | value = decimal.Decimal("12.34567") 19 | print(f"result: {value:{width}.{precision}}") #'result: 12.35' 20 | 21 | 22 | # variable annotations 23 | def test(a: List[int], b: int) -> int: 24 | return a[0] + b 25 | print(test([3, 1], 2)) 26 | 27 | primes: List[int] = [] 28 | captain: str 29 | 30 | class Starship(object): 31 | stats: Dict[str, int] = {} 32 | 33 | 34 | # Underscores in Numeric Literals 35 | a = 1_000_000_000_000_000 # 1000000000000000 36 | b = 0x_FF_FF_FF_FF # 4294967295 37 | 38 | '{:_}'.format(1000000) # '1_000_000' 39 | '{:_x}'.format(0xFFFFFFFF) # 'ffff_ffff' 40 | 41 | 42 | # Asynchronous Generators 43 | async def ticker(delay, to): 44 | """Yield numbers from 0 to *to* every *delay* seconds.""" 45 | for i in range(to): 46 | yield i 47 | await asyncio.sleep(delay) 48 | 49 | 50 | # Asynchronous Comprehensions 51 | result = [i async for i in aiter() if i % 2] 52 | result = [await fun() for fun in funcs if await condition()] 53 | -------------------------------------------------------------------------------- /python_visual.py: -------------------------------------------------------------------------------- 1 | # _*_ coding: utf-8 _*_ 2 | 3 | """ 4 | python_visual.py by xianhu 5 | """ 6 | 7 | import numpy as np 8 | import matplotlib 9 | import matplotlib.mlab as mlab 10 | import matplotlib.pyplot as plt 11 | import matplotlib.font_manager as fm 12 | from mpl_toolkits.mplot3d import Axes3D 13 | 14 | # 解决中文乱码问题 15 | myfont = fm.FontProperties(fname="/Library/Fonts/Songti.ttc", size=14) 16 | matplotlib.rcParams["axes.unicode_minus"] = False 17 | 18 | 19 | def simple_plot(): 20 | """ 21 | simple plot 22 | """ 23 | # 生成测试数据 24 | x = np.linspace(-np.pi, np.pi, 256, endpoint=True) 25 | y_cos, y_sin = np.cos(x), np.sin(x) 26 | 27 | # 生成画布,并设定标题 28 | plt.figure(figsize=(8, 6), dpi=80) 29 | plt.title("简单曲线图", fontproperties=myfont) 30 | plt.grid(True) 31 | 32 | # 设置X轴 33 | plt.xlabel("X轴", fontproperties=myfont) 34 | plt.xlim(-4.0, 4.0) 35 | plt.xticks(np.linspace(-4, 4, 9, endpoint=True)) 36 | 37 | # 设置Y轴 38 | plt.ylabel("Y轴", fontproperties=myfont) 39 | plt.ylim(-1.0, 1.0) 40 | plt.yticks(np.linspace(-1, 1, 9, endpoint=True)) 41 | 42 | # 画两条曲线 43 | plt.plot(x, y_cos, "b--", linewidth=2.0, label="cos示例") 44 | plt.plot(x, y_sin, "g-", linewidth=2.0, label="sin示例") 45 | 46 | # 设置图例位置,loc可以为[upper, lower, left, right, center] 47 | plt.legend(loc="upper left", prop=myfont, shadow=True) 48 | 49 | # 图形显示 50 | plt.show() 51 | return 52 | # simple_plot() 53 | 54 | 55 | def simple_advanced_plot(): 56 | """ 57 | simple advanced plot 58 | """ 59 | # 生成测试数据 60 | x = np.linspace(-np.pi, np.pi, 256, endpoint=True) 61 | y_cos, y_sin = np.cos(x), np.sin(x) 62 | 63 | # 生成画布, 并设定标题 64 | plt.figure(figsize=(8, 6), dpi=80) 65 | plt.title("复杂曲线图", fontproperties=myfont) 66 | plt.grid(True) 67 | 68 | # 画图的另外一种方式 69 | ax_1 = plt.subplot(111) 70 | ax_1.plot(x, y_cos, color="blue", linewidth=2.0, linestyle="--", label="左cos") 71 | ax_1.legend(loc="upper left", prop=myfont, shadow=True) 72 | 73 | # 设置Y轴(左边) 74 | ax_1.set_ylabel("左cos的y轴", fontproperties=myfont) 75 | ax_1.set_ylim(-1.0, 1.0) 76 | ax_1.set_yticks(np.linspace(-1, 1, 9, endpoint=True)) 77 | 78 | # 画图的另外一种方式 79 | ax_2 = ax_1.twinx() 80 | ax_2.plot(x, y_sin, color="green", linewidth=2.0, linestyle="-", label="右sin") 81 | ax_2.legend(loc="upper right", prop=myfont, shadow=True) 82 | 83 | # 设置Y轴(右边) 84 | ax_2.set_ylabel("右sin的y轴", fontproperties=myfont) 85 | ax_2.set_ylim(-2.0, 2.0) 86 | ax_2.set_yticks(np.linspace(-2, 2, 9, endpoint=True)) 87 | 88 | # 设置X轴(共同) 89 | ax_1.set_xlabel("x轴", fontproperties=myfont) 90 | ax_1.set_xlim(-4.0, 4.0) 91 | ax_1.set_xticks(np.linspace(-4, 4, 9, endpoint=True)) 92 | 93 | # 图形显示 94 | plt.show() 95 | return 96 | # simple_advanced_plot() 97 | 98 | 99 | def subplot_plot(): 100 | """ 101 | subplot plot 102 | """ 103 | # 子图的style列表 104 | style_list = ["g+-", "r*-", "b.-", "yo-"] 105 | 106 | # 依次画图 107 | for num in range(4): 108 | # 生成测试数据 109 | x = np.linspace(0.0, 2+num, num=10*(num+1)) 110 | y = np.sin((5-num) * np.pi * x) 111 | 112 | # 子图的生成方式 113 | plt.subplot(2, 2, num+1) 114 | plt.title("子图 %d" % (num+1), fontproperties=myfont) 115 | plt.plot(x, y, style_list[num]) 116 | 117 | # 图形显示 118 | plt.show() 119 | return 120 | # subplot_plot() 121 | 122 | 123 | def bar_plot(): 124 | """ 125 | bar plot 126 | """ 127 | # 生成测试数据 128 | means_men = (20, 35, 30, 35, 27) 129 | means_women = (25, 32, 34, 20, 25) 130 | 131 | # 设置标题 132 | plt.title("柱状图", fontproperties=myfont) 133 | 134 | # 设置相关参数 135 | index = np.arange(len(means_men)) 136 | bar_width = 0.35 137 | 138 | # 画柱状图 139 | plt.bar(index, means_men, width=bar_width, alpha=0.2, color="b", label="男生") 140 | plt.bar(index+bar_width, means_women, width=bar_width, alpha=0.8, color="r", label="女生") 141 | plt.legend(loc="upper right", prop=myfont, shadow=True) 142 | 143 | # 设置柱状图标示 144 | for x, y in zip(index, means_men): 145 | plt.text(x, y+0.3, y, ha="center", va="bottom") 146 | for x, y in zip(index, means_women): 147 | plt.text(x+bar_width, y+0.3, y, ha="center", va="bottom") 148 | 149 | # 设置刻度范围/坐标轴名称等 150 | plt.ylim(0, 45) 151 | plt.xlabel("分组Group", fontproperties=myfont) 152 | plt.ylabel("得分Scores", fontproperties=myfont) 153 | plt.xticks(index+(bar_width/2), ("A组", "B组", "C组", "D组", "E组"), fontproperties=myfont) 154 | 155 | # 图形显示 156 | plt.show() 157 | return 158 | # bar_plot() 159 | 160 | 161 | def barh_plot(): 162 | """ 163 | barh plot 164 | """ 165 | # 生成测试数据 166 | means_men = (20, 35, 30, 35, 27) 167 | means_women = (25, 32, 34, 20, 25) 168 | 169 | # 设置标题 170 | plt.title("横向柱状图", fontproperties=myfont) 171 | 172 | # 设置相关参数 173 | index = np.arange(len(means_men)) 174 | bar_height = 0.35 175 | 176 | # 画柱状图(水平方向) 177 | plt.barh(index, means_men, height=bar_height, alpha=0.2, color="b", label="Men") 178 | plt.barh(index+bar_height, means_women, height=bar_height, alpha=0.8, color="r", label="Women") 179 | plt.legend(loc="upper right", shadow=True) 180 | 181 | # 设置柱状图标示 182 | for x, y in zip(index, means_men): 183 | plt.text(y+0.3, x, y, ha="left", va="center") 184 | for x, y in zip(index, means_women): 185 | plt.text(y+0.3, x+bar_height, y, ha="left", va="center") 186 | 187 | # 设置刻度范围/坐标轴名称等 188 | plt.xlim(0, 45) 189 | plt.xlabel("Scores") 190 | plt.ylabel("Group") 191 | plt.yticks(index+(bar_height/2), ("A", "B", "C", "D", "E")) 192 | 193 | # 图形显示 194 | plt.show() 195 | return 196 | # barh_plot() 197 | 198 | 199 | def bar_advanced_plot(): 200 | """ 201 | bar advanced plot 202 | """ 203 | # 生成测试数据 204 | means_men = np.array((20, 35, 30, 35, 27, 25, 32, 34, 20, 25)) 205 | means_women = np.array((25, 32, 34, 20, 25, 20, 35, 30, 35, 27)) 206 | 207 | # 设置标题 208 | plt.title("高级柱状图", fontproperties=myfont) 209 | 210 | # 设置相关参数 211 | index = np.arange(len(means_men)) 212 | bar_width = 0.8 213 | 214 | # 画柱状图(两种:X轴以上/X轴以下) 215 | plt.bar(index, means_men, width=bar_width, alpha=0.4, color="b", label="Men") 216 | plt.bar(index, -means_women, width=bar_width, alpha=0.4, color="r", label="Women") 217 | 218 | # 画折线图(两种,和柱状图对应) 219 | plt.plot(index, means_men, marker="o", linestyle="-", color="r", label="Men line") 220 | plt.plot(index, -means_women, marker=".", linestyle="--", color="b", label="Women line") 221 | 222 | # 设置图形标示(两种,和柱状图对应) 223 | for x, y in zip(index, means_men): 224 | plt.text(x, y+1, y, ha="center", va="bottom") 225 | for x, y in zip(index, means_women): 226 | plt.text(x, -y-1, y, ha="center", va="top") 227 | 228 | # 设置Y轴和图例位置 229 | plt.ylim(-45, 80) 230 | plt.legend(loc="upper left", shadow=True) 231 | 232 | # 图形显示 233 | plt.show() 234 | return 235 | # bar_advanced_plot() 236 | 237 | 238 | def table_plot(): 239 | """ 240 | table plot 241 | """ 242 | # 生成测试数据 243 | data = np.array([ 244 | [1, 4, 2, 5, 2], 245 | [2, 1, 1, 3, 6], 246 | [5, 3, 6, 4, 1] 247 | ]) 248 | 249 | # 设置标题 250 | plt.title("层次柱状图", fontproperties=myfont) 251 | 252 | # 设置相关参数 253 | index = np.arange(len(data[0])) 254 | color_index = ["r", "g", "b"] 255 | 256 | # 声明底部位置 257 | bottom = np.array([0, 0, 0, 0, 0]) 258 | 259 | # 依次画图,并更新底部位置 260 | for i in range(len(data)): 261 | plt.bar(index, data[i], width=0.5, color=color_index[i], bottom=bottom, alpha=0.7, label="标签 %d" % i) 262 | bottom += data[i] 263 | 264 | # 设置图例位置 265 | plt.legend(loc="upper left", prop=myfont, shadow=True) 266 | 267 | # 图形显示 268 | plt.show() 269 | return 270 | # table_plot() 271 | 272 | 273 | def histograms_plot(): 274 | """ 275 | histograms plot 276 | """ 277 | # 生成测试数据 278 | mu, sigma = 100, 15 279 | x = mu + sigma * np.random.randn(10000) 280 | 281 | # 设置标题 282 | plt.title("直方图", fontproperties=myfont) 283 | 284 | # 画直方图, 并返回相关结果 285 | n, bins, patches = plt.hist(x, bins=50, normed=1, cumulative=False, color="green", alpha=0.6, label="直方图") 286 | 287 | # 根据直方图返回的结果, 画折线图 288 | y = mlab.normpdf(bins, mu, sigma) 289 | plt.plot(bins, y, "r--", label="线条") 290 | 291 | # 设置图例位置 292 | plt.legend(loc="upper left", prop=myfont, shadow=True) 293 | 294 | # 图形显示 295 | plt.show() 296 | return 297 | # histograms_plot() 298 | 299 | 300 | def pie_plot(): 301 | """ 302 | pie plot 303 | """ 304 | # 生成测试数据 305 | sizes = [15, 30, 45, 10] 306 | labels = ["Frogs", "中文", "Dogs", "Logs"] 307 | colors = ["yellowgreen", "gold", "lightskyblue", "lightcoral"] 308 | 309 | # 设置标题 310 | plt.title("饼图", fontproperties=myfont) 311 | 312 | # 设置突出参数 313 | explode = [0, 0.05, 0, 0] 314 | 315 | # 画饼状图 316 | patches, l_text, p_text = plt.pie(sizes, explode=explode, labels=labels, colors=colors, autopct="%1.1f%%", shadow=True, startangle=90) 317 | for text in l_text: 318 | text.set_fontproperties(myfont) 319 | plt.axis("equal") 320 | 321 | # 图形显示 322 | plt.show() 323 | return 324 | # pie_plot() 325 | 326 | 327 | def scatter_plot(): 328 | """ 329 | scatter plot 330 | """ 331 | # 生成测试数据 332 | point_count = 1000 333 | x_index = np.random.random(point_count) 334 | y_index = np.random.random(point_count) 335 | 336 | # 设置标题 337 | plt.title("散点图", fontproperties=myfont) 338 | 339 | # 设置相关参数 340 | color_list = np.random.random(point_count) 341 | scale_list = np.random.random(point_count) * 100 342 | 343 | # 画散点图 344 | plt.scatter(x_index, y_index, s=scale_list, c=color_list, marker="o") 345 | 346 | # 图形显示 347 | plt.show() 348 | return 349 | # scatter_plot() 350 | 351 | 352 | def fill_plot(): 353 | """ 354 | fill plot 355 | """ 356 | # 生成测试数据 357 | x = np.linspace(-2*np.pi, 2*np.pi, 1000, endpoint=True) 358 | y = np.sin(x) 359 | 360 | # 设置标题 361 | plt.title("填充图", fontproperties=myfont) 362 | 363 | # 画图 364 | plt.plot(x, y, color="blue", alpha=1.00) 365 | 366 | # 填充图形, plt.fill_between(x, y1, y2, where=None, *kwargs) 367 | plt.fill_between(x, 0, y, where=(y > 0), color="blue", alpha=0.25) 368 | plt.fill_between(x, 0, y, where=(y < 0), color="red", alpha=0.25) 369 | 370 | # 图形显示 371 | plt.show() 372 | return 373 | # fill_plot() 374 | 375 | 376 | def radar_plot(): 377 | """ 378 | radar plot 379 | """ 380 | # 生成测试数据 381 | labels = np.array(["A组", "B组", "C组", "D组", "E组", "F组"]) 382 | data = np.array([68, 83, 90, 77, 89, 73]) 383 | theta = np.linspace(0, 2*np.pi, len(data), endpoint=False) 384 | 385 | # 数据预处理 386 | data = np.concatenate((data, [data[0]])) 387 | theta = np.concatenate((theta, [theta[0]])) 388 | 389 | # 画图方式 390 | plt.subplot(111, polar=True) 391 | plt.title("雷达图", fontproperties=myfont) 392 | 393 | # 设置"theta grid"/"radar grid" 394 | plt.thetagrids(theta*(180/np.pi), labels=labels, fontproperties=myfont) 395 | plt.rgrids(np.arange(20, 100, 20), labels=np.arange(20, 100, 20), angle=0) 396 | plt.ylim(0, 100) 397 | 398 | # 画雷达图,并填充雷达图内部区域 399 | plt.plot(theta, data, "bo-", linewidth=2) 400 | plt.fill(theta, data, color="red", alpha=0.25) 401 | 402 | # 图形显示 403 | plt.show() 404 | return 405 | # radar_plot() 406 | 407 | 408 | def three_dimension_scatter(): 409 | """ 410 | 3d scatter plot 411 | """ 412 | # 生成测试数据 413 | x = np.random.random(100) 414 | y = np.random.random(100) 415 | z = np.random.random(100) 416 | color = np.random.random(100) 417 | scale = np.random.random(100) * 100 418 | 419 | # 生成画布(两种形式) 420 | fig = plt.figure() 421 | fig.suptitle("三维散点图", fontproperties=myfont) 422 | 423 | # ax = fig.gca(projection="3d") 424 | ax = fig.add_subplot(111, projection="3d") 425 | 426 | # 画三维散点图 427 | ax.scatter(x, y, z, s=scale, c=color, marker=".") 428 | 429 | # 设置坐标轴图标 430 | ax.set_xlabel("X Label") 431 | ax.set_ylabel("Y Label") 432 | ax.set_zlabel("Z Label") 433 | 434 | # 设置坐标轴范围 435 | ax.set_xlim(0, 1) 436 | ax.set_ylim(0, 1) 437 | ax.set_zlim(0, 1) 438 | 439 | # 图形显示 440 | plt.show() 441 | return 442 | # three_dimension_scatter() 443 | 444 | 445 | def three_dimension_line(): 446 | """ 447 | 3d line plot 448 | """ 449 | # 生成测试数据 450 | x = np.linspace(0, 1, 1000) 451 | y = np.linspace(0, 1, 1000) 452 | z = np.sin(x * 2 * np.pi) / (y + 0.1) 453 | 454 | # 生成画布(两种形式) 455 | fig = plt.figure() 456 | ax = fig.gca(projection="3d", title="plot title") 457 | # ax = fig.add_subplot(111, projection="3d", title="plot title") 458 | 459 | # 画三维折线图 460 | ax.plot(x, y, z, color="red", linestyle="-") 461 | 462 | # 设置坐标轴图标 463 | ax.set_xlabel("X Label") 464 | ax.set_ylabel("Y Label") 465 | ax.set_zlabel("Z Label") 466 | 467 | # 图形显示 468 | plt.show() 469 | return 470 | # three_dimension_line() 471 | 472 | 473 | def three_dimension_bar(): 474 | """ 475 | 3d bar plot 476 | """ 477 | # 生成测试数据(位置数据) 478 | xpos = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] 479 | ypos = [2, 3, 4, 5, 1, 6, 2, 1, 7, 2] 480 | zpos = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0] 481 | 482 | # 生成测试数据(柱形参数) 483 | dx = [1, 1, 1, 1, 1, 1, 1, 1, 1, 1] 484 | dy = [1, 1, 1, 1, 1, 1, 1, 1, 1, 1] 485 | dz = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] 486 | 487 | # 生成画布(两种形式) 488 | fig = plt.figure() 489 | ax = fig.gca(projection="3d", title="plot title") 490 | 491 | # 画三维柱状图 492 | ax.bar3d(xpos, ypos, zpos, dx, dy, dz, alpha=0.5) 493 | 494 | # 设置坐标轴图标 495 | ax.set_xlabel("X Label") 496 | ax.set_ylabel("Y Label") 497 | ax.set_zlabel("Z Label") 498 | 499 | # 图形显示 500 | plt.show() 501 | return 502 | # three_dimension_bar() 503 | -------------------------------------------------------------------------------- /python_visual_animation.py: -------------------------------------------------------------------------------- 1 | # _*_ coding: utf-8 _*_ 2 | 3 | """ 4 | python_visual_animation.py by xianhu 5 | """ 6 | 7 | import numpy as np 8 | import matplotlib 9 | import matplotlib.pyplot as plt 10 | import matplotlib.font_manager as fm 11 | from mpl_toolkits.mplot3d import Axes3D 12 | 13 | # 解决中文乱码问题 14 | myfont = fm.FontProperties(fname="/Library/Fonts/Songti.ttc", size=14) 15 | matplotlib.rcParams["axes.unicode_minus"] = False 16 | 17 | 18 | def simple_plot(): 19 | """ 20 | simple plot 21 | """ 22 | # 生成画布 23 | plt.figure(figsize=(8, 6), dpi=80) 24 | 25 | # 打开交互模式 26 | plt.ion() 27 | 28 | # 循环 29 | for index in range(100): 30 | # 清除原有图像 31 | plt.cla() 32 | 33 | # 设定标题等 34 | plt.title("动态曲线图", fontproperties=myfont) 35 | plt.grid(True) 36 | 37 | # 生成测试数据 38 | x = np.linspace(-np.pi + 0.1*index, np.pi+0.1*index, 256, endpoint=True) 39 | y_cos, y_sin = np.cos(x), np.sin(x) 40 | 41 | # 设置X轴 42 | plt.xlabel("X轴", fontproperties=myfont) 43 | plt.xlim(-4 + 0.1*index, 4 + 0.1*index) 44 | plt.xticks(np.linspace(-4 + 0.1*index, 4+0.1*index, 9, endpoint=True)) 45 | 46 | # 设置Y轴 47 | plt.ylabel("Y轴", fontproperties=myfont) 48 | plt.ylim(-1.0, 1.0) 49 | plt.yticks(np.linspace(-1, 1, 9, endpoint=True)) 50 | 51 | # 画两条曲线 52 | plt.plot(x, y_cos, "b--", linewidth=2.0, label="cos示例") 53 | plt.plot(x, y_sin, "g-", linewidth=2.0, label="sin示例") 54 | 55 | # 设置图例位置,loc可以为[upper, lower, left, right, center] 56 | plt.legend(loc="upper left", prop=myfont, shadow=True) 57 | 58 | # 暂停 59 | plt.pause(0.1) 60 | 61 | # 关闭交互模式 62 | plt.ioff() 63 | 64 | # 图形显示 65 | plt.show() 66 | return 67 | # simple_plot() 68 | 69 | 70 | def scatter_plot(): 71 | """ 72 | scatter plot 73 | """ 74 | # 打开交互模式 75 | plt.ion() 76 | 77 | # 循环 78 | for index in range(50): 79 | # 清除原有图像 80 | # plt.cla() 81 | 82 | # 设定标题等 83 | plt.title("动态散点图", fontproperties=myfont) 84 | plt.grid(True) 85 | 86 | # 生成测试数据 87 | point_count = 5 88 | x_index = np.random.random(point_count) 89 | y_index = np.random.random(point_count) 90 | 91 | # 设置相关参数 92 | color_list = np.random.random(point_count) 93 | scale_list = np.random.random(point_count) * 100 94 | 95 | # 画散点图 96 | plt.scatter(x_index, y_index, s=scale_list, c=color_list, marker="o") 97 | 98 | # 暂停 99 | plt.pause(0.2) 100 | 101 | # 关闭交互模式 102 | plt.ioff() 103 | 104 | # 显示图形 105 | plt.show() 106 | return 107 | # scatter_plot() 108 | 109 | 110 | def three_dimension_scatter(): 111 | """ 112 | 3d scatter plot 113 | """ 114 | # 生成画布 115 | fig = plt.figure() 116 | 117 | # 打开交互模式 118 | plt.ion() 119 | 120 | # 循环 121 | for index in range(50): 122 | # 清除原有图像 123 | fig.clf() 124 | 125 | # 设定标题等 126 | fig.suptitle("三维动态散点图", fontproperties=myfont) 127 | 128 | # 生成测试数据 129 | point_count = 100 130 | x = np.random.random(point_count) 131 | y = np.random.random(point_count) 132 | z = np.random.random(point_count) 133 | color = np.random.random(point_count) 134 | scale = np.random.random(point_count) * 100 135 | 136 | # 生成画布 137 | ax = fig.add_subplot(111, projection="3d") 138 | 139 | # 画三维散点图 140 | ax.scatter(x, y, z, s=scale, c=color, marker=".") 141 | 142 | # 设置坐标轴图标 143 | ax.set_xlabel("X Label") 144 | ax.set_ylabel("Y Label") 145 | ax.set_zlabel("Z Label") 146 | 147 | # 设置坐标轴范围 148 | ax.set_xlim(0, 1) 149 | ax.set_ylim(0, 1) 150 | ax.set_zlim(0, 1) 151 | 152 | # 暂停 153 | plt.pause(0.2) 154 | 155 | # 关闭交互模式 156 | plt.ioff() 157 | 158 | # 图形显示 159 | plt.show() 160 | return 161 | # three_dimension_scatter() 162 | -------------------------------------------------------------------------------- /python_wechat.py: -------------------------------------------------------------------------------- 1 | # _*_ coding: utf-8 _*_ 2 | 3 | """ 4 | python_wechat.py by xianhu 5 | 主要包括如下功能: 6 | (1) 自动提醒群红包 7 | (2) 自动监测被撤回消息 8 | (3) 群关键字提醒,群被@提醒 9 | """ 10 | 11 | import time 12 | import itchat 13 | import logging 14 | from itchat.content import * 15 | 16 | # 初始化 17 | my = itchat.new_instance() 18 | my.auto_login(hotReload=False, enableCmdQR=2) 19 | 20 | # my还包括的以下属性,注意用点.查看: 21 | # (1) alive 是否还活着,isLogging 是否已登陆 22 | # (2) loginInfo 登陆信息,其中的User属性为自己的信息User字典类,包括UserName, NickName, RemarkName, Sex(1 or 2), Signature, Province, City等 23 | # (3) memberList 通讯录列表,每一项为一个User字典类,包括UserName, NickName, RemarkName, Sex(1 or 2), Signature, Province, City等 24 | # (4) chatroomList 群聊列表,每一项为一个Chatroom字典类,包括UserName, NickName, RemarkName, MemberCount, MemberList, Self等 25 | # (5) mpList 订阅号列表,每一项为一个MassivePlatform字典类,包括UserName, NickName等 26 | 27 | my.global_keys = ["创业", "人工智能", "企业服务"] 28 | my.to_user_name = "filehelper" # 消息接受者 29 | my.update_time = time.time() # 信息更新时间 30 | my.msg_store = {} # 消息存储队列 31 | my.friends = {} # 好友字典列表 32 | my.groups = {} # 群聊字典列表 33 | 34 | 35 | def update_my_infos(): 36 | """ 37 | 更新信息 38 | """ 39 | # 获取并更新通讯录: {UserName: UserInstance} 40 | my.friends = {user["UserName"]: user for user in my.get_friends(update=True)} 41 | # 获取并更新群列表: {UserName: UserInstance} 42 | my.groups = {group["UserName"]: group for group in my.get_chatrooms(update=True)} 43 | return 44 | update_my_infos() 45 | 46 | 47 | class Message(object): 48 | """ 49 | 消息类 50 | """ 51 | def __init__(self, msg): 52 | """ 53 | 构造函数:提取消息内容 54 | 消息来源分类: 55 | (1)来自好友的消息 56 | (2)来自群的消息 57 | 提取消息内容,消息类型分类: 58 | (1)文字(2)图片(3)语音(4)视频(5)地址(6)名片(7)提醒(8)分享(9)附件 59 | """ 60 | # 更新信息,十分钟更新一次 61 | # logging.warning("message: %s", msg) 62 | if time.time() - my.update_time > 600: 63 | update_my_infos() 64 | my.update_time = time.time() 65 | 66 | self.msg_id = msg["MsgId"] # 消息ID 67 | self.from_user_name = msg["FromUserName"] # 消息发送者ID,如果为群消息,则为群ID 68 | 69 | self.msg_type = msg["MsgType"] # 消息类型,这里参考下边的we_type 70 | self.msg_content = msg["Content"] # 消息内容,这里参考下边的we_text 71 | self.msg_time = msg["CreateTime"] # 消息发送时间,时间戳格式 72 | 73 | self.msg_file = msg["FileName"] # 消息中所带文件的名称 74 | self.msg_file_length = msg["FileSize"] # 消息中所带文件的大小,字符串类型 75 | self.msg_voice_length = msg["VoiceLength"] # 消息中所带语音的长度(毫秒) 76 | self.msg_play_length = msg["PlayLength"] # 消息中所带视频的长度(秒) 77 | self.msg_url = msg["Url"] # 消息中所带链接的地址 78 | 79 | self.user_user_name = msg["User"].get("UserName", "") # 消息发送者ID,如果为群消息,则为群ID 80 | self.user_nick_name = msg["User"].get("NickName", "") # 消息发送者昵称,如果为群消息,则为群名 81 | self.user_remark_name = msg["User"].get("RemarkName", "") # 消息发送者备注名称,如果为群消息,则为群备注名称 82 | self.wind_name = self.user_remark_name if self.user_remark_name else ( 83 | self.user_nick_name if self.user_nick_name else ( 84 | my.friends[self.user_user_name]["NickName"] if self.user_user_name in my.friends else ( 85 | my.groups[self.user_user_name]["NickName"] if self.user_user_name in my.groups else "未知窗口" 86 | ) 87 | ) 88 | ) 89 | 90 | self.actual_user_name = msg.get("ActualUserName", "") # 群消息中,消息发送者的ID 91 | self.actual_nick_name = msg.get("ActualNickName", "") # 群消息中,消息发送者的群昵称 92 | self.actual_remark_name = self.actual_nick_name \ 93 | if (self.actual_user_name not in my.friends) or (not my.friends[self.actual_user_name]["RemarkName"]) \ 94 | else my.friends[self.actual_user_name]["RemarkName"] 95 | 96 | self.is_at = msg.get("IsAt", None) # 是否在群内被@ 97 | self.we_type = msg["Type"] # 消息类型 98 | self.we_text = msg["Text"] # 消息内容 99 | 100 | logging.warning("wind_name=%s, send_name=%s, we_type=%s, we_text=%s", self.wind_name, self.actual_remark_name, self.we_type, self.we_text) 101 | return 102 | 103 | 104 | def process_message_group(msg): 105 | """ 106 | 处理群消息 107 | """ 108 | # ==== 处理红包消息 ==== 109 | if msg.we_type == "Note" and msg.we_text.find("收到红包,请在手机上查看") >= 0: 110 | my.send("【%s】中有人发红包啦,快抢!" % msg.wind_name, toUserName=my.to_user_name) 111 | 112 | # ==== 处理关键词消息 ==== 113 | for key in my.global_keys: 114 | if msg.we_type == "Text" and msg.we_text.find(key) >= 0: 115 | my.send("【%s】中【%s】提及了关键字:%s" % (msg.wind_name, msg.actual_remark_name, key), toUserName=my.to_user_name) 116 | my.send(msg.we_text, toUserName=my.to_user_name) 117 | break 118 | 119 | # ==== 群内是否被@ ==== 120 | if msg.we_type == "Text" and msg.is_at: 121 | my.send("【%s】中【%s】@了你" % (msg.wind_name, msg.actual_remark_name), toUserName=my.to_user_name) 122 | my.send(msg.we_text, toUserName=my.to_user_name) 123 | return 124 | 125 | 126 | def process_message_revoke(msg): 127 | """ 128 | 处理撤回消息 129 | """ 130 | # 消息存储,删除过期消息 131 | my.msg_store[msg.msg_id] = msg 132 | for _id in [_id for _id in my.msg_store if time.time() - my.msg_store[_id].msg_time > 120]: 133 | my.msg_store.pop(_id) 134 | 135 | # 保存消息中的内容(图片、语音等) 136 | if msg.we_type in ["Picture", "Recording"]: 137 | try: 138 | msg.we_text(".Cache/" + msg.msg_file) 139 | logging.warning("process_message_revoke: download %s to .Cache/", msg.msg_file) 140 | except Exception as excep: 141 | logging.error("process_message_revoke: download %s to .Cache/ error: %s", msg.msg_file, excep) 142 | 143 | # ==== 撤回消息处理(必须为最后一步) ==== 144 | if msg.we_type == "Note" and msg.we_text.find("撤回了一条消息") >= 0: 145 | old_msg = my.msg_store.get(msg.msg_content[msg.msg_content.find("<msgid>")+7: msg.msg_content.find("</msgid>")]) 146 | if not old_msg: 147 | logging.warning("process_message_revoke: no message id in my.msg_store") 148 | return 149 | 150 | if old_msg.from_user_name.startswith("@@"): 151 | my.send("【%s】中【%s】撤回了自己发送的消息:\nType: %s\n%s" % 152 | (old_msg.wind_name, old_msg.actual_remark_name, old_msg.we_type, old_msg.msg_file), toUserName=my.to_user_name) 153 | else: 154 | my.send("【%s】撤回了自己发送的消息:\nType: %s\n%s" % 155 | (old_msg.wind_name, old_msg.we_type, old_msg.msg_file), toUserName=my.to_user_name) 156 | 157 | if old_msg.we_type in ["Text", "Card"]: 158 | my.send(str(old_msg.we_text), toUserName=my.to_user_name) 159 | elif old_msg.we_type == "Sharing": 160 | my.send(old_msg.we_text + "\n" + old_msg.msg_url, toUserName=my.to_user_name) 161 | elif old_msg.we_type == "Picture": 162 | my.send_image(".Cache/" + old_msg.msg_file, toUserName=my.to_user_name) 163 | elif old_msg.we_type == "Recording": 164 | my.send_file(".Cache/" + old_msg.msg_file, toUserName=my.to_user_name) 165 | return 166 | 167 | 168 | @my.msg_register([TEXT, PICTURE, RECORDING, VIDEO, MAP, CARD, NOTE, SHARING, ATTACHMENT], isFriendChat=True, isGroupChat=True) 169 | def text_reply(msg): 170 | """ 171 | 消息自动接收, 接受全部的消息(自己发送的消息除外) 172 | """ 173 | # 跳过来自自己的消息 174 | if msg["FromUserName"] == my.loginInfo["User"]["UserName"]: 175 | return 176 | 177 | # 消息提取 178 | msg = Message(msg) 179 | 180 | # 消息过滤, 只监测文字、图片、语音、名片、注解、分享等 181 | if msg.we_type not in ["Text", "Picture", "Recording", "Card", "Note", "Sharing"]: 182 | logging.warning("process_message_group: message type isn't included, ignored") 183 | return 184 | 185 | # 处理群消息 186 | if msg.from_user_name.startswith("@@"): 187 | process_message_group(msg) 188 | 189 | # 处理撤回消息 190 | process_message_revoke(msg) 191 | return 192 | 193 | 194 | # 运行程序 195 | my.run(debug=False) 196 | 197 | """ 198 | 好友消息: 199 | { 200 | 'MsgId': '5254859004542036569', 201 | 'FromUserName': '@f3b7fdc54717ea8dc22cb3edef59688e82ef34874e3236801537b94f6cd73e1e', 202 | 'ToUserName': '@e79dde912b8f817514c01f399ca9ba12', 203 | 'MsgType': 1, 204 | 'Content': '[微笑]己改', 205 | 'Status': 3, 206 | 'ImgStatus': 1, 207 | 'CreateTime': 1498448860, 208 | 'VoiceLength': 0, 209 | 'PlayLength': 0, 210 | 'FileName': '', 211 | 'FileSize': '', 212 | 'MediaId': '', 213 | 'Url': '', 214 | 'AppMsgType': 0, 215 | 'StatusNotifyCode': 0, 216 | 'StatusNotifyUserName': '', 217 | 'HasProductId': 0, 218 | 'Ticket': '', 219 | 'ImgHeight': 0, 220 | 'ImgWidth': 0, 221 | 'SubMsgType': 0, 222 | 'NewMsgId': 5254859004542036569, 223 | 'OriContent': '', 224 | 'User': <User: { 225 | 'MemberList': <ContactList: []>, 226 | 'Uin': 0, 227 | 'UserName': '@f3b7fdc54717ea8dc22cb3edef59688e82ef34874e3236801537b94f6cd73e1e', 228 | 'NickName': '付贵吉祥', 229 | 'HeadImgUrl': '/cgi-bin/mmwebwx-bin/webwxgeticon?seq=688475226&username=@f3b7fdc54717ea8dc22cb3edef59688e82ef34874e3236801537b94f6cd73e1e&skey=@', 230 | 'ContactFlag': 3, 231 | 'MemberCount': 0, 232 | 'RemarkName': '付贵吉祥@中建5号楼', 233 | 'HideInputBarFlag': 0, 234 | 'Sex': 1, 235 | 'Signature': '漫漫人生路...', 236 | 'VerifyFlag': 0, 237 | 'OwnerUin': 0, 238 | 'PYInitial': 'FGJX', 239 | 'PYQuanPin': 'fuguijixiang', 240 | 'RemarkPYInitial': 'FGJXZJ5HL', 241 | 'RemarkPYQuanPin': 'fuguijixiangzhongjian5haolou', 242 | 'StarFriend': 0, 243 | 'AppAccountFlag': 0, 244 | 'Statues': 0, 245 | 'AttrStatus': 135205, 246 | 'Province': '山东', 247 | 'City': '', 248 | 'Alias': '', 249 | 'SnsFlag': 17, 250 | 'UniFriend': 0, 251 | 'DisplayName': '', 252 | 'ChatRoomId': 0, 253 | 'KeyWord': '', 254 | 'EncryChatRoomId': '', 255 | 'IsOwner': 0 256 | }>, 257 | 'Type': 'Text', 258 | 'Text': '[微笑]己改' 259 | } 260 | """ 261 | 262 | """ 263 | 群消息: 264 | { 265 | 'MsgId': '7844877618948840992', 266 | 'FromUserName': '@@8dc5df044444d1fb8e3972e755b47adf9d07f5a032cae90a4d822b74ee1e4880', 267 | 'ToUserName': '@e79dde912b8f817514c01f399ca9ba12', 268 | 'MsgType': 1, 269 | 'Content': '就是那个,那个协议我们手上有吗', 270 | 'Status': 3, 271 | 'ImgStatus': 1, 272 | 'CreateTime': 1498448972, 273 | 'VoiceLength': 0, 274 | 'PlayLength': 0, 275 | 'FileName': '', 276 | 'FileSize': '', 277 | 'MediaId': '', 278 | 'Url': '', 279 | 'AppMsgType': 0, 280 | 'StatusNotifyCode': 0, 281 | 'StatusNotifyUserName': '', 282 | 'HasProductId': 0, 283 | 'Ticket': '', 284 | 'ImgHeight': 0, 285 | 'ImgWidth': 0, 286 | 'SubMsgType': 0, 287 | 'NewMsgId': 7844877618948840992, 288 | 'OriContent': '', 289 | 'ActualNickName': '5-1-1003', 290 | 'IsAt': False, 291 | 'ActualUserName': '@a0922f18795e4c3b6d7d09c492ace233', 292 | 'User': <Chatroom: { 293 | 'MemberList': <ContactList: [ 294 | <ChatroomMember: { 295 | 'MemberList': <ContactList: []>, 296 | 'Uin': 0, 297 | 'UserName': '@e79dde912b8f817514c01f399ca9ba12', 298 | 'NickName': '齐现虎', 299 | 'AttrStatus': 2147600869, 300 | 'PYInitial': '', 301 | 'PYQuanPin': '', 302 | 'RemarkPYInitial': '', 303 | 'RemarkPYQuanPin': '', 304 | 'MemberStatus': 0, 305 | 'DisplayName': '5-1-1601', 306 | 'KeyWord': 'qix' 307 | }>, 308 | <ChatroomMember: { 309 | 'MemberList': <ContactList: []>, 310 | 'Uin': 0, 311 | 'UserName': '@a9620e3d4b82eab2521ccdbb985afc37', 312 | 'NickName': 'A高佳祥15069179911', 313 | 'AttrStatus': 102503, 314 | 'PYInitial': '', 315 | 'PYQuanPin': '', 316 | 'RemarkPYInitial': '', 317 | 'RemarkPYQuanPin': '', 318 | 'MemberStatus': 0, 319 | 'DisplayName': '5-2-220315069179911', 320 | 'KeyWord': 'gao' 321 | }>, 322 | ....... 323 | ]>, 324 | 'Uin': 0, 325 | 'UserName': '@@8dc5df044444d1fb8e3972e755b47adf9d07f5a032cae90a4d822b74ee1e4880', 326 | 'NickName': '中建锦绣澜庭二期5#楼', 327 | 'HeadImgUrl': '/cgi-bin/mmwebwx-bin/webwxgetheadimg?seq=0&username=@@8dc5df044444d1fb8e3972e755b47adf9d07f5a032cae90a4d822b74ee1e4880&skey=@', 328 | 'ContactFlag': 3, 329 | 'MemberCount': 106, 330 | 'RemarkName': '', 331 | 'HideInputBarFlag': 0, 332 | 'Sex': 0, 333 | 'Signature': '', 334 | 'VerifyFlag': 0, 335 | 'OwnerUin': 0, 336 | 'PYInitial': 'ZJJXLTEJ5L', 337 | 'PYQuanPin': 'zhongjianjinxiulantingerji5lou', 338 | 'RemarkPYInitial': '', 339 | 'RemarkPYQuanPin': '', 340 | 'StarFriend': 0, 341 | 'AppAccountFlag': 0, 342 | 'Statues': 0, 343 | 'AttrStatus': 0, 344 | 'Province': '', 345 | 'City': '', 346 | 'Alias': '', 347 | 'SnsFlag': 0, 348 | 'UniFriend': 0, 349 | 'DisplayName': '', 350 | 'ChatRoomId': 0, 351 | 'KeyWord': '', 352 | 'EncryChatRoomId': '@d1e510bc8cbd192468e9c85c6f5a9d81', 353 | 'IsOwner': 1, 354 | 'IsAdmin': None, 355 | 'Self': <ChatroomMember: { 356 | 'MemberList': <ContactList: []>, 357 | 'Uin': 0, 358 | 'UserName': '@e79dde912b8f817514c01f399ca9ba12', 359 | 'NickName': '齐现虎', 360 | 'AttrStatus': 2147600869, 361 | 'PYInitial': '', 362 | 'PYQuanPin': '', 363 | 'RemarkPYInitial': '', 364 | 'RemarkPYQuanPin': '', 365 | 'MemberStatus': 0, 366 | 'DisplayName': '5-1-1601', 367 | 'KeyWord': 'qix' 368 | }>, 369 | 'HeadImgUpdateFlag': 1, 370 | 'ContactType': 0, 371 | 'ChatRoomOwner': '@e79dde912b8f817514c01f399ca9ba12' 372 | }>, 373 | 'Type': 'Text', 374 | 'Text': '就是那个,那个协议我们手上有吗' 375 | } 376 | 377 | 警示消息:好友类 378 | { 379 | 'MsgId': '1529895072288746571', 380 | 'FromUserName': '@4076708be2e09ef83f249f168553d0dd55b4f734aee7d276e92ddbe98625476a', 381 | 'ToUserName': '@f97583d8ffbaee6189854116897c677f', 382 | 'MsgType': 10000, 383 | 'Content': '你已添加了呼啸而过的小青春,现在可以开始聊天了。', 384 | 'Status': 4, 385 | 'ImgStatus': 1, 386 | 'CreateTime': 1498533407, 387 | 'VoiceLength': 0, 388 | 'PlayLength': 0, 389 | 'FileName': '', 390 | 'FileSize': '', 391 | 'MediaId': '', 392 | 'Url': '', 393 | 'AppMsgType': 0, 394 | 'StatusNotifyCode': 0, 395 | 'StatusNotifyUserName': '', 396 | 'HasProductId': 0, 397 | 'Ticket': '', 398 | 'ImgHeight': 0, 399 | 'ImgWidth': 0, 400 | 'SubMsgType': 0, 401 | 'NewMsgId': 1529895072288746571, 402 | 'OriContent': '', 403 | 'User': <User: { 404 | 'userName': '@4076708be2e09ef83f249f168553d0dd55b4f734aee7d276e92ddbe98625476a', 405 | 'MemberList': <ContactList: []> 406 | }>, 407 | 'Type': 'Note', 408 | 'Text': '你已添加了呼啸而过的小青春,现在可以开始聊天了。' 409 | } 410 | 411 | 警示消息:群类 412 | { 413 | 'MsgId': '1049646282086057263', 414 | 'FromUserName': '@@300f57b68ca7ef593ae3221eef7dba5377466c86122aaa15a8ffc1031310e210', 415 | 'ToUserName': '@006f63e8086ab07fcbe3771dc824c4a6', 416 | 'MsgType': 10000, 417 | 'Content': '你邀请"大姐"加入了群聊', 418 | 'Status': 3, 419 | 'ImgStatus': 1, 420 | 'CreateTime': 1498533901, 421 | 'VoiceLength': 0, 422 | 'PlayLength': 0, 423 | 'FileName': '', 424 | 'FileSize': '', 425 | 'MediaId': '', 426 | 'Url': '', 427 | 'AppMsgType': 0, 428 | 'StatusNotifyCode': 0, 429 | 'StatusNotifyUserName': '', 430 | 'HasProductId': 0, 431 | 'Ticket': '', 432 | 'ImgHeight': 0, 433 | 'ImgWidth': 0, 434 | 'SubMsgType': 0, 435 | 'NewMsgId': 1049646282086057263, 436 | 'OriContent': '', 437 | 'ActualUserName': '@006f63e8086ab07fcbe3771dc824c4a6', 438 | 'ActualNickName': '某某某', 439 | 'IsAt': False, 440 | 'User': <Chatroom: { 441 | 'UserName': '@@300f57b68ca7ef593ae3221eef7dba5377466c86122aaa15a8ffc1031310e210', 442 | 'MemberList': <ContactList: []> 443 | }>, 444 | 'Type': 'Note', 445 | 'Text': '你邀请"大姐"加入了群聊' 446 | } 447 | """ 448 | -------------------------------------------------------------------------------- /python_weibo.py: -------------------------------------------------------------------------------- 1 | # _*_ coding: utf-8 _*_ 2 | 3 | """ 4 | python_weibo.py by xianhu 5 | """ 6 | 7 | import re 8 | import rsa 9 | import time 10 | import json 11 | import base64 12 | import logging 13 | import binascii 14 | import requests 15 | import urllib.parse 16 | 17 | 18 | class WeiBoLogin(object): 19 | """ 20 | class of WeiBoLogin, to login weibo.com 21 | """ 22 | 23 | def __init__(self): 24 | """ 25 | constructor 26 | """ 27 | self.user_name = None 28 | self.pass_word = None 29 | self.user_uniqueid = None 30 | self.user_nick = None 31 | 32 | self.session = requests.Session() 33 | self.session.headers.update({"User-Agent": "Mozilla/5.0 (Windows NT 6.3; WOW64; rv:41.0) Gecko/20100101 Firefox/41.0"}) 34 | self.session.get("http://weibo.com/login.php") 35 | return 36 | 37 | def login(self, user_name, pass_word): 38 | """ 39 | login weibo.com, return True or False 40 | """ 41 | self.user_name = user_name 42 | self.pass_word = pass_word 43 | self.user_uniqueid = None 44 | self.user_nick = None 45 | 46 | # get json data 47 | s_user_name = self.get_username() 48 | json_data = self.get_json_data(su_value=s_user_name) 49 | if not json_data: 50 | return False 51 | s_pass_word = self.get_password(json_data["servertime"], json_data["nonce"], json_data["pubkey"]) 52 | 53 | # make post_data 54 | post_data = { 55 | "entry": "weibo", 56 | "gateway": "1", 57 | "from": "", 58 | "savestate": "7", 59 | "userticket": "1", 60 | "vsnf": "1", 61 | "service": "miniblog", 62 | "encoding": "UTF-8", 63 | "pwencode": "rsa2", 64 | "sr": "1280*800", 65 | "prelt": "529", 66 | "url": "http://weibo.com/ajaxlogin.php?framelogin=1&callback=parent.sinaSSOController.feedBackUrlCallBack", 67 | "rsakv": json_data["rsakv"], 68 | "servertime": json_data["servertime"], 69 | "nonce": json_data["nonce"], 70 | "su": s_user_name, 71 | "sp": s_pass_word, 72 | "returntype": "TEXT", 73 | } 74 | 75 | # get captcha code 76 | if json_data["showpin"] == 1: 77 | url = "http://login.sina.com.cn/cgi/pin.php?r=%d&s=0&p=%s" % (int(time.time()), json_data["pcid"]) 78 | with open("captcha.jpeg", "wb") as file_out: 79 | file_out.write(self.session.get(url).content) 80 | code = input("请输入验证码:") 81 | post_data["pcid"] = json_data["pcid"] 82 | post_data["door"] = code 83 | 84 | # login weibo.com 85 | login_url_1 = "http://login.sina.com.cn/sso/login.php?client=ssologin.js(v1.4.18)&_=%d" % int(time.time()) 86 | json_data_1 = self.session.post(login_url_1, data=post_data).json() 87 | if json_data_1["retcode"] == "0": 88 | params = { 89 | "callback": "sinaSSOController.callbackLoginStatus", 90 | "client": "ssologin.js(v1.4.18)", 91 | "ticket": json_data_1["ticket"], 92 | "ssosavestate": int(time.time()), 93 | "_": int(time.time()*1000), 94 | } 95 | response = self.session.get("https://passport.weibo.com/wbsso/login", params=params) 96 | json_data_2 = json.loads(re.search(r"\((?P<result>.*)\)", response.text).group("result")) 97 | if json_data_2["result"] is True: 98 | self.user_uniqueid = json_data_2["userinfo"]["uniqueid"] 99 | self.user_nick = json_data_2["userinfo"]["displayname"] 100 | logging.warning("WeiBoLogin succeed: %s", json_data_2) 101 | else: 102 | logging.warning("WeiBoLogin failed: %s", json_data_2) 103 | else: 104 | logging.warning("WeiBoLogin failed: %s", json_data_1) 105 | return True if self.user_uniqueid and self.user_nick else False 106 | 107 | def get_username(self): 108 | """ 109 | get legal username 110 | """ 111 | username_quote = urllib.parse.quote_plus(self.user_name) 112 | username_base64 = base64.b64encode(username_quote.encode("utf-8")) 113 | return username_base64.decode("utf-8") 114 | 115 | def get_json_data(self, su_value): 116 | """ 117 | get the value of "servertime", "nonce", "pubkey", "rsakv" and "showpin", etc 118 | """ 119 | params = { 120 | "entry": "weibo", 121 | "callback": "sinaSSOController.preloginCallBack", 122 | "rsakt": "mod", 123 | "checkpin": "1", 124 | "client": "ssologin.js(v1.4.18)", 125 | "su": su_value, 126 | "_": int(time.time()*1000), 127 | } 128 | try: 129 | response = self.session.get("http://login.sina.com.cn/sso/prelogin.php", params=params) 130 | json_data = json.loads(re.search(r"\((?P<data>.*)\)", response.text).group("data")) 131 | except Exception as excep: 132 | json_data = {} 133 | logging.error("WeiBoLogin get_json_data error: %s", excep) 134 | 135 | logging.debug("WeiBoLogin get_json_data: %s", json_data) 136 | return json_data 137 | 138 | def get_password(self, servertime, nonce, pubkey): 139 | """ 140 | get legal password 141 | """ 142 | string = (str(servertime) + "\t" + str(nonce) + "\n" + str(self.pass_word)).encode("utf-8") 143 | public_key = rsa.PublicKey(int(pubkey, 16), int("10001", 16)) 144 | password = rsa.encrypt(string, public_key) 145 | password = binascii.b2a_hex(password) 146 | return password.decode() 147 | 148 | 149 | if __name__ == "__main__": 150 | logging.basicConfig(level=logging.DEBUG, format="%(asctime)s\t%(levelname)s\t%(message)s") 151 | weibo = WeiBoLogin() 152 | weibo.login("username", "password") 153 | -------------------------------------------------------------------------------- /test.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xianhu/LearnPython/0b2efbcd4c72fcbb78566b452f870d33a8d6ece6/test.png -------------------------------------------------------------------------------- /wxPython/hello_world.py: -------------------------------------------------------------------------------- 1 | # _*_ coding: utf-8 _*_ 2 | 3 | """ 4 | Hello World 5 | """ 6 | 7 | import wx 8 | 9 | 10 | class HelloFrame(wx.Frame): 11 | """ 12 | A Frame that says Hello World 13 | """ 14 | 15 | def __init__(self, *args, **kw): 16 | # ensure the parent's __init__ is called 17 | super(HelloFrame, self).__init__(*args, **kw) 18 | 19 | # create a panel in the frame 20 | pnl = wx.Panel(self) 21 | 22 | # and put some text with a larger bold font on it 23 | st = wx.StaticText(parent=pnl, label="Hello World!", pos=(25, 25)) 24 | font = st.GetFont() 25 | font.PointSize += 10 26 | font = font.Bold() 27 | st.SetFont(font) 28 | 29 | # create a menu bar 30 | self.make_menubar() 31 | 32 | # and a status bar 33 | self.CreateStatusBar() 34 | self.SetStatusText("Welcome to wxPython!") 35 | 36 | def make_menubar(self): 37 | """ 38 | A menu bar is composed of menus, which are composed of menu items. 39 | This method builds a set of menus and binds handlers to be called 40 | when the menu item is selected. 41 | """ 42 | # Make a file menu with Hello and Exit items 43 | menu_file = wx.Menu() 44 | # The "\t..." syntax defines an accelerator key that also triggers the same event 45 | 46 | item_hello = menu_file.Append(-1, "&Hello...\tCtrl-H", "Help string shown in status bar for this menu item") 47 | menu_file.AppendSeparator() 48 | 49 | # When using a stock ID we don't need to specify the menu item's label 50 | item_exit = menu_file.Append(wx.ID_EXIT) 51 | 52 | # Now a help menu for the about item 53 | menu_help = wx.Menu() 54 | item_about = menu_help.Append(wx.ID_ABOUT) 55 | 56 | # Make the menu bar and add the two menus to it. The '&' defines 57 | # that the next letter is the "mnemonic" for the menu item. On the 58 | # platforms that support it those letters are underlined and can be 59 | # triggered from the keyboard. 60 | menu_bar = wx.MenuBar() 61 | menu_bar.Append(menu_file, "&File") 62 | menu_bar.Append(menu_help, "&Help") 63 | 64 | # Give the menu bar to the frame 65 | self.SetMenuBar(menu_bar) 66 | 67 | # Finally, associate a handler function with the EVT_MENU event for 68 | # each of the menu items. That means that when that menu item is 69 | # activated then the associated handler function will be called. 70 | self.Bind(wx.EVT_MENU, self.OnHello, item_hello) 71 | self.Bind(wx.EVT_MENU, self.OnExit, item_exit) 72 | self.Bind(wx.EVT_MENU, self.OnAbout, item_about) 73 | 74 | def OnExit(self, event): 75 | """Close the frame, terminating the application.""" 76 | self.Close(True) 77 | 78 | def OnHello(self, event): 79 | """Say hello to the user.""" 80 | wx.MessageBox("Hello again from wxPython") 81 | 82 | def OnAbout(self, event): 83 | """Display an About Dialog""" 84 | wx.MessageBox("This is a wxPython Hello World sample", "About Hello World 2", wx.OK | wx.ICON_INFORMATION) 85 | 86 | 87 | if __name__ == '__main__': 88 | # When this module is run (not imported) then create the app, the 89 | # frame, show it, and start the event loop. 90 | app = wx.App() 91 | frm = HelloFrame(None, title='Hello World 2') 92 | frm.Show() 93 | app.MainLoop() 94 | --------------------------------------------------------------------------------