Python Paramiko 筆記

在以前公司工作的時候,有點忘了是遇到什麼情境,總之我就看到python 有這樣的一個套件庫:Paramiko

話不多說,我們就給大家來看文件吧:http://www.paramiko.org/

然後就結束這一回合(阿不是!

他是一個和SSH 有關的套件庫,是可以使用python 直接在遠端給他執行程式起來… 啊寫文章的同時我就想到了!之前我們好像是要做那個資料庫備份什麼的, 然後有發現說有時server 會不夠空間backup , 所以後來我就用這個套件透過本機去連結遠端執行 df -h 的指令,以方便告訴我到底有沒有足夠的空間這樣…. 不然每次連線打指令實在很麻煩…

然後 , 我最喜歡的是: show you the code !

import paramiko

paramiko.util.log_to_file('paramilo.log')
key = paramiko.RSAKey.from_private_key_file("pem path...")

ssh = paramiko.SSHClient()
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
ssh.connect(hostname='......',username='user',pkey=key)

stdin, stdout, stderr = ssh.exec_command('df -h')

result = open('log.txt','wb')
result.write(stdout.read())
result.close()

ssh.close()
小君曰:我到底寫了什麼...?

原來可以這麼寫(9):結果我變成python 工程師?

祝大家新年快樂。原來可以這麼寫這個系列終於來到第九篇!

說聲好消息,最近工作獲得肯定(撒花~)。只是不知道年終到底有多少…搞不好…其實很少…. 這個就題外話啦,在這個公開網路場合還是不宜多說XD

從資料庫匯出資料

最近接到一個需求,是要從資料庫匯出資料。其實這個東西並不是很難,寫寫SQL 語法就能搞定…但因為安全的因素我們的資料庫通常要透過SSH 跳板才能進去。可是他們匯出資料的需求是要by 一個顧客(客戶),你媽咧我難道一個一個SQL 撈出來然後再丟進Excel 嗎?

不!這絕對不是工程師的思維… 後來想想我在我第一份工作的時候開啟了一個side project : office: https://github.com/r567tw/office

那時候為什麼我要開啟這個專案呢?原因是,我當時負責重構一個網站系統,是用Laravel 重構原本native php 改寫的報名網站…. (這大概可以說是我工程師生涯其中一個直得常常拿出來說嘴的一個成就…但當然啦我之後在想覺得那時候我初出茅廬才維護一年多就改寫實在有點冒險…只怪我當時太年輕太衝動太不懂事了…. 裡面還是有一些遺珠之憾等級的小後悔~)

啊話說開了,總之那時候有要驗證台灣的身分證字號,還有生成台灣的身分證字號…這當然網路上可以有工具可以用啦,但你不覺得開瀏覽器->搜尋-> 點進網址 -> 可能還有點一些按鈕bla 的才能搞定自己的需求很麻煩嗎?

於是你看到office 裡面就有一個資料夾應運而生:id_card_number

隨著時間推移,裡面的工具也越來越多XD

這次我就用到使用ssh 連接到database 來幫我完成需求的工具:connectDBthoughSSH

import pymysql
import sshtunnel 
import dotenv
import os

dotenv.load_dotenv()

server = sshtunnel.SSHTunnelForwarder(
    ssh_address_or_host=(os.getenv('SSH_HOST'), 22), # 指定ssh登入的跳轉機的address
    ssh_username=os.getenv('SSH_USER'), # 跳轉機的使用者
    ssh_pkey=os.getenv('SSH_PEM_PATH'), # 跳轉機的密碼
    remote_bind_address=(os.getenv('DB_HOST'), 3306)
)

server.start()

db = pymysql.connect(
    host='127.0.0.1',
    port=server.local_bind_port,
    user=os.getenv('DB_USER'),
    passwd=os.getenv('DB_PASSWORD'),
    db=os.getenv('DB_DATABASE')
)

cur = db.cursor(pymysql.cursors.DictCursor)

cur.execute('select id,name from clients')

clients = cur.fetchall()

db.close()
server.close()

接下來,拿到sql 的資料之後就是python 和 excel 的問題了,撒花!

匯入第二波小說資料

因為目前時程與安排的緣故,目前匯入資料暫時由工程師處理,前面的應用到step function 就是其中一環的應用,但說真的,前面這一環的資料匯入,我開發幾個 laravel 的 api , 實在規劃的! 很!爛! 我愧對我作為工程師的身份啊…

經過漫長快一個禮拜的規劃… 我想到他馬的我為什麼要繼續用PHP完成我這個需求?用Python 呢?

再經過兩~三天的研究與開發, python 的版本終於應運而生!不過裡面資料先暫時用在sqlite 上面, 之後我想把它放在mysql 資料庫上面… 然後寫好專案裡面的readme和說明,不用我只要大家用這個程式就可以做使用,多自動化多方便啊… 這是我這個的最終目標啊!

嘗試做一些改變

目前,我是一名後端工程師,我的專案其實就只有一個。這一個專案負責官網、後台、ios/android app 的API, 同時也需要與交易的 Lambda 溝通,去年我甚至也主導單集銷售模式的Lambda 開發,而我在接手此專案的過程中曾發下宏願:

  1. 完整文件化
  2. 導入TDD,甚或是DDD , 強化程式碼品質、程式碼架構彈性

目前我自認自己將文件化的目標至少有70-80%,我很努力的研究swagger 怎麼寫,創造一個較為優良的swagger文件的環境,整理目前就我角度上專案的開發現況,導入代碼表的文件在每個需要代碼的swagger 文件。也在多次與app team/PM/官網/後台 有多次的溝通摩擦、gap , 雖然是有點加重了我個人的loading , 但至少在開發前做一次好好地確認、流程、導入mock api 的機制先在開發前作討論。

我不知道,我這樣的做法,是否對於各方角度team 有好的成效、好的溝通效率?甚願可以。希望可以。畢竟API 的 DX 很差,那我這個後端工程師真的不用在繼續幹下去了!

接下來,希望完成資料庫的文件化,也希望程式的TDD, 測試能一一地補上。這是我接下來要努力的目標之一。

每次改變一點點,這也是DevOps 文化的其中一環麻。

小君曰:原來這次我是python工程師?

將鐵人賽的文章搬到部落格

好久沒有寫文章了,清清一下灰塵~

不過眼尖的會發現,目前我的部落格裡面也包含了前兩次我參加it鐵人賽的文章。因為後來我起了一個python爬蟲爬我自己鐵人賽的文章,然後發出request給自己的部落格新增文章。不過在之前要啟用一下自己的部落格可以開放網路發request用,所以要安裝一個package:Application Passwords plugin

詳情的話可以參考這篇文章:https://www.yannyann.com/2018/09/wp-rest-api-create-new-post-and-upload-image/

然後我的相關程式碼放到我的office 那裡了:https://github.com/r567tw/office/tree/master/ItHomeToTechBlog

小君曰:完成今年一大目標,打勾✔️

 

 

Pytest 簡單教學

最近在整理自己的履歷和side projects……,順便也買了一些線上課程學習,其中有一門課是教你演算法,舉Leetcode 裡面的題目為例,如果再工程師界久了都知道,Leetcode 是一個刷題網站,而我身為想要變強的工程師當然不可以忽略這個網站啊…… 因此在bitbucket 開了一個專案,放置一些藉由上課所學習的解題檔案(線上課程用的是JAVA),但我想要轉成Python ,藉此提升自己的python實力~~

如果有興趣可以來看看,但因為目前上課進度緩慢,其實也才幾題而已XD https://bitbucket.org/r567tw/leetcode/src/master/

不過在本機跑的時候也想要自己就先在本機測試一下不要用leetcode 在那邊幫我測試…但之前都是用類似以下的語法

test = Solution(); #先new 一個Solution 的class
print(Solution.method(...)) #然後呼叫方法一個一個用肉眼檢查

這種方法超級土法煉鋼的… 完全就不是工程師的style ~~

而我是一個php工程師,之前花了一點時間了解phpunit , 然後也有在一些專案寫一些UnitTest… 心想…. 難道python 沒有嗎?

叮咚! 原來就是Pytest 啊! 我現在leetcode 刷題要在本機測試都會使用這個來玩玩看的!接下來我要介紹怎麼使用Pytest,以及我如何將這個導入到我這個leetcode 的練習專案。

安裝Pytest

首先你要使用pytest 之前就一定要確認pytest 有沒有在你的電腦當中(廢話!),所以你可以參考這個文件來幫助你安裝pytest ,其實也就這麼簡單

$ pip install pytest

然後其實很簡單,就是使用pytest 這個指令或者pip freeze 確認pytest 在不在就好了啊

使用Pytest

其實和phpunit 很像,其實也是用所謂“assert”的方式確認答案是否正確,以底下程式碼為例說明:

from solutions.atoi import Solution


def test_myAtoi():
    test = Solution()
    assert(test.myAtoi("42") == 42)
    assert(test.myAtoi("   -42") == -42)
    assert(test.myAtoi("4193 with words") == 4193)

其實Pytest 的部分就是去偵測你的個函數名稱是否前綴有個`test` ,如果有的話就會跑底下的內容,於是一個完美個TDD流程完成!

接下來就是跑個指令、然後看看結果就好了,以我目前很緩慢只有解Atoi\Palindrome\Pow 的狀況就像底下的情況一樣

alindrome

$ pytest
============================================= test session starts =============================================
platform darwin -- Python 3.6.4, pytest-3.3.1, py-1.5.2, pluggy-0.6.0
rootdir: /Users/fang/playground/leetcode, inifile:
collected 3 items                                                                                             

tests/test_atoi.py .                                                                                    [ 33%]
tests/test_palindrome.py .                                                                              [ 66%]
tests/test_pow.py .                                                                                     [100%]
========================================== 3 passed in 0.05 seconds ===========================================

你寫幾個測試檔案,裡面就會有幾個items ,如果你最後沒看到什麼failed 的話就表示你都很順利喔~

剩下的我就利用一些modulte 引入的概念,將資料夾很清楚分出tests 和 solutions ,之後我就在solutions 裡面放入leetcode 這題的解法,而tests 裡面放的就是要被驗證的結果,沒過pytest 就會告訴我沒過了

小君曰:之後要參加鐵人賽了,就決定暫時不繼續努力週更了XD

 

Pytube 簡單教學

來寫個簡單的python 教學好了,對了! 去年我有挑戰it 幫鐵人賽,參加的是自我挑戰組,並且自己訂的主題就是python 30天! 歡迎大家去看看!

連結於此

對於鐵人賽完賽的心得不必多說,我想已經都寫在最後一天了,總之就是覺得自己還有很大的成長空間,下次參加鐵人賽一定要有更充足的準備和題目。

不得不說,這次鐵人賽的獎品
我個人覺得好浮誇……

好了,簡單交代近況也夠了,進入主題來談談python 好用的套件pytube 吧!

pytube 是用來可以抓youtube的影片,首先,你必須先安裝它

$ pip install pytube

接下來你可以確認一下pytube 是否正常運作?

$ pytube --version
$ pytube 9.4.0

注意:

如果你是最新安裝pytube version 應該會是9.5.1 , 不過pytube 9.5.1 有些問題,可以參考此連結解決問題

接下來我們就可以開始寫下載youtube影片的程式啦!
這裡我只是簡單呈現怎麼撰寫,詳細與延伸可以參考文件:https://python-pytube.readthedocs.io/en/latest/#
小君曰:不知道為什麼文件的版本似乎落後了我目前寫的版本…

# 就是這麼簡單!!!!
from pytube import YouTube

url =input('請輸入你要下載的youtube網址: ')
print('下載 來自'+url+' 的youtube影片中...')
YouTube(url).streams.first().download()

像我自己想要更加炫技一下就會想知道我目前youtube影片的名字的話可以這樣寫….. 加入beautifulSoup 這個可以分析網頁的套件。

from pytube import YouTube
import requests
from bs4 import BeautifulSoup

url =input('請輸入你要下載的youtube網址: ')

# 先去youtube 上看看這部影片的名字
request=requests.get(url)
context = request.content
# 藉由BeautifulSoup
soup=BeautifulSoup(context,"html.parser")
# 取得我要的資料
video_name = soup.select('h1.watch-title-container')[0].get_text();
# 資料清理
video_name = video_name.replace('\n','')
video_name = video_name.replace(' ','')
# 準備下載啦
print('下載 來自'+video_name+' 的youtube影片中...')
YouTube(url).streams.first().download()
print('下載完成!')

Python_Virtualenv 簡單筆記

前言

有點xx 久沒有寫文章了…
這次來筆記一下python virtualenv~ 一個使用不會污染原本python package 的東西~ 有點類似虛擬環境的概念。

雖然後來發現…python 3 好像也有提供自己的virtual env… 指令是“python3 -m venv {這裡放置的是你要的環境名稱}”,然後要啟動他其實和關閉它其實和vituralenv 有點差不多…

Notice: 以下我使用的環境都是for Mac , 如果你是其他作業系統可以參考但請查閱文件

安裝

不多說,安裝pip 後請服用

pip install virtualenv

然後確定是否有安裝成功請服用

virtualenv --version

如果有出現一串數字那就表示可以用啦!如果有安裝上的錯誤請自行google, 或者在底下留言,有空的話我可以幫忙trace 一下啦,順便一起成長~

使用

1.創造虛擬環境

virtualenv {接你想接的任何環境名稱}
舉例來說: virtualenv testenv

然後等他跑一下你會看到目錄下有個被你指定的名稱資料夾,以例子來看就是testenv資料夾,裡面大概長這個樣子

PS. 以下我都會用testenv這個資料夾名稱作為範例,你們要使用請將testenv換成任何你們想換的資料夾名稱呦

testenv
├── bin
├── include
├── lib
└── pip-selfcheck.json

Tips: 上面這麼完美的一個資料夾樹是我用tree 這個指令做的,使用“tree -L 1 testenv” , 你可以用brew 安裝tree 之後應該就可以服用,L是一個參數,你可以在後面輸入數字選擇你想顯示的資料夾階層數目

2.啟動虛擬環境
請服用

source testenv/bin/activate

接下來你會看到你的command line 最前面有(testvenv) 的字樣(或者任何你設定的資料夾名稱)

Tips: 小弟查過關於source 這個指令的傳說,就是將執行的指令檔裡面所設的參數或者內容應用到整個command line 環境中…

像是:

(testenv) xxx@xxx-MacBook-xxx-$

3.離開虛擬環境
已經在虛擬環境中如果想離開請用

deactivate

沒錯!就是這麼簡單

4.其他你可能在虛擬環境裡有幫助的指令們
– 查python或pip 安裝的版本

python --version
pip --version
  • 查看pip 安裝了哪些modules
pip freeze
  • 將pip 安裝的modules 紀錄,這樣以後才能讓別人一鍵安裝
pip freeze > requirements.txt
  • 藉由別人提供的紀錄安裝python module
pip install -r requirements.txt

幕後花絮

一般來說用vituralenv 創造的python 版本都會是python 3以上,但如果今天我要python 2呢?(雖然python 2 已進入倒數)

virtualenv {你的資料夾名稱} --python=python2.7

P.S. 請確定你有裝python2.7 或你指定的版本喔…另外聽說也可以使用pythonbrew 解決這個情況…不過小弟試過好像有點卡關可是我也沒有面對要python多版本的部分所以就果斷放棄

剩下的我都放在文件裡了,好啦也不是我寫的文件,有關於virtualenv的其他使用或進階用法可以參考這個文件

小君曰:還是多寫寫文章增加自己的實力好了

Python 鐵人賽:遺珠之憾

最後一天,終於寫到這裡

第一次參加鐵人賽,很幸運的可以連續30天完成。甚至有些時候差點要超過時間完成不了鐵人賽
看了之前鐵人賽的文章,似乎過了一段時間在完成30天就會把挑戰第幾天凍結。(我也想要有鐵人煉成的成就啊~~

說真的這次給了我一個經驗,就是下次可能也要預先存幾個草稿好讓我可以之後準時發布
我覺得也感謝我這次參加鐵人賽的經驗,讓我有機會好好整理python的學習

總之,我來談談這次python鐵人賽沒談到的遺珠之憾吧
同時也是我之後會繼續專研的方向

  1. 基本與物件導向
  2. 多執行緒的議題
  3. 更深入的 Django和Flask
  4. 更深入的Pandas
  5. 關於機器學習/人工智慧:TensorFlow+Keras
  6. 其他爬蟲的框架:scrapy
  7. MapReduce 和 Spark 或Handoop

個人自己有看過的書籍而且覺得不錯
1)Python初學特訓班
2)Python 自動化的樂趣:搞定重複瑣碎&單調無聊的工作
3)Python新手使用Django架站的16堂課:活用Django Web Framework快速建構動態網站
不過這本架站的16堂課已經是舊版,如果要新版的請至此(Python新手使用Django架站技術實作:活用Django 2.0 Web Framework建構動態網站的16堂課)
https://www.books.com.tw/products/0010790747

個人推薦相關線上課程

  1. https://morvanzhou.github.io/
  2. Youtube
  3. Hahow 也有相關python的課程,我自己在上的有:「Python 網頁爬蟲入門實戰」和「用 Python 理財:打造小資族選股策略」

Python 資料科學:Pandas

今天來說說資料分析的python modules — pandas

首先我們來安裝他

pip install pandas

接下來我要介紹在pandas兩個資料結構 Series 和 DataFrame
他們的宣告很簡單,而且樣式也是很簡單,
首先是series

import pandas as pd

l = [1,2,3,56,7,7,73,3,3,2]

date = pd.date_range('20180731',periods=10)
s = pd.Series(l,index= date)
print(s)

print(s)接下來你就會看到

2018-07-31     1
2018-08-01     2
2018-08-02     3
2018-08-03    56
2018-08-04     7
2018-08-05     7
2018-08-06    73
2018-08-07     3
2018-08-08     3
2018-08-09     2
Freq: D, dtype: int64

所以series 很簡單,你可以想像成一個關係數列,然後之後我們可以藉由呼叫這個series的各種方法,如下

print(s.loc['20180731']) #因為index 是時間可以這樣呼叫=>1
print(s.loc['20180731':'20180802']) #因為index從2018-07-31到2018-08-02 的值
'''
2018-07-31    1
2018-08-01    2
2018-08-02    3
Freq: D, dtype: int64
'''
print(s.iloc[6]) #也可以用index喔(從0開始)-->73
print(s.iloc[5:7]) #iloc 最後一筆不算,所以會從5-6
'''
2018-08-05     7
2018-08-06    73
Freq: D, dtype: int64
'''
print(s.max()) #最大值 -->73
print(s.min()) #最小值 -->1
print(s.mean()) #平均值 -->15.7
print(s.std()) #標準差 -->26.106831800635376

還有其他的方法,請大家可以自行參考這裡。
https://pandas.pydata.org/pandas-docs/version/0.23.4/generated/pandas.Series.html

再來,我要介紹關於dataframe的部分,dataframe簡單來說就是許多series組成的

import pandas as pd

date = pd.date_range('20181029',periods=3)
s1 = pd.Series([1,2,3],index=date)
s2 = pd.Series([4,5,6],index=date)
s3 = pd.Series([7,8,9],index=date)
df = pd.DataFrame() #empty dataframe
df = pd.DataFrame({'c1':s1,'c2':s2,'c3':s3})
print(df)

print df就會長得像這樣

import pandas as pd

date = pd.date_range('20181029',periods=3)
s1 = pd.Series([1,2,3],index=date)
s2 = pd.Series([4,5,6],index=date)
s3 = pd.Series([7,8,9],index=date)
df = pd.DataFrame() #empty dataframe
df = pd.DataFrame({'c1':s1,'c2':s2,'c3':s3})
print(df)

print df就會長得像這樣

            c1  c2  c3
2018-10-29   1   4   7
2018-10-30   2   5   8
2018-10-31   3   6   9

同樣的,他也和series支援很多方法

df.loc['2018-01-05']
'''
c1    2
c2    5
c3    8
'''

df.loc['2018-01-01':'2018-01-02',['c1','c2']]
'''
            c1  c2
2018-01-01   1   4
2018-01-02   2   5
'''

df.iloc[1:3,[2,1]]
'''
            c3  c2
2018-01-02   8   5
2018-01-03   9   6
'''

Python 網頁:Flask

寫到這裡真的覺得自己下次要參加鐵人賽要想清楚。 要規劃好內容,也可能自己要寫一些存擋備份(不知道那些完成鐵人賽的是不是都是這樣?)

不然有時候寫到後面,真的不是很想繼續寫下去、也覺得自己寫的內容有點爛XD

也或許自己寫的這個技術並不是自己最在行的,而是自己下班的閒暇之餘所寫的,所以如果有錯或者有什麼提供建議再精進的方向給我!

今天要介紹Flask
首先,就是要先安裝flask啊!

pip install flask

接下來建立我們的檔案 index.py

from flask import Flask
app = Flask(__name__)
@app.route("/")
def hello():
    return "Hello World!"
if __name__ == "__main__":
    app.run()

最後我們執行index.py就會看到類似底下的訊息

* Serving Flask app "index" (lazy loading)
 * Environment: production
   WARNING: Do not use the development server in a production environment.
   Use a production WSGI server instead.
 * Debug mode: off
 * Running on http://127.0.0.1:5000/ (Press CTRL+C to quit)

接下來輸入http://127.0.0.1:5000/ 到瀏覽器裏
就會看到Hello World 囉

Python 網頁:Django- 來做一個部落格(2)

今天,想把Django篇先結束XD

昨天,我們已經將post這個表註冊到後台並且已經migrate它
現在,我們要開始做前端的畫面並且能夠顯示。 這非常的陽春,如果需要更加深研的請歡迎自行搜尋

首先你會好奇為什麼在後台儲存資料卻是post object,原因是你沒有設定要顯示的什麼東西

所以在這裡請編輯models.py

from django.db import models
from django.utils import timezone

# Create your models here.
class Post(models.Model):
    title = models.CharField(max_length=200)
    slug = models.CharField(max_length=200)
    content = models.TextField()
    pub_date = models.DateTimeField(default=timezone.now)

    def __str__(self):
        return self.title

加入 _str__ 方法並回傳他要回傳的名稱這樣就可以在後台看到標題了

然後請編輯一下blog/urls.py

...(略)
from django.contrib import admin
from django.urls import path
from mblog import views

urlpatterns = [
    path('', views.homepage, name='homepage'),
    path('admin/', admin.site.urls),

]

將mblog/view.py引入,然後宣告首頁指向他

接下來編輯views.py

from django.shortcuts import render

from .models import Post

# Create your views here.
def homepage(request):
    posts = Post.objects.all()
    context = {
        'posts_list': posts
    }
    return render(request, 'homepage.html', context)

定義一個hombepage 方法,然後宣告他要傳的template 為homepage.html

最後請在mblog 裡面新建一個資料夾:templates,裡面有一個新檔案加入homepage.html

{% if posts_list %}
    <ul>
    {% for post in posts_list %}
        <li><a href="#">
            {{ post.title }}</a>
        </li>
    {% endfor %}
    </ul>
{% else %}
    <p>沒有文章可以顯示</p>
{% endif %}

這樣一個簡單的文章列表就會產生

此時我們的資料夾結構

./
├── blog
│   ├── __init__.py
│   ├── __pycache__
│   │   ├── __init__.cpython-36.pyc
│   │   ├── settings.cpython-36.pyc
│   │   ├── urls.cpython-36.pyc
│   │   └── wsgi.cpython-36.pyc
│   ├── settings.py
│   ├── urls.py
│   └── wsgi.py
├── db.sqlite3
├── manage.py
└── mblog
    ├── __init__.py
    ├── __pycache__
    │   ├── __init__.cpython-36.pyc
    │   ├── admin.cpython-36.pyc
    │   ├── apps.cpython-36.pyc
    │   ├── models.cpython-36.pyc
    │   └── views.cpython-36.pyc
    ├── admin.py
    ├── apps.py
    ├── migrations
    │   ├── 0001_initial.py
    │   ├── __init__.py
    │   └── __pycache__
    │       ├── 0001_initial.cpython-36.pyc
    │       └── __init__.cpython-36.pyc
    ├── models.py
    ├── templates
    │   └── homepage.html
    ├── tests.py
    └── views.py