himawari8图片下载改进版

Posted in 2017-3-23 11:42 | Category: Python | Tags: earth himawari8 python

第一版下载图片后设为壁纸,四周都是黑黑的不好看, 所以结合本地壁纸将两张图片进行合成

只要计算一下要缩减的大小与要放置的位置

我的方法是:打开 gimp,合成两张图片,记下缩减的大小(214,214)与位置(160,160)

每次只要运行一下

python himawari8.py

源码

from PIL import Image, ImageOps, ImageDraw
from io import BytesIO
from urllib.request import Request, urlopen
from datetime import datetime, timedelta
import json

SCALE = 2
WIDTH = 1368
HEIGHT = 768


def get_info():
    url = "http://himawari8-dl.nict.go.jp/himawari8/img/D531106/latest.json"
    request = Request(url)
    response = urlopen(request, timeout=10)
    return json.loads(response.read())


def download():
    png = Image.new('RGB', (550 * SCALE, 550 * SCALE))
    # desktop = Image.new('RGB', (WIDTH, HEIGHT))
    desktop = Image.open('/home/jianglin/Pictures/308556.png')
    url_format = 'http://himawari8-dl.nict.go.jp/himawari8/img/D531106/{}d/{}/{}_{}_{}.png'
    info = get_info()
    # date = datetime.strptime(info['date'], '%Y-%m-%d %H:%M:%S') + timedelta(
    #     hours=-8)
    date …

下载Himawari8拍摄的实时地球图片

Posted in 2017-3-22 22:10 | Category: Python | Tags: earth himawari8 python

设置壁纸

feh --bg-scale /tmp/earth.png

设置桌面大小,及图片放大倍数

SCALE = 4
WIDTH = 1368
HEIGHT = 768

直接给出源码

from PIL import Image
from io import BytesIO
from urllib.request import Request, urlopen
from datetime import datetime
import json

SCALE = 4
WIDTH = 1368
HEIGHT = 768


def get_info():
    url = "http://himawari8-dl.nict.go.jp/himawari8/img/D531106/latest.json"
    request = Request(url)
    response = urlopen(request, timeout=10)
    return json.loads(response.read())


def download():
    png = Image.new('RGB', (550 * SCALE, 550 * SCALE))
    desktop = Image.new('RGB', (WIDTH, HEIGHT))
    url_format = 'http://himawari8-dl.nict.go.jp/himawari8/img/D531106/{}d/{}/{}_{}_{}.png'
    info = get_info()
    date = datetime.strptime(info['date'], '%Y-%m-%d %H:%M:%S')
    for x in range(SCALE):
        for y in range(SCALE):
            url = url_format.format(SCALE, 550,
                                    date.strftime("%Y/%m …

sqlalchemy使用上的小tip

Posted in 2017-3-14 6:16 | Category: Python | Tags: django sqlalchemy python

GitHub地址: https://github.com/honmaple/maple-json

sqlalchemy object序列化为json

灵感来源于 Django REST framework

多个实例

posts = Post.query.all()
serializer = Seralizer(posts,many=True)
data = serializer.data

单个实例

post = Post.query.first()
serializer = Seralizer(post,many=False)
data = serializer.data

排除字段

serializer = Seralizer(post,exclude=['title'])

仅包括字段

serializer = Seralizer(post,include=['title'])

关系查询深度

serializer = Seralizer(post,depth=3)
  • depth 默认为2

增加一些自定义的函数

serializer = Serializer(post,extra=['get_post_count'])

Post

class Post(Model):
    ......
    def get_post_count(self):
        return 11

可传递参数的函数

class PostSerializer(Serializer …

使用flask实现的一个简单的图片上传存储服务

Posted in 2017-3-14 6:16 | Category: Python | Tags: linux flask python

maple-file

使用flask实现的一个简单的图片上传服务

设计初衷

对于图片的存储,有很多选择,一般采用云服务如(七牛,又拍等),但是国内的服务像七牛 自定义域名竟然需要域名备案(Excuse me,当初就是因为备案麻烦才选择国外的),而且浪费了我十块钱,

而我又想像七牛一样可以直接在本地就可以上传图片,找来找去,没有找到一个比较合适的,所以花两天时间自己写了一个

使用

由于初衷是本地脚本就可以发布,所以没有前端界面,等以后有时间了再加上

API

  • /api/login
    • POST 登录
  • /api/logout
    • GET 注销
  • /api/albums
    • GET 获取相册列表
    • POST 新建相册
      • name 相册名称
      • description 相册描述
  • /api/albums/

    pk 相册ID

    • GET 获取相册信息
    • PUT 修改相册信息
      • name 相册名称
      • description 相册描述
    • DELETE 删除相册
    • /api/images
    • GET 获取图片列表
    • POST 上传图片
      • images 上传图片列表
      • album 相册ID(默认会新建一个default相册)
    • /api/images/
    • GET 获取图片信息
    • PUT 修改图片信息
      • name 图片名称
      • description 图片描述
    • DELETE 删除图片

配置

class Config(object):
    DEBUG = True # 生产环境设置为False
    SECRET_KEY = 'ccc' # import os;os.urandom(24)
    SECRET_KEY_SALT = 'ssss'
    JSON_AS_ASCII …

django获取当前request

Posted in 2017-1-10 19:3 | Category: Python | Tags: django python

参考链接:

https://blndxp.wordpress.com/2016/03/04/django-get-current-user-anywhere-in-your-code-using-a-middleware/

http://nedbatchelder.com/blog/201008/global_django_requests.html

使用中间件

from __future__ import absolute_import, division, print_function

try:
    from threading import local
except ImportError:
    from django.utils._threading_local import local

_thread_locals = local()

def get_current_request():
    """ returns the request object for this thread """
    return getattr(_thread_locals, "request", None)

def get_current_user():
    """ returns the current user, if exist, otherwise returns None """
    request = get_current_request()
    if request:
        return getattr(request, "user", None)

class ThreadLocalMiddleware(object):
    """ Simple middleware that adds the request object in thread local stor    age."""

    def process_request(self, request):
        _thread_locals.request = request

    def process_response(self, request, response):
        if hasattr(_thread_locals, 'request'):
        del _thread_locals.request
            return response

Python中的__main__函数

Posted in 2016-12-14 13:30 | Category: Python | Tags: python

Table of Contents

__main__

转自 这里

很多新手刚开始学习python的时候经常会看到python 中 name = 'main' 这样的代码,可能很多新手一开始学习的时候都比较疑惑,python 中 name = 'main' 的作用,到底干嘛的?

有句话经典的概括了这段代码的意义:

“Make a script both importable and executable”

意思就是说让你写的脚本模块既可以导入到别的模块中用,另外该模块自己也可执行。 这句话,可能一开始听的还不是很懂。下面举例说明: 先写一个模块:

#module.py
def main():
    print("we are in %s" % __name__)

if __name__ == '__main__':
    main()

这个函数定义了一个main函数,我们执行一下该py文件发现结果是打印出

we are in __main__

说明我们的if语句中的内容被执行了,调用了 main(): 但是如果我们从另我一个模块导入该模块,并调用一次main()函数会是怎样的结果呢?

#anothermodle.py
from module import main
main()

其执行的结果是:

we are in module

但是没有显示

"we are in __main__"

也就是说模块 name = 'main' 下面的函数没有执行。 这样既可以让“模块”文件运行,也可以被其他模块引入,而且不会执行函数2次。这才是关键。

总结一下:

如果我们是直接执行某个.py文件的时候,该文件中那么

__name__ == '__main__'

True, 但是我们如果从另外一个.py文件通过import导入该文件的时候,这时name = 'main'的值就是我们这个py文件的名字而不是name = 'main'。 这个功能还有一个用处:调试代码的时候,在

if __name__ == '__main__'

中加入一些我们的调试代码, 我们可以让外部模块调用的时候不执行我们的调试代码,但是如果我们想排查问题的时候,直接执行该模块文件,调试代码能够正常运行!

sqlalchemy序列化为json

Posted in 2016-12-13 7:53 | Category: Python | Tags: flask sqlalchemy python

为什么需要这个需求?

sqlalchemy 是个好东西,虽然其文档犹如老太婆的裹脚布--又臭又长,饱受诟病

使用 restful 时sqlalchemy返回的是一个 object 类,假设前后端分离,前端无法处理

如何实现?

直接给出代码

class Serializer(object):

    def __init__(self, instance, many=False, include=[], exclude=[], depth=2):
        self.instance = instance
        self.many = many
        self.include = include
        self.exclude = exclude
        self.depth = depth

    @property
    def data(self):
        if self.include and self.exclude:
            raise ValueError('include and exclude can\'t work together')
        if self.many:
            if isinstance(self.instance, list):
                return self._serializerlist(self.instance, self.depth)
            pageinfo = {
                'items': True,
                'pages': self.instance.pages,
                'has_prev': self.instance.has_prev,
                'page': self.instance.page,
                'has_next': self.instance.has_next,
                'iter_pages': list(self.instance.iter_pages(left_edge=1,
                                                            left_current …

flask使用token进行验证

Posted in 2016-12-13 3:32 | Category: Python | Tags: flask python token

为什么需要用token验证

原因呢是因为写博客时已经在本地写好了,但是要发表到网站上还需要这么几步:

  • [X] 打开浏览器
  • [X] 打开我的网站
  • [X] 进入登陆页
  • [X] 登陆
  • [X] 进入后台页
  • [X] 进入文章发表页
  • [X] 复制粘贴
  • [X] 发表

所以使用token验证成为必然

如何使用token?

生成token

使用itsdangerous对token进行加密

class User(model):
    ......

    @property
    def token(self):
        config = current_app.config
        secret_key = config.setdefault('SECRET_KEY')
        salt = config.setdefault('SECURITY_PASSWORD_SALT')
        serializer = URLSafeTimedSerializer(secret_key)
        # column = self.(需要加密的字段)
        token = serializer.dumps(column, salt=salt)
        return token

请保管好SECRET_KEYSECURITY_PASSWORD_SALT,不要泄露

验证token

class User(Model):
    ......

    @staticmethod
    def check_token(token, max_age=86400):
        config = current_app.config
        secret_key = config.setdefault('SECRET_KEY')
        salt = config.setdefault('SECURITY_PASSWORD_SALT')
        serializer = URLSafeTimedSerializer(secret_key)
        try:
            column = serializer.loads(token, salt=salt, max_age=max_age)
        except BadSignature:
            return False
        except SignatureExpired:
            return False
  • max-age 最大过期时间 …

利用网易云api获取歌曲信息

Posted in 2016-12-11 4:4 | Category: Python | Tags: python

最近是增加了一个aplayer在网站上,但原本想要使用qiniu存储,最后觉得太麻烦了,直接利用网易云api获取歌曲

使用python标准库urllib

直接给出代码

from urllib import request
import json

id = '28819878'
url = "http://music.163.com/api/song/detail/?id=" + id + "&ids=%5B" + id + "%5D&csrf_token"
rep = request.urlopen(url).read().decode('UTF-8')
rep = json.loads(rep)['songs'][0]
name = rep['name']
artist = rep['artists'][0]['name']
mp3url = rep['mp3Url']
picurl = rep['album']['blurPicUrl']
print('name:', name)
print('artists:', artist)
print('mp3:', mp3url)
print('pic:', picurl)
url = 'http://music.163.com/api/song/media?id=' + id
rep = request.urlopen(url).read().decode('UTF-8')
lyric = json.loads(rep)['lyric']
print('lyric:\n', json.dumps(lyric))

结果

#+RESULTS:
: name: 轨迹
: artists: 徐小薇
: mp3: http://m2.music.126.net/1vGFlmmY1NeHEZy_1QuYhA==/5898879883333738.mp3
: pic: http://p4.music.126.net/EMS4GE-ojql3azwxXYPT3w==/3264450024433079.jpg
: lyric:
:  "[00:12.98 …

常用正则表达式

Posted in 2016-11-25 2:42 | Category: Python | Tags: python regex

pip安装mysql-python出错

Posted in 2016-9-28 11:7 | Category: Python | Tags: pip python mysql

Table of Contents

Collecting mysql-python
  Using cached MySQL-python-1.2.5.zip
    Complete output from command python setup.py egg_info:
    sh: mysql_config: 未找到命令
    Traceback (most recent call last):
      File "<string>", line 1, in <module>
      File "/tmp/pip-build-g21LDi/mysql-python/setup.py", line 17, in <module>
        metadata, options = get_config()
      File "setup_posix.py", line 43, in get_config
        libs = mysql_config("libs_r")
      File "setup_posix.py", line 25, in mysql_config
        raise EnvironmentError("%s not found" % (mysql_config.path,))
    EnvironmentError: mysql_config not found

    ----------------------------------------
Command "python setup.py egg_info" failed with error code 1 in /tmp/pip-build-g21LDi/mysql-python/

Mac

参考问题

brew install mysql
export PATH=$PATH:/usr/local/mysql/bin
pip install MySQL-Python

Centos

yum install python-devel mysql-devel

python的匿名函数lambda

Posted in 2016-8-13 11:20 | Category: Python | Tags: python lambda

参考文档

lambda arguments: expression

等于

def <lambda>(arguments):
    return expression

举例

def add(a,b):
    return a + b
print(add(1,3))

可以写成这样

add = lambda a,b:a+b
print(add(1,3))

从上可以看出 lambda 的语法

lambda [arg1[,arg2,arg3....argN]]:expression

Python二分查找实现

Posted in 2016-8-5 20:55 | Category: Python | Tags: python 算法 二分查找

三种方法实现:

def find(a, low, high, v):
    mid = low + (high - low) // 2
    if v < a[0] or v > a[-1]:
        return False
    if mid >= len(a):
        return False
    if a[mid] == v:
        return True
    elif a[mid] > v:
        return find(a, low, mid - 1, v)
    else:
        return find(a, mid + 1, high, v)

def find2(a, low, high, v):
    mid = low + (high - low) // 2
    if v < a[0] or v > a[-1]:
        return False
    if a[mid] == v:
        return True
    elif a[mid] < v:
        low = mid
    else:
        high = mid
    return find2(a, low, high, v)

def find3(a, v):
    n = len(a)
    low = -1
    high = n
    ret = True
    while (low + 1 != high):
        mid = low + (high - low) // 2
        if (a[mid] == v …

python列表reverse后结果为None

Posted in 2016-8-1 0:35 | Category: Python | Tags: python

今天在实现列表倒序时偶然发现

print(list.reverse())

#+RESULTS:
: None

返回为空,搜索了一下,才知道原来reverse是在原列表进行的操作,所以正确的方法是:

a = [1, 2, 3, 4, 5, 6, 7, 8, 9, 0]
a.reverse()
print(a)

#+RESULTS:
: [0, 9, 8, 7, 6, 5, 4, 3, 2, 1]

同样的适用于 sort

a = [1, 2, 3, 4, 5, 6, 7, 8, 9, 0]
a.reverse()
print(a)
a.sort()
print(a)

#+RESULTS:
: [0, 9, 8, 7, 6, 5, 4, 3, 2, 1]
: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

话说 org-mode显示的挺好的,到了markdownresult就不显示了

使用python脚本恢复原md文件

Posted in 2016-7-28 23:56 | Category: Python | Tags: pelican python

首先,这个恢复不是从磁盘中恢复,而是从数据库中恢复

原因呢,不久前我的博客md文件被我不小心删了, 而我的博客分静态博客(基于pelican),和我自己写的动态博客(需数据库),静态博客需要md文件, 不过还好,我的数据库一直有备份,所以直接从数据库中恢复

直接给出代码

import psycopg2
import os

conn = psycopg2.connect(database="blog",
                        user="postgres",
                        password="Your password",
                        host="127.0.0.1",
                        port="5432")
cur = conn.cursor()
cur.execute('select id,title,publish,author,category,content from articles')
articles = cur.fetchall()
print(len(articles))
for article in articles:
    cur.execute("select a.title,t.name from articles as a,tags as t, \
    tag_article as tt where  \
    tt.tags_id = t.id and tt.articles_id = a.id and a.id = %d" %
                article[0])
    tags = cur.fetchall()
    tags = ','.join(tag[1] for tag in tags)

    filename = os.path.join('markdown/', '%s.md' % article[1])
    title = (
        'Title: %s\nAuthor: %s\nDate: %s\nCategory: %s\nTags: %s\nSlug: %s\nSummary: %s\n …

flask时间格式化

Posted in 2016-6-15 23:46 | Category: Python | Tags: flask datetime python

在前端显示为该问题 "几分钟前发表或几天前发表"

后端通过filter注册

参考资料

设计需求

  • 如果问题发表超过 10天 ,则显示为 %Y-%m-%d %H:%M

  • 如果小于 10天 ,但是大于 1天 ,则显示为 n天前 发表

  • 如果小于 1天 ,但是大于 1小时 ,则显示为 n小时前 发表

  • 如果小于 1小时 ,但是大于 90秒 ,则显示为 n分钟前 发表

  • 如果小于 90秒 ,则显示为 刚刚 发表

具体实现

通过 diff.daysdiff.seconds 实现

比如,大于10天

if diff.days > 10:
    return dt.strftime('%Y-%m-%d %H:%M')

大于90秒,小于1小时

if diff.seconds <= 3600 and diff.seconds > 90:
    periods = ((diff.seconds / 60, "minute", "minutes"), )

具体代码

def timesince(dt, default="just now"):
    now = datetime.now()
    diff = now - dt
    if diff.days > 10:
        return dt.strftime('%Y-%m-%d %H:%M')
    if diff.days <= 10 and diff.days > 0:
        periods = ((diff.days, "day", "days"), )
    if diff.days <= 0 and diff.seconds > 3600:
        periods = ((diff.seconds / 3600, "hour …

基于restful的flask权限管理

Posted in 2016-6-10 1:34 | Category: Python | Tags: flask python restful

更新:2016-8-16

class RestBase(object):
    decorators = ()

    def __call__(self, func):
        f = self.method(func)
        if self.decorators:
            for dec in reversed(self.decorators):
                f = dec(f)
        return f

    def method(self, func):
        @wraps(func)
        def decorator(*args, **kwargs):
            meth = getattr(self, request.method.lower(), None)
            if request.method == 'HEAD':
                meth = getattr(self, 'get', None)
            if meth is not None:
                check = meth(*args, **kwargs)
                if check:
                    return self.callback()
            return func(*args, **kwargs)

        return decorator

    def callback(self):
        abort(403)

为什么需要restful形式的权限管理

最近在写flask应用时使用了 restful 形式的flask.views.MethodView,但是在对其进行权限管理时遇到了一些问题

flask文档上介绍说用

decorators = []

添加装饰器,但实际使用上,比如

  • getpost 采用不同的权限

get 不使用 login_required
post 需要 login_required

这样就不能使用 decorators 对视图进行装饰

  • post ,delete, put 都需要 login_required,但是get不需要 而 delete 又需要更高级别的权限,我们可以这样

    class AAA(MethodView):
    
        def get(self,uid):
            ...
    
        @login_required
        def post(self …

flask日志处理

Posted in 2016-5-24 22:36 | Category: Python | Tags: flask python logging

使用文档上的一句话:

Applications fail, servers fail. Sooner or later you will see an exception in production. Even if your code is 100% correct, you will still see exceptions from time to time. Why? Because everything else involved will fail.

应用发生错误时发送邮件

这里文档上个人认为说的不清不楚,毕竟想要使用还要看logging的文档

原文档

ADMINS = ['yourname@example.com']
if not app.debug:
    import logging
    from logging.handlers import SMTPHandler
    mail_handler = SMTPHandler('127.0.0.1',
                               'server-error@example.com',
                               ADMINS, 'YourApplication Failed')
    mail_handler.setLevel(logging.ERROR)
    app.logger.addHandler(mail_handler)

实际上这里的好多参数没有交代清楚,具体可以看https://docs.python.org/2/library/logging.handlers.html#smtp-handler

具体代码

import logging
from logging.handlers import SMTPHandler
from logging import Formatter
config = app.config
credentials = (config['MAIL_USERNAME'], config['MAIL_PASSWORD'])
mail_handler = SMTPHandler(
    secure=(),
    mailhost=(config['MAIL_SERVER'], config['MAIL_PORT']),
    fromaddr='',
    toaddrs='',
    subject='YourApplication Failed',
    credentials=credentials)

mail_handler.setFormatter(Formatter …

flask中生成atom

Posted in 2016-5-17 16:42 | Category: Python | Tags: flask python

参考资料1 参考资料2

下面是具体代码
# from urlparse import urljoin #python2
from urllib.parse import urljoin
from flask import request
from werkzeug.contrib.atom import AtomFeed


def make_external(url):
    return urljoin(request.url_root, url)


@site.route('/atom.xml')
def feed():
    feed = AtomFeed('Recent Articles',
                    feed_url=request.url,
                    url=request.url_root,
                    subtitle='I like solitude, yearning for freedom')
    articles = Articles.query.limit(15).all()
    for article in articles:
        feed.add(
            article.title,
            article.content,
            content_type='html',
            author=article.author,
            url=make_external(url_for('blog.view', id=article.id)),
            updated=article.publish,
            published=article.publish)
    return feed.get_response()

flask实现分页

Posted in 2016-4-25 1:7 | Category: Python | Tags: flask jinja2 python

数据库实现分页

offset

使用offset可以实现数据库分页功能

questions = Questions.query.offset(num) # 从num开始

limit

使用limit实现限制每页的文章数量

questions = Questions.query.offset(num).limit(6) #每页显示6篇文章

前端实现分页

需求设计

是使用上一页,下一页,用表单进行跳转,还是使用数字显示

获得文章数量 pages,和当前页码 number

简单的上一页,下一页

因为我的设计不是这个,所以简单说一下

下一页,上一页

jinja2 代码

<a href="{{ url_for('blog.index',number=number + 1)}}">下一页</a>
<a href="{{ url_for('blog.index',number=number - 1)}}">下一页</a>

首页没有上一页,尾页没有下一页

{% if number == pages %}
no next page
{% else %}
 <a href="{{ url_for('blog.index',number=number + 1)}}">下一页</a>
{% endif %}
{% if number == 1 %}
no previous page
{% else %}
 <a href="{{ url_for('blog.index',number=number - 1)}}">上一页</a>
{% endif %}

显示各个页码的分页

搞了一下午,终于搞定了

设计

总页码小于7,显示所有页码,总页码大于7,显示当前页码以及当前页码前两页和后两页. 当页码大于7时,当前页码小于4,显示1~6页的页码·····

使用

{{ import 'base/page.html' as page }}
number为当前页码,pages为总共的页码
{{ page.page('blog.index',number=number,pages=pages)}}
如果url_for需要加参数,使用
{{ page.page …