周記 2017 4.24 - 4.30

微信支付寶對賬單下載

背景:幫朋友下載商戶在微信和支付寶每天的賬單
微信對賬單API
支付寶對賬單API

微信對賬單

對賬單接口入?yún)⒂幸粋€參數(shù):簽名 來效驗請求是否合法,這個簽名是由 MD5(請求參數(shù) + 用戶自定義秘鑰) 生成的,利用MD5的不可逆來保證安全性。

對賬單接口出參,請求失敗時返回 狀態(tài)碼和錯誤信息;成功時,直接返回文本(csv) 信息。

賬單信息:
交易時間,公眾賬號ID,商戶號,子商戶號,設備號,微信訂單號,商戶訂單號,用戶標識,交易類型,交易狀態(tài),付款銀行,貨幣種類,總金額,代金券或立減優(yōu)惠金額,微信退款單號,商戶退款單號,退款金額,代金券或立減優(yōu)惠退款金額,退款類型,退款狀態(tài),商品名稱,商戶數(shù)據(jù)包,手續(xù)費,費率
.......................................
總交易單數(shù),總交易額,總退款金額,總代金券或立減優(yōu)惠退款金額,手續(xù)費總金額

Python代碼(2.7):
ExportBill.py

# -*- coding:utf-8 -*-
# 請求微信 API 下載對賬單
# pip install requests
# pip install mysql-connector-python-rf
# pip install MySQL-python

import sys
import requests
import uuid
import hashlib
from MysqlUtil import Mysql

reload(sys)
sys.setdefaultencoding('utf8')

# 公眾賬號ID
appid = 'xxx'

# 商戶號
mch_id = 'xxx'

# 秘鑰
key = 'xxx'

# 賬單類型
# ALL,返回當日所有訂單信息,默認值
# SUCCESS,返回當日成功支付的訂單
# REFUND,返回當日退款訂單
# RECHARGE_REFUND,返回當日充值退款訂單(相比其他對賬單多一欄“返還手續(xù)費”)
bill_type = 'ALL'

# 隨機字符串 隨機字符串,不長于32位。推薦隨機數(shù)生成算法
nonce_str = str(uuid.uuid4()).replace('-', '')

# 下載對賬單
url = 'https://api.mch.weixin.qq.com/pay/downloadbill'

# 對賬單日期
bill_date = 'xxx'

# 輸入?yún)?shù)
params = '''
    <xml>
      <appid>%s</appid>
      <bill_date>%s</bill_date>
      <bill_type>%s</bill_type>
      <mch_id>%s</mch_id>
      <nonce_str>%s</nonce_str>
      <sign>%s</sign>
    </xml>
'''

encoding = 'utf-8'

md5 = hashlib.md5()


# 生成簽名
def md5_count():
    strs = 'appid=%s&bill_date=%s&bill_type=%s&mch_id=%s&nonce_str=%s&key=%s' % (appid, bill_date, bill_type, mch_id,
                                                                                 nonce_str, key)
    md5.update(strs)
    return md5.hexdigest().upper()


# 持久化
def persistence(text):
    try:
        con = Mysql(user='root', password='', host='127.0.0.1', port=3306, database='test')
        print '持久化數(shù)據(jù):'
        lines = text.split('\r\n')
        print '表頭: %s' % lines.pop(0)
        while len(lines) > 3:
            line = lines.pop(0)
            con.save_list('insert into YM_wx_pay values(%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,'
                          '%s,%s,%s,%s,%s,%s,%s,%s)', line.split(','))
        print '-----------------------'
        print lines.pop(0)
        print lines.pop(0)
    finally:
        if con:
            con.close()


if __name__ == '__main__':
    params = params % (appid, bill_date, bill_type, mch_id, nonce_str, md5_count())
    request = requests.post(url, data=params)
    request.encoding = encoding
    if request.text and not request.text.__contains__('return_code'):
        persistence(request.text)
    else:
        print request.text
        print '接口返回參數(shù)有誤!'

MysqlUtil.py

# -*- coding:utf-8 -*-
import mysql.connector


class Mysql(object):
    def __init__(self, user, password, host, port, database):
        self.__conn__ = mysql.connector.connect(user=user, password=password,
                                                host=host, port=port,
                                                database=database)
        self.__cursor__ = self.__conn__.cursor()

    def save_list(self, sql, params):
        self.__cursor__.execute(sql, params)
        self.__conn__.commit()

    def close(self):
        self.__cursor__.close()
        self.__conn__.close()
支付寶對賬單

需要引入SDK然后按照代碼示例拉取對賬單,目前SDK有Java,.NET,PHP,靈活性沒有微信接口好,不能用Python大法解決。

搜狗搜索

當我們要開始探索某個未知的領域,首先會想到在網(wǎng)上查找相關資料,谷歌無疑是很棒的搜索工具;但是現(xiàn)在有很多干貨是在知乎或微信公眾號發(fā)布的,谷歌搜索并不能很好的覆蓋這兩個內(nèi)容來源,搜狗搜索可以對微信公眾號以及知乎內(nèi)容進行檢索,起到了很好的輔助作用。

Python關于線程的幾個知識

使用Python腳本跑數(shù)據(jù),跑了2個多小時,事后分析每部時間耗費,發(fā)現(xiàn)主要是執(zhí)行sql導致等待時間過長;首先想到使用多線程來提升并發(fā)度,減少CPU等待時間;更優(yōu)的方法是使用協(xié)程來,既提升并行度同時不會造成頻繁的CPU上下文切換。

啟動一個線程:

import threading

def print_str():
        print 'hello world %s.' % threading.current_thread().name


t = threading.Thread(target=print_str)  # 實例化一個線程,比Java簡單多了

t.start()  # 啟動線程
t.join()  # 主線程等待直到線程t執(zhí)行完畢
t.join(1)  # 主線程等待線程t執(zhí)行(最多等待1m)

鎖:

lock = threading.Lock()  # 創(chuàng)建一個鎖
lock.acquire()  # 加鎖
lock.release()  # 解鎖 通常寫在finally里

線程本地變量:

local = threading.local()  # 線程本地變量 HTTP使用較多
local.name = 'xxx'

try:
     age = local.age  # 注意:假設我從local中取一個不存在變量拋出異常
except AttributeError:
    pass

線程池:

from multiprocessing.dummy import Pool as ThreadPool

pool = ThreadPool()  # 默認創(chuàng)建線程數(shù)量等于當前機器CPU核數(shù)

def test(url):
    print url


results = pool.map(test, ['http://www.baidu.com', 'http://www.sina.com', 'http://www.qq.com'])  # 這樣線程就可以并發(fā)地從列表中取出字符串處理
pool.join()

注意:
因為Python GIL限制,多線程是偽多線程,代碼依然在一個CPU中跑。
適用于IO密集型任務中;I/O密集型執(zhí)行期間大部分是時間都用在I/O上,如數(shù)據(jù)庫I/O,較少時間用在CPU計算上。

Java PriorityQueue VS DelayQueue

PriorityQueue:優(yōu)先隊列,正如在之前文章中所說其本質(zhì)上是一個二差堆,根節(jié)點是最小值,添加元素刪除元素的時間復雜度都是logn。

        PriorityQueue priorityQueue = new PriorityQueue();  // 如果沒有設置比較器,會使用插入對象的compareTo方法。
        priorityQueue.add(10);
        priorityQueue.add(5);
        priorityQueue.add(3);
        System.out.println(priorityQueue.peek());  // 查看堆頂元素
        System.out.println(priorityQueue.poll());  // 拿出堆頂元素

DelayQueue:延時隊列,在PriorityQueue基礎上擴展來的。

簡單解釋:現(xiàn)在有3個任務,任務1要求5分鐘后執(zhí)行,任務2要求1分鐘后執(zhí)行,任務3要求10分鐘后執(zhí)行;把這三個任務添加到DelayQueue中然后在1分鐘后彈出任務2執(zhí)行,5分鐘后彈出任務1執(zhí)行,10分鐘后彈出任務3執(zhí)行。

    static class T implements Delayed {

        public long t;

        public T(long t) {
            this.t = t;
        }

        @Override
        public long getDelay(TimeUnit unit) {
            return t - System.nanoTime();
        }

        @Override
        public int compareTo(Delayed o) {
            return this.getDelay(null) - o.getDelay(null) > 0 ? 1 : -1;
        }
    }

    public static void main(String[] args) throws InterruptedException {
        DelayQueue<T> delayQueue = new DelayQueue();
        long time = System.nanoTime();
        delayQueue.add(new T(time + 1000000000l));  // 1秒
        delayQueue.add(new T(time + 10000000000l));  // 10秒
        delayQueue.add(new T(time + 5000000000l));  // 5秒
        System.out.println(delayQueue.take().t);  // take是阻塞方法,直到到期然后繼續(xù)執(zhí)行
        System.out.println(delayQueue.take().t);
        System.out.println(delayQueue.take().t);
    }

take方法是如何在沒有元素到期時阻塞在有元素到期是喚醒彈出元素的呢。

    public E take() throws InterruptedException {
        final ReentrantLock lock = this.lock;
        lock.lockInterruptibly();  // 加鎖來避免多線程問題
        try {
            for (;;) {
                E first = q.peek();
                if (first == null)
                    available.await();
                else {
                    long delay = first.getDelay(NANOSECONDS);  // 假設當前元素已到期
                    if (delay <= 0)
                        return q.poll();  // 彈出
                    first = null; // don't retain ref while waiting
                    if (leader != null)
                        available.await();
                    else {
                        Thread thisThread = Thread.currentThread();
                        leader = thisThread;
                        try {
                            available.awaitNanos(delay);  // 假設當前對象沒有到彈出時間,等待(執(zhí)行時間 - 當前時間)時間后自動喚醒 注意:單位是納秒
                        } finally {
                            if (leader == thisThread)
                                leader = null;
                        }
                    }
                }
            }
        } finally {
            if (leader == null && q.peek() != null)
                available.signal();
            lock.unlock();
        }
    }
最后編輯于
?著作權歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容