分類彙整: Python範例

Python IDEs 常見的整合開發環境介紹

Python IDEs

俗語說  ”工欲善其事,必先利其器 ” 。
所以在撰寫 python 程式時,挑選好的開發工具 Python IDEs 是蠻重要的一件事情。其實 Python官方的安裝包裡面含有 IDLE,已經是個麻雀雖小五臟俱全的IDE了,對於初學的人其實已經蠻夠用了。
但如果能了解有哪些不錯的IDEs,對於我們未來撰寫功能更複雜的大型專案,或是有資料科學領域上的需求就能使用更方便、更合適的工具,對於開發效率上也能有所提升。

以下介紹一些 Python 常見的 IDEs (Integrated Development Environment):

Spyder

如果有安裝過 Anaconda distribution 版本的話,應該會知道Spyder。Spyder整合了NumPy,SciPy,Matplotlib 與 IPython,以及其他開源軟體。
  • 編輯器:支援多語言,具有函式和類檢視器,代碼分析特性(pyflakes 和 pylint 獲得了支援),代碼補全,水平與垂直視窗的分離,直接跳入定義等等。
  • 互動埠: Python 或 IPython 埠都在工作區可以調整和使用。支援對編輯器里的代碼直接偵錯。此外整合了 Matplotlib 的圖表顯示。
  • 文件瀏覽器:在編輯器或埠中顯示任意類或函式呼叫的文件。
  • 可變的瀏覽窗口:在檔案的執行過程中可以建立可變的瀏覽窗口。同時也可以對其進行編輯。
  • 在檔案中尋找:支援正規表示式與 Mercurial 倉庫
  • 檔案瀏覽器
  • 歷史記錄

Jupyter Notebook

Python IDEs - jupyter notebook

與Spyder一樣,被包含在 Anaconda distribution 的版本之中,若要獨立使用 pip 安裝亦可。
透過網頁介面,可以將程式碼寫在不同的 Cell (區塊) 之中,並且分段落執行,已執行過的程片段會存在記憶體中,所以對於調整參數或是做測試來說,相當的方便,比如有時候想要看變數的值,直接開個 Cell 印出來看就好了
  • 支援超過 40 種程式語言,比如 Python、R,、Julia 與 Scala
  • 可以透過 email、Dropbox、GitHub 或是 Jupyter Notebook Viewer 與他人分享 Notebook
  • 可以顯示多媒體資源,比如圖片、影片、LaTeX 甚至是JavaScript,也可以做 realtime 的資料視覺化
PS1. 微軟的 Azure Notebooks 就是使用 Jupyter Notebook。目前提供免費的線上開發服務,若還沒安裝本機端 IDE,但是想先體驗看看 Jupyter Notebook 也可以直接登入用看看。
PS2. 之前有寫一篇使用 Python 擷取 AQI 空氣品質資料的範例,就是在 Azure Notebooks 這個服務上寫的。 範例程式

PyCharm

https://www.jetbrains.com/pycharm/

PyCharm是由捷克公司JetBrains開發。提供代碼分析、圖形化調試器,集成測試器、集成版本控制系統(Vcs),並支持使用Django進行網頁開發。
是一套功能非常完善也強大的跨平台開發的環境。
主要功能:
  • 代碼分析與輔助功能,擁有補全代碼、高亮語法和錯誤提示;
  • 項目和代碼導航:專門的項目視圖,文件結構視圖和和文件、類、方法和用例的快速跳轉;
  • 重構:包括重新命名,提取方法,引入變量,引入常量、pull,push等;
  • 支持網絡框架: Django, web2py 和 Flask;
  • 集成Python 調試器;
  • 集成單元測試,按行覆蓋代碼;
  • Google App Engine下的Python開發;
  • 集成版本控制系統:為Mercurial, Git, Subversion, Perforce 和 CVS提供統一的用戶界面,擁有修改以及合併功能。

PyDev

PyDev 是 Eclipse 的 插件 plugin,若有使用過 Eclipse寫過 Java 或是開發過 Android  很習慣在Eclipse上面開發程式的話,
可以考慮安裝 PyDev 來開發 Python 程式,當然其功能也是相當完整。

Visual Studio

微軟出的 Visual Studio 應該非常多人聽過也用過,也支援Python的程式語言開發
若有使用過 Visual Studio 開發過 C#、VB.NET、ASP.NET 等相關微軟平台上的程式專案開發的話,那麼在這個介面上開發 Python 程式或許也是個不錯的選擇。

結語

當然還有非常多不錯的 Python IDEs 沒有列舉出來,待之後有時間再補上來。

Pandas+SQL-空氣品質資料擷取

Pandas+SQL 操作 – 前言

Pandas+SQL 的操作範例,本篇文章以政府開放資料平台中的 空氣品質指標(AQI) 為資料來源,展示了如何使用 pandas 搭配 SQL 語法 來做資料搜尋,對於已經有 SQL 語法操作基礎的人,可以用之前學過的 SQL 語法快速的搜尋並篩選出所需要的資料,提供大家參考。

Pandas 簡介

Pandaspython 的一個數據分析模組庫,於 2009 年底開源出來,提供高效能、簡易使用的資料格式 (Data Frame) 讓使用者可以快速操作及分析資料,主要特色描述如下:

  • 在異質數據的讀取、轉換和處理上,讓分析人員更容易處理,例如:從列欄試算表中找到想要的值。
  • Pandas 提供兩種主要的資料結構,SeriesDataFrame
    • Series: 用來處理時間序列相關的資料(如感測器資料等),主要為建立索引的一維陣列。
    • DataFrame: 用來處理結構化(Table like)的資料,有列索引與欄標籤的二維資料集,例如:關聯式資料庫、 CSV  等等。
  • 透過載入至 Pandas 的資料結構物件後,透過結構化物件所提供的方法,快速地資料前處理。例如:資料補值,空值去除或取代等。
  • 更多的輸入來源及輸出整合性,例如:可以從資料庫讀取資料進入 Dataframe ,也可將處理完的資料存回資料庫。

本篇文章就是使用 DataFrame 搭配關連式資料庫,使用 SQL 語法進行資料查詢篩選,而未來有時間再整理更多其他 Pandas 相關的應用範例。

安裝 Pandas

Python 安裝方式一樣都是透過 pip install 即可完成安裝,語法如下:

pip install pandas  

其他介紹可以參考 官方網站

JSON

JSONJavaScript Object Notation)是一種由道格拉斯·克羅克福特構想設計、輕量級的資料交換語言,以文字為基礎,且易於讓人閱讀。儘管 JSON 是 Javascript 的一個子集,但 JSON 是獨立於語言的文字格式,並且採用了類似於 C語言 家族的一些習慣。此種格式與XML格式常被用於API的資料回傳格式。本篇文章的程式碼範例就是以 JSON 格式的內容為資料的輸入來源。

範例程式碼

此範例程式主要流程大致為:

  1. 透過 requests 呼叫政府公開資料的 API 得到空氣品質指標的資料( JSON 格式)
  2. 透過 json.loads 函數將資料讀入
  3. 使用 pandas DataFrame 產生出資料框
  4. 透過 sqlalchemy 模組中的 create_engine 函數來建立 sqlite 的連線 ,並設定將資料表儲存在 memory 中(提供一次性的操作使用,若需要永久儲存則可以寫入檔案中)
  5. 使用 SQL 語法作取出特定的欄位(縣市、區域、平均 PM2.5 值)並以 PM2.5 的值由大至小排序。
import json
import requests
import pandas as pd
'''
資料庫的讀寫函數可以使用 SQLAlchemy,支援 PostgreSQL, MySQL, Oracle,
Microsoft SQL server 等資料庫...
'''
from sqlalchemy import create_engine

req = requests.get('http://opendata2.epa.gov.tw/AQI.json')
data = json.loads(req.content.decode('utf8'))
df = pd.DataFrame(data)

#透過sqlalchemy模組中的create_engine函數來建立sqlite的連線
#並設定將資料表儲存在memory中(提供一次性的操作使用,若需要永久儲存則可以寫入檔案中)
engine = create_engine('sqlite:///:memory:')
df.to_sql('db_table', engine, index=False)
print(pd.read_sql_query('SELECT `County` as `縣市`, `SiteName` as `區域`, \
	CAST(`PM2.5_AVG` AS int) as `PM2.5` FROM `db_table` \
	order by CAST(`PM2.5_AVG` AS int) ASC', engine))

點我觀看執行範例 (使用 Microsoft Azure Notebooks )

Pandas+SQL 執行效果截圖
Pandas+SQL 執行效果截圖

若有其他想法,例如:想知道哪個縣市的整體平均空氣品質較差就可以在 SQL 語法中使用 GROUP BY 語法,對於 SQL 語法熟悉的話就能輕易地藉由改變查詢的語法來獲得想查詢 / 篩選的資料。

PS. 對於Python語法上有疑問可以參考課程投影片

PEP8 Python 編碼規範手冊

PEP 8 介紹

PEP8 是 Python 社群共通的風格指南,一開始是 Python 之父 Guido van Rossum 自己的撰碼風格,慢慢後來演變至今,目的在於幫助開發者寫出可讀性高且風格一致的程式。許多開源計畫,例如 Django 、 OpenStack等都是以 PEP8 為基礎再加上自己的風格建議。

程式碼編排 (Code lay-out)

這邊列出PEP8裡面的重點,有興趣可以直接看官方原文的文件會更清楚一些。

縮排 (Indentation)
每層縮排使用 4 個空格

斷行風格
正確:
# 斷行首字母與開頭的括號垂直對齊.

foo = long_function_name(var_one, var_two,
                         var_three, var_four)

# 垂直縮排,首行不能有參數.

def long_function_name(
        var_one, var_two, var_three,
        var_four):
    print(var_one)

# 垂直縮排,後面還有其它代碼時,需要添加一層額外的縮排加以區別:

foo = long_function_name(
    var_one, var_two,
    var_three, var_four)

錯誤:
# 垂直縮排方式首行不能有引數

foo = long_function_name(var_one, var_two,
    var_three, var_four)

# 垂直縮排,首行不能有參數; 後面還有其它代碼部分時,斷行要添加一層縮進,使其與其它代碼部分能區別開來

def long_function_name(
    var_one, var_two, var_three,
    var_four):
    print(var_one)

if 條件斷行
if ( 剛好有 4 個字符,相當於一層縮排。
對於 if 條件斷行,以下幾種風格都可以:
沒有額外的縮排

if (this_is_one_thing and
    that_is_another_thing):
    do_something()

添加註釋加以區分

# Add a comment, which will provide some distinction in editors
# supporting syntax highlighting.
if (this_is_one_thing and
    that_is_another_thing):
    # Since both conditions are true, we can frobnicate.
    do_something()

添加額外的縮排加以區分

# Add some extra indentation on the conditional continuation line.
if (this_is_one_thing
        and that_is_another_thing):
    do_something()

多行的括號

括號結束符與最後行的首字符對齊,如:

my_list = [
    1, 2, 3,
    4, 5, 6,
    ]

result = some_function_that_takes_arguments(
    'a', 'b', 'c',
    'd', 'e', 'f',
    )

括號結束符與首行的首字符對齊, 如:

my_list = [
    1, 2, 3,
    4, 5, 6,
]
result = some_function_that_takes_arguments(
    'a', 'b', 'c',
    'd', 'e', 'f',
)

上面兩種排版的方式都可以

使用Tab還是空格縮排

用空格

每行最長長度

所有行都不超過 80 個字符

限制編輯器視窗的寬度,使能並排同時打開多個文件。
設置編輯器寬度(set width to 80),來避免 wrapping
對於較少結構限制的長文本(如 docstrings 或註釋),行長應限制為 72 個字符。
如果團隊成員都同意使用長行,則可以將行長增加到不超過 100 個字符,但是 docstrings 和註釋還必須為 72 個字符。

有括號的長行可以用 implicit continuation 來斷行,其它的可以用 \ 來斷行,如:

with open('/path/to/some/file/you/want/to/read') as file_1, \
     open('/path/to/some/file/being/written', 'w') as file_2:
    file_2.write(file_1.read())

操作符要和操作數在一起

# 推薦的正確的風格,這樣很容易將操作符與操作數匹配:

income = (gross_wages
          + taxable_interest
          + (dividends - qualified_dividends)
          - ira_deduction
          - student_loan_interest)

# 這種風格現今已不推薦使用了:

income = (gross_wages +
          taxable_interest +
          (dividends - qualified_dividends) -
          ira_deduction -
          student_loan_interest)

空行分隔

模組中最頂層的函數和類定義都要用兩行空行分隔
類別中的方法定義用單行分隔
要把一組相關的函數分組,可以用一些額外的空行
函數中的邏輯區塊可以加空行來分隔

原始碼的編碼

Python 核心模組文件的編碼都必須用 UTF-8(Python2 是 ASCII)。
使用默認的編碼時(Python3: UTF-8,Python2: ASCII),不能使用編碼聲明
標準庫中,只有測試、作者名才能使用非默認的編碼,其它情況下的非 ASCII 字符用 \x, \u, \u, \N 表示法表示。

Import

每行 import 只導入一個模組:
# 正確:
import os
import sys
# 錯誤:
import sys, os
# 正確:同一模組中的內容可以在同一行導入
from subprocess import Popen, PIPE

import 語句要在文件的前面,在模組註釋及 docstrings 之後,在模組全域變數和常數定義之前。
import 分組及導入順序,每個分組之間用一行空行分隔 1. 標準庫 2. 相關第三方庫 3. 本地應用/庫的特殊導入
推薦使用絕對導入,如:
import mypkg.sibling
from mypkg import sibling
from mypkg.sibling import example

在比較覆雜的套件組成中,也可以用顯式的相對導入,如:
from . import sibling
from .sibling import example
從一個模塊中導入一個類別時,要顯示拼寫出類別名,如:
from myclass import MyClass
from foo.bar.yourclass import YourClass

如果與本地名稱衝突,可以先導入模組:
import myclass
import foo.bar.yourclass
然後使用:"myclass.MyClass" 和 “foo.bar.yourclass.YourClass"。
應該避免使用 from <module> import *
模組層級的特殊名稱(如__all__)的位置:
必須在模組的 docstrings 或註釋之後,但在任何的 import 語句之前。from __future__ 比較特殊,Python 強制該語句必須在 docstrings 或註釋之後,因此風格如下:

"""This is the example module.

This module does stuff.
"""

from __future__ import barry_as_FLUFL

__all__ = ['a', 'b', 'c']
__version__ = '0.1'
__author__ = 'Cardinal Biggles'

import os
import sys

字符引號 (String Quotes)

單引號和雙引號的功能是等同的。
對於多行字符串,應該用雙引號字符形式的三引號""",以便與 PEP257 中的 docstrings 規範兼容

表達式和語句中的空格 (Whitespace in Expressions and Statements)

()、[]、{} 等括號內不要多餘的空格,如:
# 正確:
spam(ham[1], {eggs: 2})
# 錯誤:
spam( ham[ 1 ], { eggs: 2 } )
,、;、: 之前不要有空格,如:
# 正確:
if x == 4: print x, y; x, y = y, x
# 錯誤:
if x == 4 : print x , y ; x , y = y , x
在 slice 語句中的 :實際上是一個二元操作符,因此其兩側的空格數必須相同; 但當無 slice 參數時,兩側的空格可以都省略,如:
# 以下是正確的風格:
ham[1:9], ham[1:9:3], ham[:9:3], ham[1::3], ham[1:9:]
ham[lower:upper], ham[lower:upper:], ham[lower::step]
ham[lower+offset : upper+offset]
ham[: upper_fn(x) : step_fn(x)], ham[:: step_fn(x)]
ham[lower + offset : upper + offset]
# 以下是錯誤的風格:
ham[lower + offset:upper + offset]
ham[1: 9], ham[1 :9], ham[1:9 :3]
ham[lower : : upper]
ham[ : upper]
函數調用的 () 及索引的 [] 前不要加空格,如:
# 正確風格:
spam(1)
dct[‘key’] = lst[index]
# 錯誤風格:
spam (1)
dct [‘key’] = lst [index]
不要在賦值語句中加入額外的空格來對齊,如:
# 正確的風格:
x = 1
y = 2
long_variable = 3
# 錯誤的風格:
x = 1
y = 2
long_variable = 3

其它推薦風格

任何行的行尾都不要有空白符。
在二元操作符號兩側一般都要加一個空格,一般的二元操作符號如:
賦值: =, +=, -=
比較:==, <, >, !=, <>, <=, >=, in, not in, is, is not
布林操作: and, or, not
在分優先級的表達式中,在最低優先級的操作符兩側加一個空格,但至多只能加一個空格,如:
# 正確的風格:
x = x*2 – 1
hypot2 = x*x + y*y
c = (a+b) * (a-b)
# 錯誤的風格:
x = x * 2 – 1
hypot2 = x * x + y * y
c = (a + b) * (a – b)
在關鍵字參數和默認參數值中的 = 兩側不要加空格,如:
# 正確的風格:
def complex(real, imag=0.0):
return magic(r=real, i=imag)
錯誤的風格:
def complex(real, imag = 0.0):
return magic(r = real, i = imag)
函數註解中的 : 前不要加空格,這符合 : 的常規風格,但是 -> 兩側要加空格,如:
# 正確的風格:
def munge(input: AnyStr): …
def munge() -> AnyStr: …
# 錯誤的風格:
def munge(input:AnyStr): …
def munge()->PosInt: …
參數註解中,如果註解的參數有默認值,指定默認值的 = 兩側要加空格,如:
# 正確的風格:
def munge(sep: AnyStr = None): …
def munge(input: AnyStr, sep: AnyStr = None, limit=1000): …
# 錯誤的風格:
def munge(input: AnyStr=None): …
def munge(input: AnyStr, limit = 1000): …

不要將多條語句組合在一行中,如:
# 正確的風格:
if foo == ‘blah’:
do_blah_thing()
do_one()
do_two()
do_three()
# 錯誤風格:
if foo == ‘blah’: do_blah_thing()
do_one(); do_two(); do_three()

# 如果 if/for/while 區塊內的程式碼很少,組合在一行有時還是可以接受的
# 但是不推薦,如:
if foo == ‘blah’: do_blah_thing()
for x in lst: total += x
while t < 10: t = delay()
# 但是在有多段語句時,絕對不能這樣,如:
if foo == ‘blah’: do_blah_thing()
else: do_non_blah_thing()

try: something()
finally: cleanup()

do_one(); do_two(); do_three(long, argument,
list, like, this)

if foo == ‘blah’: one(); two(); three()

註解 (Comments)

註解內容必須要和程式碼相關!
註解應該是完整的語句,首字母一般大寫(英文),一般要有句號。
註解很短時句號可以省略。
區塊註解一般由多個段落組成。用英文寫註解

區塊註解 (Block Comments)

每行用 # 及一個空格開始,如 #
段落用一個只有 # 的行分隔

行內註解 (Inline Comments)

註解與語句內容至少用兩個空格分開,註解用 # 加一個空格開始
# 不要像下面這樣,註解內容沒有必要
x = x + 1 # Increment x
# 但是有時,如下面的註解會很有用
x = x + 1 # Compensate for border

文件字串 (Documentation Strings)

公開的模組、函數、類及方法都應該有文件字串,而非公開的方法可以用註解來代替,且註解放置在 def 行之後。
多行的文件字串,結束符號要自成一行,如:

"""Return a foobang

Optional plotz says to frobnicate the bizbaz first.
"""

單行的文件字串,結束符號和內容放在同一行

命名 (Naming Conventions)

沒有推薦的風格,但是別人要能從你的程式碼中看出你用的是什麽風格,常用的風格如下:

  • b 單個小寫字母
  • B 單個大寫字母
  • lowercase
  • lower_case_with_underscores
  • UPPERCASE
  • UPPER_CASE_WITH_UNDERSCORES
  • CapitalizedWords, 這種風格中,對於縮寫詞應全部用大寫,如
  • HTTPServerError 比 HttpServerError 好
  • mixedCase
    Capitalized_Words_With_Underscores,這個太醜,不要用這種!
  • st_mode、st_mtime 等前綴,一般是系統接口返回,如果自己寫的程式碼不推薦用這種
  • _single_leading_underscore : 弱 “內部使用” 指示器,這種對象用 from M import * 不會被導入
  • single_trailing_underscore_ : 可以用來和 Python 關鍵詞進行區分,如 Tkinter.Toplevel(master, class_=’ClassName’)
  • __double_leading_underscore : 命名一個類屬性時,可以進行命名矯正,例如 class FooBar 內的 __boo 會變成 _FooBar__boo
  • double_leading_and_trailing_underscore : “magic” 對象,不要自己發明這種對象

命名習慣 (Prescriptive: Naming Conventions)

  • 不用單個 l, O, I 等這樣的單個字符來命名,它們與數字1,0不好區分
  • 套件名和模組名:全部用小寫,必要時可用 _,但不推薦,C/C++ 的擴展模組,如果其對應有 Python 版本,那麽 C/C++ 擴展模組名前加 _
  • 類別名:用 CapWords 風格
  • 異常名:用 CapWords 風格,一般應該有 Error 後綴
  • 全域變數名:能用 from M import * 導入的變數全部放在 __all__ 中,或者全域變數用 _ 做前綴
  • 函數名:應該用全部用小寫,單詞間可以用 _ 分隔,如 my_func,不推薦用 mixedCase 風格
  • 函數和方法的參數:實例方法的第一個參數用 self, 類別方法的第一個參數用 cls,如果參數與關鍵字衝突,在參數名後加 _ 後綴,如 class_
  • 實例變數和方法: 用小寫字符和 _, 非公開的實例變數和方法用一個 _ 做前綴; 避免與子類別中的名字衝突,類的變數可用兩個 _ 作前綴,例如 class FooBar 內的 __boo 會變成只能通過 FooBar._FooBar__boo 讀取
  • 常數:全部大寫,可用 _ 分隔,如 MAX_OVERFLOW、TOTAL

推薦的程式撰寫方式 (Programming Recommendations)

字符串連接不要用 a += b 或者 a = a + b, 用 “.join(), 後者性能更好。跟 None 的比較用 is 和 is not,不要用 ==,如果你想判斷 if x is not None, 不要縮寫成 if x 使用 if foo is not None,而不是 if not foo is None,前者更加易讀

如果要實現序列比較操作的話,應將 6 個操作(__eq__ , __ne__ , __lt__ , __le__ , __gt__ , __ge__)全部實現,可以借助 functools.total_ordering() 修飾器來減少工作量

將函數保存在一個變數中應該用 def f(x): return 2*x, 而非 f = lambda x: 2*x,後者不利於調試

自定義的異常類應該繼承至 Exception 類,而非 BaseException 類。Python 2 中拋出異常用 raise ValueError(‘message’),而非 raise ValueRoor, ‘message’

盡量可以的指明異常名,如:

try:
    import platform_specific_module
except ImportError:
    platform_specific_module = None

避免使用無異常名的 except: 語句,它會捕獲全部的異常(如 Ctrl C)。
將異常綁定到名字的方法:

try:
    process_data()
except Exception as exc:
    raise DataProcessingFailedError(str(exc))

try: 中的語句要盡量減少,如:
# 正確的寫法:

try:
    value = collection[key]
except KeyError:
    return key_not_found(key)
else:
    return handle_value(value)

# 錯誤的寫法

try:
    # Too broad!
    return handle_value(collection[key])
except KeyError:
    # Will also catch KeyError raised by handle_value()
    return key_not_found(key)

如果資源只適用於某個代碼段內,使用 with 或 try/finally 來確保能進行清理工作
上下文管理器應用通過一個單獨的函數或方法來呼叫,如:
# 正確的做法:

with conn.begin_transaction():
    do_stuff_in_transaction(conn)

# 錯誤的做法:

with conn:
    do_stuff_in_transaction(conn)

return 語句應該一致,如:
# 正確的做法:

def foo(x):
    if x &amp;amp;amp;amp;amp;amp;amp;amp;amp;gt;= 0:
        return math.sqrt(x)
    else:
        return None

def bar(x):
    if x &amp;amp;amp;amp;amp;amp;amp;amp;amp;lt; 0:
        return None
    return math.sqrt(x)

# 錯誤的做法:

def foo(x):
    if x &amp;amp;amp;amp;amp;amp;amp;amp;amp;gt;= 0:
        return math.sqrt(x)

def bar(x):
    if x &amp;amp;amp;amp;amp;amp;amp;amp;amp;lt; 0:
        return
    return math.sqrt(x)

使用字符串的方法,而不是用 string 模組中的方法
使用 “.startswith() 和 “.endswidth() 而不用 slicing 來檢查前綴和後綴:
# 正確:
if foo.startswith(‘bar’):
# 錯誤:
if foo[:3] == ‘bar’:
判斷對象的類型用 isinstance 而不直接 type 比較,如:
# 正確:
if isinstance(obj, int):
# 錯誤:
if type(obj) is type(1):
對序列是否空的判斷不用 len,如:
# 正確:
if not seq:
if seq:
# 錯誤:
if len(seq):
if not len(seq):
布林值的比較:
# 正確:
if greeting:
# 不要這樣:
if greeting == True:
# 這樣更不行:
if greeting is True:


參考資料:

PEP 8 — Style Guide for Python Code

Google關鍵字搜尋,將搜尋結果排名紀錄下來

使用Python撰寫自動化搜尋特定關鍵字

Google關鍵字搜尋將搜尋結果排名紀錄下來

Selenium 使用 Chrome 瀏覽器 webdriver

SEO (Search Engine Optimization),是維護網站非常重要的一項工作,利用這個小程式可以自動化的搜尋關鍵字,並將搜尋排名結果存入檔案,以利分析成效與後續的持續優化。

需要先安裝 selenium 套件

下載 Chrome 瀏覽器 webdriver

額外會需要用到兩隻檔案,需要先建立好放置於py檔同層資料夾下

site.csv : 裡面放要搜尋的網站位置

terms.csv : 搜尋關鍵字

from selenium import webdriver
import csv
import time

chromedriver = "/Users/chifu/Documents/chromedriver"
chrome_options = webdriver.ChromeOptions()
chrome_options.add_argument("--incognito")
driver = webdriver.Chrome(chromedriver, chrome_options=chrome_options)
csvr_site = csv.reader(open('site.csv', 'r'))
csvr_terms = csv.reader(open('terms.csv', 'r'))
outfile = open('rank.csv', 'w')
csvwriter = csv.writer(outfile)
search_pages = 5

for s in csvr_site:
	site = s[0]

for row in csvr_terms:
	print(row[0])
	current_page = 1
	while current_page &amp;amp;lt;= search_pages:
		if current_page == 1:
			driver.get("https://www.google.com.tw/search?q=%s" % row[0])
		else:
			driver.get(next_pageurl)
		time.sleep(1)
		doms = driver.find_elements_by_css_selector("div.rc h3.r a")
		next_pageurl = driver.find_element_by_css_selector("a#pnnext.pn").get_attribute("href")
		counter = 0
		rank = "not found"
		for dom in doms:
			counter += 1	
			href = dom.get_attribute("href")
			if site in href:
				rank = counter
				break
		if rank != "not found":
			break
		current_page += 1

	csvwriter.writerow([row[0], current_page, rank])
	outfile.flush()
	time.sleep(1)
driver.close()

相關API參考

字串練習,課堂作業

題目: 在特定的文章字串中,搜尋輸入的字串
條件1:若有符合的字串,將其索引值印出 (全部印出,並非印出第一個符合的索引值)
2:最後印出 總共有9個"的", 若輸入的字為"的"

text='在 Google I/O 2013 開發者大會上,除了 Samsung GALAXY S 4 的 Google 版本外,並未發表任何新產品;但許多消費者一定很期待,包括 Nexus 4、Nexus 7、Nexus 10 的後繼機種的消息。眼尖的網友或許會發現,在 Google I/O 2013 的介紹影片中,與 Nexus 4、Nexus 10 並列的官方圖片,中間那款並不是 Nexus 7,機身頂部與底部都是彎曲設計,極有可能是 Nexus 7 的後繼機種。不過,根據 VR-Zone 獲得的資訊顯示,次世代 Nexus 7 還是由 ASUS 代工,除了螢幕為 1920 x 1080 解析度 IPS 面板外,可能還會選擇 Qualcomm Snapdragon 800 四核心處理器,至於 NVIDIA Tegra 4 則因成本考量而被摒棄,這或許是二代 Nexus 7 至今還無法釋出的原因之一。'
findstr=input("請輸入要搜尋的字:")

HW7_sample

# -*- coding: utf-8 -*-

# Form implementation generated from reading ui file 'test.ui'
#
# Created: Thu Jul 18 16:17:56 2013
#      by: PyQt4 UI code generator 4.10.1
#
# WARNING! All changes made in this file will be lost!

from PyQt4 import QtCore, QtGui

try:
    _fromUtf8 = QtCore.QString.fromUtf8
except AttributeError:
    def _fromUtf8(s):
        return s

try:
    _encoding = QtGui.QApplication.UnicodeUTF8
    def _translate(context, text, disambig):
        return QtGui.QApplication.translate(context, text, disambig, _encoding)
except AttributeError:
    def _translate(context, text, disambig):
        return QtGui.QApplication.translate(context, text, disambig)

class Ui_MainWindow(object):
    def setupUi(self, MainWindow):
        self.oper = ''
        self.num1=0
        self.num2=0
        MainWindow.setObjectName(_fromUtf8("MainWindow"))
        MainWindow.resize(357, 253)
        self.centralwidget = QtGui.QWidget(MainWindow)
        self.centralwidget.setObjectName(_fromUtf8("centralwidget"))
        self.lineEdit = QtGui.QLineEdit(self.centralwidget)
        self.lineEdit.setGeometry(QtCore.QRect(20, 20, 321, 41))
        self.lineEdit.setObjectName(_fromUtf8("lineEdit"))
        self.pushButton = QtGui.QPushButton(self.centralwidget)
        self.pushButton.setGeometry(QtCore.QRect(20, 100, 101, 41))
        font = QtGui.QFont()
        font.setFamily(_fromUtf8("Agency FB"))
        font.setPointSize(14)
        self.pushButton.setFont(font)
        self.pushButton.setObjectName(_fromUtf8("pushButton"))
        self.pushButton_2 = QtGui.QPushButton(self.centralwidget)
        self.pushButton_2.setGeometry(QtCore.QRect(20, 150, 101, 41))
        font = QtGui.QFont()
        font.setFamily(_fromUtf8("Agency FB"))
        font.setPointSize(14)
        self.pushButton_2.setFont(font)
        self.pushButton_2.setObjectName(_fromUtf8("pushButton_2"))
        self.pushButton_3 = QtGui.QPushButton(self.centralwidget)
        self.pushButton_3.setGeometry(QtCore.QRect(130, 100, 101, 41))
        font = QtGui.QFont()
        font.setFamily(_fromUtf8("Agency FB"))
        font.setPointSize(14)
        self.pushButton_3.setFont(font)
        self.pushButton_3.setObjectName(_fromUtf8("pushButton_3"))
        self.pushButton_4 = QtGui.QPushButton(self.centralwidget)
        self.pushButton_4.setGeometry(QtCore.QRect(130, 150, 101, 41))
        font = QtGui.QFont()
        font.setFamily(_fromUtf8("Agency FB"))
        font.setPointSize(14)
        self.pushButton_4.setFont(font)
        self.pushButton_4.setObjectName(_fromUtf8("pushButton_4"))
        self.pushButton_5 = QtGui.QPushButton(self.centralwidget)
        self.pushButton_5.setGeometry(QtCore.QRect(240, 100, 101, 41))
        font = QtGui.QFont()
        font.setFamily(_fromUtf8("Agency FB"))
        font.setPointSize(14)
        self.pushButton_5.setFont(font)
        self.pushButton_5.setObjectName(_fromUtf8("pushButton_5"))
        self.pushButton_6 = QtGui.QPushButton(self.centralwidget)
        self.pushButton_6.setGeometry(QtCore.QRect(240, 150, 101, 41))
        font = QtGui.QFont()
        font.setFamily(_fromUtf8("Agency FB"))
        font.setPointSize(14)
        self.pushButton_6.setFont(font)
        self.pushButton_6.setObjectName(_fromUtf8("pushButton_6"))
        MainWindow.setCentralWidget(self.centralwidget)
        self.menubar = QtGui.QMenuBar(MainWindow)
        self.menubar.setGeometry(QtCore.QRect(0, 0, 357, 22))
        self.menubar.setObjectName(_fromUtf8("menubar"))
        MainWindow.setMenuBar(self.menubar)
        self.statusbar = QtGui.QStatusBar(MainWindow)
        self.statusbar.setObjectName(_fromUtf8("statusbar"))
        MainWindow.setStatusBar(self.statusbar)

        self.retranslateUi(MainWindow)
        QtCore.QMetaObject.connectSlotsByName(MainWindow)
        QtCore.QObject.connect(self.pushButton, QtCore.SIGNAL("clicked()"), self.btn_add)
        QtCore.QObject.connect(self.pushButton_6, QtCore.SIGNAL("clicked()"), self.btn_equal)

    def retranslateUi(self, MainWindow):
        MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow", None))
        self.pushButton.setText(_translate("MainWindow", "+", None))
        self.pushButton_2.setText(_translate("MainWindow", "-", None))
        self.pushButton_3.setText(_translate("MainWindow", "*", None))
        self.pushButton_4.setText(_translate("MainWindow", "/", None))
        self.pushButton_5.setText(_translate("MainWindow", "C", None))
        self.pushButton_6.setText(_translate("MainWindow", "=", None))

    def btn_add(self):
        if self.num1 == 0:
            self.num1 = int(self.lineEdit.text())
        else:
            self.num1 = self.num1 + int(self.lineEdit.text())
            print(self.num1)
    def btn_equal(self):
        print(self.num1 + int(self.lineEdit.text()))

if __name__ == "__main__":
    import sys
    app = QtGui.QApplication(sys.argv)
    MainWindow = QtGui.QMainWindow()
    ui = Ui_MainWindow()
    ui.setupUi(MainWindow)
    MainWindow.show()
    sys.exit(app.exec_())