一、從Web擷取資訊
網頁擷取(Web Scraping)相關模組
l Webbrowser:
Python內建,可開啟瀏覽器連到指定的網頁。
Python內建,可開啟瀏覽器連到指定的網頁。
l Requests:
需下載安裝,可從網路上下載檔案和網頁。
需下載安裝,可從網路上下載檔案和網頁。
l BeautifulSoup:
需下載安裝,可解析HTML的網頁編寫格式。
需下載安裝,可解析HTML的網頁編寫格式。
l Selenium:
需下載安裝,可啟動並控制Web瀏覽器、填寫表單,並模擬滑鼠游標在網頁中的點按動作。
需下載安裝,可啟動並控制Web瀏覽器、填寫表單,並模擬滑鼠游標在網頁中的點按動作。
Webbrowser模組
l import webbrowser
webbrowser.open("http://inventwithpython.com/")
webbrowser.open("http://inventwithpython.com/")
Requests模組
l 在命令提示字元輸入pip install requests,下載並安裝Requests模組。
l 使用requests.get()方法下載網頁,返回一個Response物件:
import requests
aRes = requests.get("https://automatetheboringstuff.com/files/rj.txt")
print(type(aRes)) à <class 'requests.models.Response'>
# 使用Response物件的status_code屬性檢查請求是否成功
print(aRes.status_code == requests.codes.ok) à True
# 使用Response物件的text變數儲存下載網頁的字串,檢查字元長度
print(len(aRes.text)) à 174130
# 使用Response物件的text變數儲存下載網頁的字串,顯示前74個字元
print(aRes.text[:74]) à The Project Gutenberg EBook of Romeo and Juliet, by William Shakespeare
import requests
aRes = requests.get("https://automatetheboringstuff.com/files/rj.txt")
print(type(aRes)) à <class 'requests.models.Response'>
# 使用Response物件的status_code屬性檢查請求是否成功
print(aRes.status_code == requests.codes.ok) à True
# 使用Response物件的text變數儲存下載網頁的字串,檢查字元長度
print(len(aRes.text)) à 174130
# 使用Response物件的text變數儲存下載網頁的字串,顯示前74個字元
print(aRes.text[:74]) à The Project Gutenberg EBook of Romeo and Juliet, by William Shakespeare
l 使用Response物件的raise_for_status()方法進行錯誤檢測:
import requests
# 如果下載網頁成功,什麼都不做
aRes = requests.get("https://automatetheboringstuff.com/files/rj.txt")
aRes.raise_for_status()
# 如果下載網頁失敗,會丟出例外
bRes = requests.get("https://automatetheboringstuff.com/ThisPageDoesNotExist")
bRes.raise_for_status() à raise HTTPError
import requests
# 如果下載網頁成功,什麼都不做
aRes = requests.get("https://automatetheboringstuff.com/files/rj.txt")
aRes.raise_for_status()
# 如果下載網頁失敗,會丟出例外
bRes = requests.get("https://automatetheboringstuff.com/ThisPageDoesNotExist")
bRes.raise_for_status() à raise HTTPError
l 使用Response物件的iter_content()方法將下載的網頁寫入檔案之中:
import requests
aRes = requests.get("https://automatetheboringstuff.com/files/rj.txt")
aRes.raise_for_status()
# 第一個引數Romeo and Juliet.txt會儲存在目前工作目錄
# 第二個引數wb以二進位(Write Binary)模式來開啟檔案,目的是為了儲存Unicode編碼
fileTest = open("Romeo and Juliet.txt", "wb")
# 使用Response物件的iter_content()方法在迴圈中會返回磁碟區塊(Chunk),每一個磁碟區塊都是一個byte,常用100000,但欲下載的檔案原始大小若超過100000個位元組,下載會不完整
for chunk in aRes.iter_content(100000):
fileTest.write(chunk)
fileTest.close()
import requests
aRes = requests.get("https://automatetheboringstuff.com/files/rj.txt")
aRes.raise_for_status()
# 第一個引數Romeo and Juliet.txt會儲存在目前工作目錄
# 第二個引數wb以二進位(Write Binary)模式來開啟檔案,目的是為了儲存Unicode編碼
fileTest = open("Romeo and Juliet.txt", "wb")
# 使用Response物件的iter_content()方法在迴圈中會返回磁碟區塊(Chunk),每一個磁碟區塊都是一個byte,常用100000,但欲下載的檔案原始大小若超過100000個位元組,下載會不完整
for chunk in aRes.iter_content(100000):
fileTest.write(chunk)
fileTest.close()
l Unicode編碼相關內容:
Joel on Software:The Absolute Minimum Every Software Developer Absolutely, Positively Must KnowAbout Unicode and Character Sets (No Excuses!)
Pragmatic Unicode
Requests模組相關內容:
Requests: HTTP for Humans
Joel on Software:The Absolute Minimum Every Software Developer Absolutely, Positively Must KnowAbout Unicode and Character Sets (No Excuses!)
Pragmatic Unicode
Requests模組相關內容:
Requests: HTTP for Humans
BeautifulSoup模組
l 學習超文字標記語言HTML的資源:
HTML Beginner Tutorial
HTML & CSS
HTML - Learn webdevelopment
HTML基礎 - 學習該如何開發Web
使用requests模組下載網頁後,會取得HTML內容並存成字串值,因此必須學習檢視HTML原始碼、開啟瀏覽器開發人員工具,以及善用檢查HTML原始碼的功能,記住不要使用正規表示式來解析HTML,應該使用BeautifulSoup模組:http://stackoverflow.com/a/1732454/1893164/。
HTML Beginner Tutorial
HTML & CSS
HTML - Learn webdevelopment
HTML基礎 - 學習該如何開發Web
使用requests模組下載網頁後,會取得HTML內容並存成字串值,因此必須學習檢視HTML原始碼、開啟瀏覽器開發人員工具,以及善用檢查HTML原始碼的功能,記住不要使用正規表示式來解析HTML,應該使用BeautifulSoup模組:http://stackoverflow.com/a/1732454/1893164/。
l 本書範例檔example.html的HTML原始碼如下:
<!-- This is the example.html file. -->
<html><head><title>The Website Title</title></head>
<body>
<p>Download my <strong>Python</strong> book from <a href="http://inventwithpython.com">my website</a>.</p>
<p class="slogan">Learn Python the easy way!</p>
<p>By <span id="author">Al Sweigart</span></p>
</body></html>
<!-- This is the example.html file. -->
<html><head><title>The Website Title</title></head>
<body>
<p>Download my <strong>Python</strong> book from <a href="http://inventwithpython.com">my website</a>.</p>
<p class="slogan">Learn Python the easy way!</p>
<p>By <span id="author">Al Sweigart</span></p>
</body></html>
l 在命令提示字元輸入pip install beautifulsoup4,下載並安裝BeautifulSoup模組。
l 使用bs4.BeautifulSoup()方法解析HTML,返回一個BeautifulSoup物件:
import requests, bs4
# 解析網路上的網頁
aRes = requests.get("http://nostarch.com")
aRes.raise_for_status()
aBeaSou = bs4.BeautifulSoup(aRes.text, "html.parser")
print(type(aBeaSou)) à <class 'bs4.BeautifulSoup'>
# 解析從網路上下載的網頁,本書範例檔example.html在目前工作目錄
bRes = open("example.html")
bBeaSou = bs4.BeautifulSoup(bRes, "html.parser")
print(type(bBeaSou)) à <class 'bs4.BeautifulSoup'>
import requests, bs4
# 解析網路上的網頁
aRes = requests.get("http://nostarch.com")
aRes.raise_for_status()
aBeaSou = bs4.BeautifulSoup(aRes.text, "html.parser")
print(type(aBeaSou)) à <class 'bs4.BeautifulSoup'>
# 解析從網路上下載的網頁,本書範例檔example.html在目前工作目錄
bRes = open("example.html")
bBeaSou = bs4.BeautifulSoup(bRes, "html.parser")
print(type(bBeaSou)) à <class 'bs4.BeautifulSoup'>
l 使用BeautifulSoup物件的select()方法尋找元素,返回一個Tag物件串列:
# 解析從網路上下載的網頁,本書範例檔example.html在目前工作目錄
import bs4
aRes = open("example.html")
aBeaSou = bs4.BeautifulSoup(aRes, "html.parser")
aTagLis = aBeaSou.select("span")
print(type(aTagLis)) à <class 'list'>
print(type(aTagLis[0])) à <class 'bs4.element.Tag'>
# 在串列的Tag物件數目
print(len(aTagLis)) à 1
# Tag物件的getText()方法可返回此元素的文字
print(aTagLis[0].getText()) à Al Sweigart
# Tag物件可傳入str()函式轉成HTML的字串來顯示
print(str(aTagLis[0])) à <span id="author">Al Sweigart</span>
# Tag物件的get()方法可返回此元素的屬性,取得該屬性的值
print(aTagLis[0].get("id")) à author
# Tag物件的attrs屬性可將該Tag物件的所有HTML屬性當成字典
print(aTagLis[0].attrs) à {'id': 'author'}
# 解析從網路上下載的網頁,本書範例檔example.html在目前工作目錄
import bs4
aRes = open("example.html")
aBeaSou = bs4.BeautifulSoup(aRes, "html.parser")
aTagLis = aBeaSou.select("span")
print(type(aTagLis)) à <class 'list'>
print(type(aTagLis[0])) à <class 'bs4.element.Tag'>
# 在串列的Tag物件數目
print(len(aTagLis)) à 1
# Tag物件的getText()方法可返回此元素的文字
print(aTagLis[0].getText()) à Al Sweigart
# Tag物件可傳入str()函式轉成HTML的字串來顯示
print(str(aTagLis[0])) à <span id="author">Al Sweigart</span>
# Tag物件的get()方法可返回此元素的屬性,取得該屬性的值
print(aTagLis[0].get("id")) à author
# Tag物件的attrs屬性可將該Tag物件的所有HTML屬性當成字典
print(aTagLis[0].attrs) à {'id': 'author'}
l 不同的選擇器模式可以組合運用,例如.select("p #author"),以下依選擇器模式的不同,顯示會找到的元素:
# 解析從網路上下載的網頁,本書範例檔example.html在目前工作目錄
import bs4
aRes = open("example.html")
aBeaSou = bs4.BeautifulSoup(aRes, "html.parser")
def selMode(mode):
aTagLis = aBeaSou.select(mode)
print(str(aTagLis[0]))
# .select("title")會找到所有<title>元素
selMode("title") à <title>The Website Title</title>
# .select("#author")會找到所有id屬性為author的元素
selMode("#author") à <span id="author">Al Sweigart</span>
# .select(".slogan")會找到所有class類別為slogan的元素
selMode(".slogan") à <p class="slogan">Learn Python the easy way!</p>
# .select("p strong")會找到所有在<p>元素之內的<strong>元素
selMode("p strong") à <strong>Python</strong>
# .select("p > strong")會找到所有在<p>元素之內的<strong>元素,且中間沒有其它元素
selMode("p > strong") à <strong>Python</strong>
# .select("span[id]")會找到所有名為<span>且有id屬性的元素
selMode("span[id]") à <span id="author">Al Sweigart</span>
# .select("span[id='author']")會找到所有名為<span>且id屬性為author的元素
selMode("span[id='author']") à <span id="author">Al Sweigart</span>
# 解析從網路上下載的網頁,本書範例檔example.html在目前工作目錄
import bs4
aRes = open("example.html")
aBeaSou = bs4.BeautifulSoup(aRes, "html.parser")
def selMode(mode):
aTagLis = aBeaSou.select(mode)
print(str(aTagLis[0]))
# .select("title")會找到所有<title>元素
selMode("title") à <title>The Website Title</title>
# .select("#author")會找到所有id屬性為author的元素
selMode("#author") à <span id="author">Al Sweigart</span>
# .select(".slogan")會找到所有class類別為slogan的元素
selMode(".slogan") à <p class="slogan">Learn Python the easy way!</p>
# .select("p strong")會找到所有在<p>元素之內的<strong>元素
selMode("p strong") à <strong>Python</strong>
# .select("p > strong")會找到所有在<p>元素之內的<strong>元素,且中間沒有其它元素
selMode("p > strong") à <strong>Python</strong>
# .select("span[id]")會找到所有名為<span>且有id屬性的元素
selMode("span[id]") à <span id="author">Al Sweigart</span>
# .select("span[id='author']")會找到所有名為<span>且id屬性為author的元素
selMode("span[id='author']") à <span id="author">Al Sweigart</span>
Selenium模組
l 在命令提示字元輸入pip install selenium,下載並安裝Selenium模組。
l WebDriver物件與WebElement物件範例:
from selenium import webdriver
chromedriverPath = r"C:\Users\Timmy\Documents\Python\chromedriver.exe"
driver = webdriver.Chrome(chromedriverPath)
print(type(driver))
à <class 'selenium.webdriver.chrome.webdriver.WebDriver'>
driver.get("http://inventwithpython.com")
# 參考下列WebDriver物件方法說明
element = driver.find_element_by_class_name("display-3")
print(type(element))
à <class 'selenium.webdriver.remote.webelement.WebElement'>
# 參考下列WebElement物件屬性或方法說明
print(element.text) à Learn to Program. For Free.
from selenium import webdriver
chromedriverPath = r"C:\Users\Timmy\Documents\Python\chromedriver.exe"
driver = webdriver.Chrome(chromedriverPath)
print(type(driver))
à <class 'selenium.webdriver.chrome.webdriver.WebDriver'>
driver.get("http://inventwithpython.com")
# 參考下列WebDriver物件方法說明
element = driver.find_element_by_class_name("display-3")
print(type(element))
à <class 'selenium.webdriver.remote.webelement.WebElement'>
# 參考下列WebElement物件屬性或方法說明
print(element.text) à Learn to Program. For Free.
l WebDriver物件方法說明-find_element_*、find_elements_*:
WebDriver物件方法find_element_*與find_elements_*皆返回WebElement物件,前者尋找比對符合的第一個元素,後者尋找比對符合的所有元素串列;如果找不到,會丟出NoSuchElement例外。
返回元素標籤為test的元素(只有此方法不分大小寫,"test"與"TEST"都可以比對<test>元素標籤):
.find_element_by_tag_name("test")
.find_elements_by_tag_name("test")
返回元素標籤為p且class屬性的值為test的元素:
.find_element_by_css_selector("p.test")
.find_elements_by_css_selector("p.test")
返回class屬性的值為test的元素:
.find_element_by_class_name("test")
.find_elements_by_class_name("test")
返回id屬性的值為test的元素:
.find_element_by_id("test")
.find_elements_by_id("test")
返回name屬性的值為test的元素:
.find_element_by_name("test")
.find_elements_by_name("test")
返回完全符合網頁文字test的<a>元素:
.find_element_by_link_text("test")
.find_elements_by_link_text("test")
返回部分符合網頁文字test的<a>元素:
.find_element_by_partial_link_text("test")
.find_elements_by_partial_link_text("test")
WebDriver物件方法find_element_*與find_elements_*皆返回WebElement物件,前者尋找比對符合的第一個元素,後者尋找比對符合的所有元素串列;如果找不到,會丟出NoSuchElement例外。
返回元素標籤為test的元素(只有此方法不分大小寫,"test"與"TEST"都可以比對<test>元素標籤):
.find_element_by_tag_name("test")
.find_elements_by_tag_name("test")
返回元素標籤為p且class屬性的值為test的元素:
.find_element_by_css_selector("p.test")
.find_elements_by_css_selector("p.test")
返回class屬性的值為test的元素:
.find_element_by_class_name("test")
.find_elements_by_class_name("test")
返回id屬性的值為test的元素:
.find_element_by_id("test")
.find_elements_by_id("test")
返回name屬性的值為test的元素:
.find_element_by_name("test")
.find_elements_by_name("test")
返回完全符合網頁文字test的<a>元素:
.find_element_by_link_text("test")
.find_elements_by_link_text("test")
返回部分符合網頁文字test的<a>元素:
.find_element_by_partial_link_text("test")
.find_elements_by_partial_link_text("test")
l WebDriver物件方法說明-.back()、.forward()、.refresh()、.quit():
點按瀏覽器下一頁按鈕:
.back()
點按瀏覽器上一頁按鈕:
.forward()
點按瀏覽器重新整理按鈕:
.refresh()
點按瀏覽器關閉按鈕:
.quit()
點按瀏覽器下一頁按鈕:
.back()
點按瀏覽器上一頁按鈕:
.forward()
點按瀏覽器重新整理按鈕:
.refresh()
點按瀏覽器關閉按鈕:
.quit()
l WebElement物件屬性或方法說明-.tag_name、.get_attribute()、.text、.location、.is_displayed():
from selenium import webdriver
chromedriverPath = r"C:\Users\Timmy\Documents\Python\chromedriver.exe"
driver = webdriver.Chrome(chromedriverPath)
driver.get("http://inventwithpython.com")
element = driver.find_element_by_link_text("Al's blog")
# 返回元素標籤字串
print(element.tag_name) à a
# 返回元素屬性的值的字串
print(element.get_attribute("href")) à http://inventwithpython.com/blog/
# 返回元素文字字串
print(element.text) à Al's blog
# 返回元素位置座標
print(element.location) à {'x': 151, 'y': 8152}
# 返回元素可見與否
print(element.is_displayed()) à True
from selenium import webdriver
chromedriverPath = r"C:\Users\Timmy\Documents\Python\chromedriver.exe"
driver = webdriver.Chrome(chromedriverPath)
driver.get("http://inventwithpython.com")
element = driver.find_element_by_link_text("Al's blog")
# 返回元素標籤字串
print(element.tag_name) à a
# 返回元素屬性的值的字串
print(element.get_attribute("href")) à http://inventwithpython.com/blog/
# 返回元素文字字串
print(element.text) à Al's blog
# 返回元素位置座標
print(element.location) à {'x': 151, 'y': 8152}
# 返回元素可見與否
print(element.is_displayed()) à True
l WebElement物件屬性或方法說明-.send_keys()、.clear()、.submit()、.is_enabled():
from selenium import webdriver
chromedriverPath = r"C:\Users\Timmy\Documents\Python\chromedriver.exe"
driver = webdriver.Chrome(chromedriverPath)
driver.get("https://mail.yahoo.com")
# 以下方法要對文字欄位的<input>或<textarea>元素進行操作
element = driver.find_element_by_id("login-username")
# 填寫表單
element.send_keys("Hello World")
# 清除表單
element.clear()
# 提交表單
element.submit()
# 返回提交的表單啟用與否
print(element.is_enabled()) à True
from selenium import webdriver
chromedriverPath = r"C:\Users\Timmy\Documents\Python\chromedriver.exe"
driver = webdriver.Chrome(chromedriverPath)
driver.get("https://mail.yahoo.com")
# 以下方法要對文字欄位的<input>或<textarea>元素進行操作
element = driver.find_element_by_id("login-username")
# 填寫表單
element.send_keys("Hello World")
# 清除表單
element.clear()
# 提交表單
element.submit()
# 返回提交的表單啟用與否
print(element.is_enabled()) à True
l WebElement物件屬性或方法說明-.click()、.is_selected():
from selenium import webdriver
chromedriverPath = r"C:\Users\Timmy\Documents\Python\chromedriver.exe"
driver = webdriver.Chrome(chromedriverPath)
driver.get("http://www.wibibi.com/info.php?tid=190")
# 以下方法要對選項按鈕欄位的<input>元素進行操作
element = driver.find_element_by_name("location")
# 點按頁面
element.click()
# 返回核取方塊或選項按鈕勾選與否
print(element.is_selected()) à True
from selenium import webdriver
chromedriverPath = r"C:\Users\Timmy\Documents\Python\chromedriver.exe"
driver = webdriver.Chrome(chromedriverPath)
driver.get("http://www.wibibi.com/info.php?tid=190")
# 以下方法要對選項按鈕欄位的<input>元素進行操作
element = driver.find_element_by_name("location")
# 點按頁面
element.click()
# 返回核取方塊或選項按鈕勾選與否
print(element.is_selected()) à True
l 使用selenium.webdriver.common.keys模組傳送鍵盤按鍵:
from selenium import webdriver
from selenium.webdriver.common.keys import Keys
chromedriverPath = r"C:\Users\Timmy\Documents\Python\chromedriver.exe"
driver = webdriver.Chrome(chromedriverPath)
driver.get("https://nostarch.com/")
element = driver.find_element_by_tag_name("html")
# 參考下列Keys物件屬性說明
element.send_keys(Keys.END)
from selenium import webdriver
from selenium.webdriver.common.keys import Keys
chromedriverPath = r"C:\Users\Timmy\Documents\Python\chromedriver.exe"
driver = webdriver.Chrome(chromedriverPath)
driver.get("https://nostarch.com/")
element = driver.find_element_by_tag_name("html")
# 參考下列Keys物件屬性說明
element.send_keys(Keys.END)
l Keys物件屬性說明:
鍵盤的上下左右方向鍵:
Keys.UP, Keys.DOWN, Keys.LEFT, Keys.RIGHT
鍵盤的Enter按鍵和Mac的Return按鍵功能相同:
Keys.ENTER, Keys.RETURN
鍵盤的Esc按鍵:
Keys.ESCAPE
其它與鍵盤按鍵名稱相同的Keys物件屬性:
Keys.TAB, Keys.F1, Keys.F2, …, Keys.F12, Keys.BACK_SPACE, Keys.DELETE, Keys.HOME, Keys.END, Keys.PAGE_UP, Keys.PAGE_DOWN
鍵盤的上下左右方向鍵:
Keys.UP, Keys.DOWN, Keys.LEFT, Keys.RIGHT
鍵盤的Enter按鍵和Mac的Return按鍵功能相同:
Keys.ENTER, Keys.RETURN
鍵盤的Esc按鍵:
Keys.ESCAPE
其它與鍵盤按鍵名稱相同的Keys物件屬性:
Keys.TAB, Keys.F1, Keys.F2, …, Keys.F12, Keys.BACK_SPACE, Keys.DELETE, Keys.HOME, Keys.END, Keys.PAGE_UP, Keys.PAGE_DOWN
二、處理Excel試算表
試算表軟體
OpenPyXL模組:基本功能操作
l 在命令提示字元輸入pip install openpyxl,下載並安裝OpenPyXL模組。
l 開啟Excel檔與工作表:
import openpyxl
# 本書範例檔example.xlsx在目前工作目錄
# 此Workbook物件代表Excel檔
aBook = openpyxl.load_workbook("example.xlsx")
print(type(aBook)) à <class 'openpyxl.workbook.workbook.Workbook'>
print(aBook.sheetnames) à ['Sheet1', 'Sheet2', 'Sheet3']
# 此Worksheet物件代表工作表
aSheet = aBook["Sheet3"]
print(type(aSheet)) à <class 'openpyxl.worksheet.worksheet.Worksheet'>
print(aSheet) à <Worksheet "Sheet3">
print(aSheet.title) à Sheet3
bSheet = aBook.active
print(bSheet) à <Worksheet "Sheet1">
import openpyxl
# 本書範例檔example.xlsx在目前工作目錄
# 此Workbook物件代表Excel檔
aBook = openpyxl.load_workbook("example.xlsx")
print(type(aBook)) à <class 'openpyxl.workbook.workbook.Workbook'>
print(aBook.sheetnames) à ['Sheet1', 'Sheet2', 'Sheet3']
# 此Worksheet物件代表工作表
aSheet = aBook["Sheet3"]
print(type(aSheet)) à <class 'openpyxl.worksheet.worksheet.Worksheet'>
print(aSheet) à <Worksheet "Sheet3">
print(aSheet.title) à Sheet3
bSheet = aBook.active
print(bSheet) à <Worksheet "Sheet1">
l 取得Excel檔工作表的儲存格:
import openpyxl
# 本書範例檔example.xlsx在目前工作目錄
aBook = openpyxl.load_workbook("example.xlsx")
aSheet = aBook["Sheet1"]
# Cell物件取得儲存格的方法一
aCell = aSheet["B1"]
print(aCell) à <Cell 'Sheet1'.B1>
print("Row " + str(aCell.row) + ", Column " + aCell.column + " is " + aCell.value)
à Row 1, Column B is Apples
print("Cell " + aCell.coordinate + " is " + aCell.value) à Cell B1 is Apples
# Cell物件取得儲存格的方法二
print(aSheet.cell(row = 1, column = 2)) à <Cell 'Sheet1'.B1>
print(aSheet.cell(row = 1, column = 2).value) à Apples
# Worksheet物件取得使用中的欄列範圍
print(aSheet.max_row) à 7
print(aSheet.max_column) à 3
import openpyxl
# 本書範例檔example.xlsx在目前工作目錄
aBook = openpyxl.load_workbook("example.xlsx")
aSheet = aBook["Sheet1"]
# Cell物件取得儲存格的方法一
aCell = aSheet["B1"]
print(aCell) à <Cell 'Sheet1'.B1>
print("Row " + str(aCell.row) + ", Column " + aCell.column + " is " + aCell.value)
à Row 1, Column B is Apples
print("Cell " + aCell.coordinate + " is " + aCell.value) à Cell B1 is Apples
# Cell物件取得儲存格的方法二
print(aSheet.cell(row = 1, column = 2)) à <Cell 'Sheet1'.B1>
print(aSheet.cell(row = 1, column = 2).value) à Apples
# Worksheet物件取得使用中的欄列範圍
print(aSheet.max_row) à 7
print(aSheet.max_column) à 3
l 取得Excel檔工作表的儲存格範圍:
import openpyxl
# 本書範例檔example.xlsx在目前工作目錄
aBook = openpyxl.load_workbook("example.xlsx")
aSheet = aBook["Sheet1"]
# Generator物件含有矩形範圍的Cell物件
print(list(aSheet["A1":"B2"])) à [(<Cell 'Sheet1'.A1>, <Cell 'Sheet1'.B1>), (<Cell 'Sheet1'.A2>, <Cell 'Sheet1'.B2>)]
# 印出Generator物件矩形範圍的所有Cell物件
for rowCell in aSheet["A1":"C2"]:
for iCell in rowCell:
print(iCell.coordinate, iCell.value)
print("---End of Row---")
import openpyxl
# 本書範例檔example.xlsx在目前工作目錄
aBook = openpyxl.load_workbook("example.xlsx")
aSheet = aBook["Sheet1"]
# Generator物件含有矩形範圍的Cell物件
print(list(aSheet["A1":"B2"])) à [(<Cell 'Sheet1'.A1>, <Cell 'Sheet1'.B1>), (<Cell 'Sheet1'.A2>, <Cell 'Sheet1'.B2>)]
# 印出Generator物件矩形範圍的所有Cell物件
for rowCell in aSheet["A1":"C2"]:
for iCell in rowCell:
print(iCell.coordinate, iCell.value)
print("---End of Row---")
l 以欄列取得Excel檔工作表的儲存格範圍:
import openpyxl
# 本書範例檔example.xlsx在目前工作目錄
aBook = openpyxl.load_workbook("example.xlsx")
aSheet = aBook.active
# Generator物件含有矩形範圍的Cell物件
print(list(aSheet.rows)) à [(<Cell 'Sheet1'.A1>, <Cell 'Sheet1'.B1>, <Cell 'Sheet1'.C1>), …, (<Cell 'Sheet1'.A7>, <Cell 'Sheet1'.B7>, <Cell 'Sheet1'.C7>)]
print(list(aSheet.columns)[1]) à (<Cell 'Sheet1'.B1>, …, <Cell 'Sheet1'.B7>)
# 印出Generator物件矩形範圍的所有Cell物件
for iCell in list(aSheet.columns)[1]:
print(iCell.coordinate, iCell.value)
import openpyxl
# 本書範例檔example.xlsx在目前工作目錄
aBook = openpyxl.load_workbook("example.xlsx")
aSheet = aBook.active
# Generator物件含有矩形範圍的Cell物件
print(list(aSheet.rows)) à [(<Cell 'Sheet1'.A1>, <Cell 'Sheet1'.B1>, <Cell 'Sheet1'.C1>), …, (<Cell 'Sheet1'.A7>, <Cell 'Sheet1'.B7>, <Cell 'Sheet1'.C7>)]
print(list(aSheet.columns)[1]) à (<Cell 'Sheet1'.B1>, …, <Cell 'Sheet1'.B7>)
# 印出Generator物件矩形範圍的所有Cell物件
for iCell in list(aSheet.columns)[1]:
print(iCell.coordinate, iCell.value)
l 欄的字母和數字之間的轉換:
import openpyxl
from openpyxl.utils import get_column_letter, column_index_from_string
print(get_column_letter(27)) à AA
print(column_index_from_string("AA")) à 27
import openpyxl
from openpyxl.utils import get_column_letter, column_index_from_string
print(get_column_letter(27)) à AA
print(column_index_from_string("AA")) à 27
l 建立並儲存Excel檔:
import openpyxl
aBook = openpyxl.Workbook()
print(aBook.sheetnames) à ['Sheet']
aSheet = aBook.active
aSheet.title = "Hello World"
print(aBook.sheetnames) à ['Hello World']
aBook.save("test.xlsx")
import openpyxl
aBook = openpyxl.Workbook()
print(aBook.sheetnames) à ['Sheet']
aSheet = aBook.active
aSheet.title = "Hello World"
print(aBook.sheetnames) à ['Hello World']
aBook.save("test.xlsx")
l 建立與刪除Excel檔工作表:
import openpyxl
aBook = openpyxl.Workbook()
print(aBook.sheetnames) à ['Sheet']
aBook.create_sheet()
print(aBook.sheetnames) à ['Sheet', 'Sheet1']
aBook.create_sheet(index = 0, title = "First Sheet")
print(aBook.sheetnames) à ['First Sheet', 'Sheet', 'Sheet1']
del aBook["Sheet"]
print(aBook.sheetnames) à ['First Sheet', 'Sheet1']
aBook.remove(aBook["Sheet1"])
print(aBook.sheetnames) à ['First Sheet']
import openpyxl
aBook = openpyxl.Workbook()
print(aBook.sheetnames) à ['Sheet']
aBook.create_sheet()
print(aBook.sheetnames) à ['Sheet', 'Sheet1']
aBook.create_sheet(index = 0, title = "First Sheet")
print(aBook.sheetnames) à ['First Sheet', 'Sheet', 'Sheet1']
del aBook["Sheet"]
print(aBook.sheetnames) à ['First Sheet', 'Sheet1']
aBook.remove(aBook["Sheet1"])
print(aBook.sheetnames) à ['First Sheet']
l 將值寫入Excel檔工作表的儲存格:
import openpyxl
aBook = openpyxl.Workbook()
aSheet = aBook.active
aSheet["A1"] = "Hello World"
print(aSheet["A1"].value) à Hello World
import openpyxl
aBook = openpyxl.Workbook()
aSheet = aBook.active
aSheet["A1"] = "Hello World"
print(aSheet["A1"].value) à Hello World
OpenPyXL模組:視覺化功能操作
l 設定儲存格的字型:
import openpyxl
from openpyxl.styles import Font
aBook = openpyxl.Workbook()
aSheet = aBook.active
# Font物件為字體Times New Roman且粗體,並指定給font屬性
aSheet["A1"].font = Font(name = "Times New Roman", bold = True)
aSheet["A1"] = "Hello World"
# Font物件為大小24點且斜體,並指定給font屬性
aSheet["C3"].font = Font(size = 24, italic = True)
aSheet["C3"] = "Hello Poor World"
aBook.save("test.xlsx")
import openpyxl
from openpyxl.styles import Font
aBook = openpyxl.Workbook()
aSheet = aBook.active
# Font物件為字體Times New Roman且粗體,並指定給font屬性
aSheet["A1"].font = Font(name = "Times New Roman", bold = True)
aSheet["A1"] = "Hello World"
# Font物件為大小24點且斜體,並指定給font屬性
aSheet["C3"].font = Font(size = 24, italic = True)
aSheet["C3"] = "Hello Poor World"
aBook.save("test.xlsx")
l 設定儲存格的列高和欄寬:
import openpyxl
aBook = openpyxl.Workbook()
aSheet = aBook.active
# row_dimensions含有RowDimension物件,可設定為0到409之間
aSheet.row_dimensions[1].height = 70
# column_dimensions含有ColumnDimension物件,可設定為0到255之間
aSheet.column_dimensions["C"].width = 50
aBook.save("test.xlsx")
bBook = openpyxl.Workbook()
bSheet = bBook.active
# 可設定隱藏列高
bSheet.row_dimensions[1].hidden = True
# 可設定隱藏欄寬
bSheet.column_dimensions["C"].hidden = True
bBook.save("test2.xlsx")
import openpyxl
aBook = openpyxl.Workbook()
aSheet = aBook.active
# row_dimensions含有RowDimension物件,可設定為0到409之間
aSheet.row_dimensions[1].height = 70
# column_dimensions含有ColumnDimension物件,可設定為0到255之間
aSheet.column_dimensions["C"].width = 50
aBook.save("test.xlsx")
bBook = openpyxl.Workbook()
bSheet = bBook.active
# 可設定隱藏列高
bSheet.row_dimensions[1].hidden = True
# 可設定隱藏欄寬
bSheet.column_dimensions["C"].hidden = True
bBook.save("test2.xlsx")
l 設定儲存格的合併和取消合併:
import openpyxl
aBook = openpyxl.Workbook()
aSheet = aBook.active
aSheet.merge_cells("A1:C3")
aSheet["A1"] = "Hello World"
aBook.save("test.xlsx")
bBook = openpyxl.load_workbook("test.xlsx")
bSheet = bBook.active
bSheet.unmerge_cells("A1:C3")
bBook.save("test2.xlsx")
import openpyxl
aBook = openpyxl.Workbook()
aSheet = aBook.active
aSheet.merge_cells("A1:C3")
aSheet["A1"] = "Hello World"
aBook.save("test.xlsx")
bBook = openpyxl.load_workbook("test.xlsx")
bSheet = bBook.active
bSheet.unmerge_cells("A1:C3")
bBook.save("test2.xlsx")
l 凍結窗格:
import openpyxl
# 本書範例檔produceSales.xlsx在目前工作目錄
aBook = openpyxl.load_workbook("produceSales.xlsx")
aSheet = aBook.active
# 儲存格左方和上方將被凍結,儲存格本身不凍結
aSheet.freeze_panes = "A2"
aBook.save("test.xlsx")
bBook = openpyxl.load_workbook("test.xlsx")
bSheet = bBook.active
# 若要解除凍結窗格,傳入None或"A1"皆可
bSheet.freeze_panes = None
bBook.save("test2.xlsx")
import openpyxl
# 本書範例檔produceSales.xlsx在目前工作目錄
aBook = openpyxl.load_workbook("produceSales.xlsx")
aSheet = aBook.active
# 儲存格左方和上方將被凍結,儲存格本身不凍結
aSheet.freeze_panes = "A2"
aBook.save("test.xlsx")
bBook = openpyxl.load_workbook("test.xlsx")
bSheet = bBook.active
# 若要解除凍結窗格,傳入None或"A1"皆可
bSheet.freeze_panes = None
bBook.save("test2.xlsx")
l 繪製長條圖、折線圖、圓餅圖:
import openpyxl
aBook = openpyxl.Workbook()
aSheet = aBook.active
for i in range(1, 11):
aSheet["A" + str(i)] = i
# Reference物件的5個引數分別為Worksheet物件、範圍區域的左上角儲存格欄列、範圍區域的右下角儲存格欄列,第二至第五引數可只填正整數
aRefer = openpyxl.chart.Reference(aSheet, min_col = 1, min_row = 1, max_col = 1, max_row = 10)
# Series物件
aSerie = openpyxl.chart.Series(aRefer, title = "First Series")
# Chart物件:長條圖
aChart = openpyxl.chart.BarChart()
aChart.title = "Bar Chart Title"
aChart.append(aSerie)
aSheet.add_chart(aChart, "C1")
# Chart物件:折線圖
bChart = openpyxl.chart.LineChart()
bChart.title = "Line Chart Title"
bChart.append(aSerie)
aSheet.add_chart(bChart, "C15")
# Chart物件:圓餅圖
cChart = openpyxl.chart.PieChart()
cChart.title = "Pie Chart Title"
cChart.append(aSerie)
aSheet.add_chart(cChart, "C29")
aBook.save("test.xlsx")
import openpyxl
aBook = openpyxl.Workbook()
aSheet = aBook.active
for i in range(1, 11):
aSheet["A" + str(i)] = i
# Reference物件的5個引數分別為Worksheet物件、範圍區域的左上角儲存格欄列、範圍區域的右下角儲存格欄列,第二至第五引數可只填正整數
aRefer = openpyxl.chart.Reference(aSheet, min_col = 1, min_row = 1, max_col = 1, max_row = 10)
# Series物件
aSerie = openpyxl.chart.Series(aRefer, title = "First Series")
# Chart物件:長條圖
aChart = openpyxl.chart.BarChart()
aChart.title = "Bar Chart Title"
aChart.append(aSerie)
aSheet.add_chart(aChart, "C1")
# Chart物件:折線圖
bChart = openpyxl.chart.LineChart()
bChart.title = "Line Chart Title"
bChart.append(aSerie)
aSheet.add_chart(bChart, "C15")
# Chart物件:圓餅圖
cChart = openpyxl.chart.PieChart()
cChart.title = "Pie Chart Title"
cChart.append(aSerie)
aSheet.add_chart(cChart, "C29")
aBook.save("test.xlsx")
l 繪製散佈圖:
import openpyxl
aBook = openpyxl.Workbook()
aSheet = aBook.active
for i in range(1, 11):
aSheet["A" + str(i)] = i
aSheet["B" + str(i)] = i**2 + 5
aRefer = openpyxl.chart.Reference(aSheet, 2, 1, 2, 10)
bRefer = openpyxl.chart.Reference(aSheet, 1, 1, 1, 10)
aSerie = openpyxl.chart.Series(aRefer, bRefer, title = "First Series")
# Chart物件:散佈圖
aChart = openpyxl.chart.ScatterChart()
aChart.title = "Scatter Chart Title"
aChart.append(aSerie)
aSheet.add_chart(aChart, "C1")
aBook.save("test.xlsx")
import openpyxl
aBook = openpyxl.Workbook()
aSheet = aBook.active
for i in range(1, 11):
aSheet["A" + str(i)] = i
aSheet["B" + str(i)] = i**2 + 5
aRefer = openpyxl.chart.Reference(aSheet, 2, 1, 2, 10)
bRefer = openpyxl.chart.Reference(aSheet, 1, 1, 1, 10)
aSerie = openpyxl.chart.Series(aRefer, bRefer, title = "First Series")
# Chart物件:散佈圖
aChart = openpyxl.chart.ScatterChart()
aChart.title = "Scatter Chart Title"
aChart.append(aSerie)
aSheet.add_chart(aChart, "C1")
aBook.save("test.xlsx")
三、處理PDF與Word文件
PyPDF2模組
l 在命令提示字元輸入pip install PyPDF2,下載並安裝PyPDF2模組。
l 從PDF檔擷取文字:
import PyPDF2
# 本書範例檔meetingminutes.pdf在目前工作目錄
aReader = PyPDF2.PdfFileReader(open("meetingminutes.pdf", "rb"))
# 印出PDF檔頁數
print(aReader.numPages) à19
aPage = aReader.getPage(0)
# 印出PDF檔頁面文字
print(aPage.extractText())
import PyPDF2
# 本書範例檔meetingminutes.pdf在目前工作目錄
aReader = PyPDF2.PdfFileReader(open("meetingminutes.pdf", "rb"))
# 印出PDF檔頁數
print(aReader.numPages) à19
aPage = aReader.getPage(0)
# 印出PDF檔頁面文字
print(aPage.extractText())
l 解密PDF檔:
import PyPDF2
# 本書範例檔encrypted.pdf在目前工作目錄
aReader = PyPDF2.PdfFileReader(open("encrypted.pdf", "rb"))
print(aReader.isEncrypted) à True
aReader.getPage(0) à PdfReadError
# 傳入的密碼錯誤會顯示0,正確會顯示1
print(aReader.decrypt("rosebud")) à 1
aReader.getPage(0)
import PyPDF2
# 本書範例檔encrypted.pdf在目前工作目錄
aReader = PyPDF2.PdfFileReader(open("encrypted.pdf", "rb"))
print(aReader.isEncrypted) à True
aReader.getPage(0) à PdfReadError
# 傳入的密碼錯誤會顯示0,正確會顯示1
print(aReader.decrypt("rosebud")) à 1
aReader.getPage(0)
l 複製頁面並建立新PDF檔:
import PyPDF2
# 本書範例檔meetingminutes.pdf在目前工作目錄
aReader = PyPDF2.PdfFileReader(open("meetingminutes.pdf", "rb"))
# 本書範例檔meetingminutes2.pdf在目前工作目錄
bReader = PyPDF2.PdfFileReader(open("meetingminutes2.pdf", "rb"))
aWriter = PyPDF2.PdfFileWriter()
# addPage方法僅能在PDF檔尾端加入頁面
for i in range(aReader.numPages):
aWriter.addPage(aReader.getPage(i))
for j in range(bReader.numPages):
aWriter.addPage(bReader.getPage(i))
aFile = open("combinedmimutes.pdf", "wb")
aWriter.write(aFile)
aFile.close()
import PyPDF2
# 本書範例檔meetingminutes.pdf在目前工作目錄
aReader = PyPDF2.PdfFileReader(open("meetingminutes.pdf", "rb"))
# 本書範例檔meetingminutes2.pdf在目前工作目錄
bReader = PyPDF2.PdfFileReader(open("meetingminutes2.pdf", "rb"))
aWriter = PyPDF2.PdfFileWriter()
# addPage方法僅能在PDF檔尾端加入頁面
for i in range(aReader.numPages):
aWriter.addPage(aReader.getPage(i))
for j in range(bReader.numPages):
aWriter.addPage(bReader.getPage(i))
aFile = open("combinedmimutes.pdf", "wb")
aWriter.write(aFile)
aFile.close()
l 旋轉頁面並建立新PDF檔:
import PyPDF2
# 本書範例檔meetingminutes.pdf在目前工作目錄
aReader = PyPDF2.PdfFileReader(open("meetingminutes.pdf", "rb"))
aPage = aReader.getPage(0)
# 將第一頁順時針旋轉90度
aPage.rotateClockwise(90)
bPage = aReader.getPage(1)
# 將第二頁逆時針旋轉90度
bPage.rotateCounterClockwise(90)
aWriter = PyPDF2.PdfFileWriter()
aWriter.addPage(aPage)
aWriter.addPage(bPage)
aFile = open("rotatedPage.pdf", "wb")
aWriter.write(aFile)
aFile.close()
import PyPDF2
# 本書範例檔meetingminutes.pdf在目前工作目錄
aReader = PyPDF2.PdfFileReader(open("meetingminutes.pdf", "rb"))
aPage = aReader.getPage(0)
# 將第一頁順時針旋轉90度
aPage.rotateClockwise(90)
bPage = aReader.getPage(1)
# 將第二頁逆時針旋轉90度
bPage.rotateCounterClockwise(90)
aWriter = PyPDF2.PdfFileWriter()
aWriter.addPage(aPage)
aWriter.addPage(bPage)
aFile = open("rotatedPage.pdf", "wb")
aWriter.write(aFile)
aFile.close()
l 加入浮水印並建立新PDF檔:
import PyPDF2
# 本書範例檔meetingminutes.pdf在目前工作目錄
aReader = PyPDF2.PdfFileReader(open("meetingminutes.pdf", "rb"))
# 本書範例檔watermark.pdf在目前工作目錄
bReader = PyPDF2.PdfFileReader(open("watermark.pdf", "rb"))
aPage = aReader.getPage(0)
aPage.mergePage(bReader.getPage(0))
aWriter = PyPDF2.PdfFileWriter()
aWriter.addPage(aPage)
for i in range(1, aReader.numPages):
aWriter.addPage(aReader.getPage(i))
aFile = open("watermarkedCover.pdf", "wb")
aWriter.write(aFile)
aFile.close()
import PyPDF2
# 本書範例檔meetingminutes.pdf在目前工作目錄
aReader = PyPDF2.PdfFileReader(open("meetingminutes.pdf", "rb"))
# 本書範例檔watermark.pdf在目前工作目錄
bReader = PyPDF2.PdfFileReader(open("watermark.pdf", "rb"))
aPage = aReader.getPage(0)
aPage.mergePage(bReader.getPage(0))
aWriter = PyPDF2.PdfFileWriter()
aWriter.addPage(aPage)
for i in range(1, aReader.numPages):
aWriter.addPage(aReader.getPage(i))
aFile = open("watermarkedCover.pdf", "wb")
aWriter.write(aFile)
aFile.close()
l 加密檔案並建立新PDF檔:
import PyPDF2
aReader = PyPDF2.PdfFileReader(open("meetingminutes.pdf", "rb"))
aWriter = PyPDF2.PdfFileWriter()
for i in range(aReader.numPages):
aWriter.addPage(aReader.getPage(i))
# encrypt()方法的第一個引數是使用者密碼,第二個引數是擁有者密碼,如果只傳入一個引數,當成擁有者密碼
# 使用者密碼:僅限閱讀瀏覽這份PDF
# 擁有者密碼:有所有權限,能列印、加注解、擷取文字和其它功能
aWriter.encrypt("rosebud", "adminpassword")
aFile = open("encryptedminutes.pdf", "wb")
aWriter.write(aFile)
aFile.close()
import PyPDF2
aReader = PyPDF2.PdfFileReader(open("meetingminutes.pdf", "rb"))
aWriter = PyPDF2.PdfFileWriter()
for i in range(aReader.numPages):
aWriter.addPage(aReader.getPage(i))
# encrypt()方法的第一個引數是使用者密碼,第二個引數是擁有者密碼,如果只傳入一個引數,當成擁有者密碼
# 使用者密碼:僅限閱讀瀏覽這份PDF
# 擁有者密碼:有所有權限,能列印、加注解、擷取文字和其它功能
aWriter.encrypt("rosebud", "adminpassword")
aFile = open("encryptedminutes.pdf", "wb")
aWriter.write(aFile)
aFile.close()
文件軟體
Python-Docx模組:基本功能操作
l 在命令提示字元輸入pip install python-docx,下載並安裝Python-Docx模組。
l docx檔的Document物件、Paragraph物件、Run物件:
import docx
# Document物件代表整份文件
# 本書範例檔demo.docx在目前工作目錄
aDocx = docx.Document("demo.docx")
# Paragraph物件代表文件中的段落
print(len(aDocx.paragraphs)) à 7
print(aDocx.paragraphs[0].text) à Document Title
# Run物件代表相同樣式連續鄰接的文字
print(len(aDocx.paragraphs[1].runs)) à 5
print(aDocx.paragraphs[1].runs[0].text) à A plain paragraph with
import docx
# Document物件代表整份文件
# 本書範例檔demo.docx在目前工作目錄
aDocx = docx.Document("demo.docx")
# Paragraph物件代表文件中的段落
print(len(aDocx.paragraphs)) à 7
print(aDocx.paragraphs[0].text) à Document Title
# Run物件代表相同樣式連續鄰接的文字
print(len(aDocx.paragraphs[1].runs)) à 5
print(aDocx.paragraphs[1].runs[0].text) à A plain paragraph with
l 從docx檔擷取文字:
import docx
aDocx = docx.Document("demo.docx")
textList = []
for i in aDocx.paragraphs:
textList.append(i.text)
textStr = "\n".join(textList)
print(textStr)
import docx
aDocx = docx.Document("demo.docx")
textList = []
for i in aDocx.paragraphs:
textList.append(i.text)
textStr = "\n".join(textList)
print(textStr)
l 寫入文字、換行符號、分頁符號並建立新docx檔:
import docx
aDocx = docx.Document()
# 寫入文字
aDocx.add_paragraph("Hello World")
aDocx.add_paragraph("Hello Poor World")
# 新增換行符號
aDocx.paragraphs[0].runs[0].add_break()
# 新增分頁符號
aDocx.paragraphs[1].runs[0].add_break(docx.enum.text.WD_BREAK.PAGE)
aDocx.save("test.docx")
import docx
aDocx = docx.Document()
# 寫入文字
aDocx.add_paragraph("Hello World")
aDocx.add_paragraph("Hello Poor World")
# 新增換行符號
aDocx.paragraphs[0].runs[0].add_break()
# 新增分頁符號
aDocx.paragraphs[1].runs[0].add_break(docx.enum.text.WD_BREAK.PAGE)
aDocx.save("test.docx")
Python-Docx模組:視覺化功能操作
l 設定Paragraph和Run物件的樣式:
import docx
# 本書範例檔demo.docx在目前工作目錄
aDocx = docx.Document("demo.docx")
print(aDocx.paragraphs[0].text) à Document Title
print(aDocx.paragraphs[0].style) à _ParagraphStyle('Title') id: 98056432
# 更改Paragraph物件style屬性,參考下列段落樣式表格說明
aDocx.paragraphs[0].style = "Normal"
print(aDocx.paragraphs[1].runs[2].text) à bold
# 更改Run物件屬性,參考下列字元樣式表格說明
aDocx.paragraphs[1].runs[2].underline = True
aDocx.save("test.docx")
import docx
# 本書範例檔demo.docx在目前工作目錄
aDocx = docx.Document("demo.docx")
print(aDocx.paragraphs[0].text) à Document Title
print(aDocx.paragraphs[0].style) à _ParagraphStyle('Title') id: 98056432
# 更改Paragraph物件style屬性,參考下列段落樣式表格說明
aDocx.paragraphs[0].style = "Normal"
print(aDocx.paragraphs[1].runs[2].text) à bold
# 更改Run物件屬性,參考下列字元樣式表格說明
aDocx.paragraphs[1].runs[2].underline = True
aDocx.save("test.docx")
l 段落樣式表格:
Normal 內文 Body Text 本文
Caption 書名 Heading 1 標題1
Intense Quote 鮮明引文 List 清單
List Bullet 項目符號 List Continue 接續
List Number 清單號碼 List Paragraph 清單段落
MacroText 巨集文字 No Spacing 無間距
Quote 引文 Subtitle 副標題
TOC Heading 書目 Title 標題
Normal 內文 Body Text 本文
Caption 書名 Heading 1 標題1
Intense Quote 鮮明引文 List 清單
List Bullet 項目符號 List Continue 接續
List Number 清單號碼 List Paragraph 清單段落
MacroText 巨集文字 No Spacing 無間距
Quote 引文 Subtitle 副標題
TOC Heading 書目 Title 標題
l 字元樣式表格:
bold 粗體 italic 斜體
underline 底線 strike 刪除線
double_strike 雙刪除線 all_caps 首字大寫
shadow 陰影 outline 外框
imprint 內陰影 emboss 浮凸
small_caps 首字大寫,小寫縮寫兩點
rtl 由右至左書寫
bold 粗體 italic 斜體
underline 底線 strike 刪除線
double_strike 雙刪除線 all_caps 首字大寫
shadow 陰影 outline 外框
imprint 內陰影 emboss 浮凸
small_caps 首字大寫,小寫縮寫兩點
rtl 由右至左書寫
l 段落樣式、字元樣式與連結樣式:
Word文件有3種類型的樣式,段落樣式可套入Paragraph物件,字元樣式可套入Run物件,連結樣式則都可套入這2種物件;如果對Run物件套入連結樣式,樣式名稱最後需要加上Char:
import docx
# 本書範例檔demo.docx在目前工作目錄
aDocx = docx.Document("demo.docx")
print(aDocx.paragraphs[0].text) à Document Title
aDocx.paragraphs[0].style = "Quote"
print(aDocx.paragraphs[1].runs[2].text) à bold
aDocx.paragraphs[1].runs[2].style = "Quote Char"
aDocx.save("test.docx")
Word文件有3種類型的樣式,段落樣式可套入Paragraph物件,字元樣式可套入Run物件,連結樣式則都可套入這2種物件;如果對Run物件套入連結樣式,樣式名稱最後需要加上Char:
import docx
# 本書範例檔demo.docx在目前工作目錄
aDocx = docx.Document("demo.docx")
print(aDocx.paragraphs[0].text) à Document Title
aDocx.paragraphs[0].style = "Quote"
print(aDocx.paragraphs[1].runs[2].text) à bold
aDocx.paragraphs[1].runs[2].style = "Quote Char"
aDocx.save("test.docx")
l 寫入文字與樣式並建立新docx檔:
import docx
aDocx = docx.Document()
# 整數0代表套入Title標題樣式
aDocx.add_heading("Header 0", 0)
# 整數1至4代表套入不同的標題層級樣式
aDocx.add_heading("Header 1", 1)
aDocx.add_paragraph("Hello World")
aPara = aDocx.add_paragraph("Hello Poor World", "Title")
aPara.add_run(", the Poor and Dispirited World", "Quote Char")
aDocx.save("test.docx")
import docx
aDocx = docx.Document()
# 整數0代表套入Title標題樣式
aDocx.add_heading("Header 0", 0)
# 整數1至4代表套入不同的標題層級樣式
aDocx.add_heading("Header 1", 1)
aDocx.add_paragraph("Hello World")
aPara = aDocx.add_paragraph("Hello Poor World", "Title")
aPara.add_run(", the Poor and Dispirited World", "Quote Char")
aDocx.save("test.docx")
l 新增圖片並建立新docx檔:
import docx
aDocx = docx.Document()
# 本書範例檔zophie.png在目前工作目錄
# 寬度設為1英寸,高度設為4公分,為選擇性引數
aDocx.add_picture("zophie.png", width = docx.shared.Inches(1), height = docx.shared.Cm(4))
aDocx.save("test.docx")
import docx
aDocx = docx.Document()
# 本書範例檔zophie.png在目前工作目錄
# 寬度設為1英寸,高度設為4公分,為選擇性引數
aDocx.add_picture("zophie.png", width = docx.shared.Inches(1), height = docx.shared.Cm(4))
aDocx.save("test.docx")
四、處理CSV檔和JSON資料
CSV(Comma-Separated Values)檔
l CSV是純文字格式的試算表,一行代表一列,以逗號分隔資料。
l Reader物件:
import csv
# 本書範例檔example.csv在目前工作目錄
aReader = csv.reader(open("example.csv"))
aData = list(aReader)
print(aData) à [['4/5/2014 13:34', 'Apples', '73'], …
print(aData[0][1]) à Apples
# Reader物件只能遍訪一次,若想要再一次讀取CSV檔,則需要再一次呼叫csv.reader來建立物件
bReader = csv.reader(open("example.csv"))
for i in bReader:
print("Row " + str(bReader.line_num) + " " + str(i))
à Row 1 ['4/5/2014 13:34', 'Apples', '73']…
import csv
# 本書範例檔example.csv在目前工作目錄
aReader = csv.reader(open("example.csv"))
aData = list(aReader)
print(aData) à [['4/5/2014 13:34', 'Apples', '73'], …
print(aData[0][1]) à Apples
# Reader物件只能遍訪一次,若想要再一次讀取CSV檔,則需要再一次呼叫csv.reader來建立物件
bReader = csv.reader(open("example.csv"))
for i in bReader:
print("Row " + str(bReader.line_num) + " " + str(i))
à Row 1 ['4/5/2014 13:34', 'Apples', '73']…
l Writer物件:
import csv
aFile = open("test.csv", "w", newline = "")
aWriter = csv.writer(aFile)
aWriter.writerow(["Hello", "World"])
aWriter.writerow(["Hello", "Poor", "World", "10,000 dollars"])
aWriter.writerow([1, 2, 3.14, 4])
aFile.close()
import csv
aFile = open("test.csv", "w", newline = "")
aWriter = csv.writer(aFile)
aWriter.writerow(["Hello", "World"])
aWriter.writerow(["Hello", "Poor", "World", "10,000 dollars"])
aWriter.writerow([1, 2, 3.14, 4])
aFile.close()
l Writer物件的delimiter與lineterminator引數:
import csv
aFile = open("test.tsv", "w", newline = "")
# 分隔符號delimiter預設為逗號,更換為"\t"
# 行尾終止符號lineterminator預設為一個換行符號,更換為"XXX"
aWriter = csv.writer(aFile, delimiter = "\t", lineterminator = "XXX")
aWriter.writerow(["Hello", "World"])
aWriter.writerow(["Hello", "Poor", "World", "10,000 dollars"])
aWriter.writerow([1, 2, 3.14, 4])
aFile.close()
import csv
aFile = open("test.tsv", "w", newline = "")
# 分隔符號delimiter預設為逗號,更換為"\t"
# 行尾終止符號lineterminator預設為一個換行符號,更換為"XXX"
aWriter = csv.writer(aFile, delimiter = "\t", lineterminator = "XXX")
aWriter.writerow(["Hello", "World"])
aWriter.writerow(["Hello", "Poor", "World", "10,000 dollars"])
aWriter.writerow([1, 2, 3.14, 4])
aFile.close()
JSON(JavaScript Object Notation)檔
l JSON是JavaScript程式碼形式的純文字格式,應用在許多Web API之中。
l JSON不能存放每一種Python值,其值只能是以下資料型別:字串、整數、浮點數、布林、串列、字典和NoneType。
l 使用loads()函式讀取JSON:
stringOfJsonData = '{"pokemon": "Porygon2", "beAbleToEvolve": true, "owned": 0, "gender": null}'
import json
pythonValue = json.loads(stringOfJsonData)
print(pythonValue) à {'pokemon': 'Porygon2', 'beAbleToEvolve': True, 'owned': 0, 'gender': None}
stringOfJsonData = '{"pokemon": "Porygon2", "beAbleToEvolve": true, "owned": 0, "gender": null}'
import json
pythonValue = json.loads(stringOfJsonData)
print(pythonValue) à {'pokemon': 'Porygon2', 'beAbleToEvolve': True, 'owned': 0, 'gender': None}
l 使用dumps()函式寫入JSON:
pythonValue = {'pokemon': 'Porygon2', 'beAbleToEvolve': True, 'owned': 0, 'gender': None}
import json
stringOfJsonData = json.dumps(pythonValue)
print(stringOfJsonData) à {"pokemon": "Porygon2", "beAbleToEvolve": true, "owned": 0, "gender": null}
pythonValue = {'pokemon': 'Porygon2', 'beAbleToEvolve': True, 'owned': 0, 'gender': None}
import json
stringOfJsonData = json.dumps(pythonValue)
print(stringOfJsonData) à {"pokemon": "Porygon2", "beAbleToEvolve": true, "owned": 0, "gender": null}
五、保持時間、工作排程和程式啟動
time模組
l time.time()函式:
import time
# Unix紀元(Unix Epoch)是程式設計中常用參考的時間,為世界標準時間(UTC)1970年1月1日0點,time.time()函式返回值是Unix紀元起與time.time()函式被呼叫的那一刻之間的秒數
a = time.time()
print(a) à 1520826796.570343
print(round(a, 2)) à 1520826796.57
print(round(a)) à 1520826797
import time
# Unix紀元(Unix Epoch)是程式設計中常用參考的時間,為世界標準時間(UTC)1970年1月1日0點,time.time()函式返回值是Unix紀元起與time.time()函式被呼叫的那一刻之間的秒數
a = time.time()
print(a) à 1520826796.570343
print(round(a, 2)) à 1520826796.57
print(round(a)) à 1520826797
l time.sleep()函式:
import time
for i in range(3):
print("Tick")
# 程式暫停秒數,注意在IDLE中按下Ctrl-C鍵也不能中斷time.sleep()的呼叫,因此必須善用迴圈
time.sleep(1)
print("Tock")
time.sleep(1)
import time
for i in range(3):
print("Tick")
# 程式暫停秒數,注意在IDLE中按下Ctrl-C鍵也不能中斷time.sleep()的呼叫,因此必須善用迴圈
time.sleep(1)
print("Tock")
time.sleep(1)
datetime模組
l 現在時間點與指定時間點:
import datetime
print(datetime.datetime.now()) à 2018-03-12 20:49:23.106381
a = datetime.datetime(2018, 6, 21, 12, 0, 0)
print(a.year, a.month, a.day, a.hour, a.minute, a.second) à 2018 6 21 12 0 0
import datetime
print(datetime.datetime.now()) à 2018-03-12 20:49:23.106381
a = datetime.datetime(2018, 6, 21, 12, 0, 0)
print(a.year, a.month, a.day, a.hour, a.minute, a.second) à 2018 6 21 12 0 0
l Unix紀元時間戳(Epoch Timestamp)轉換成datetime物件:
import datetime, time
print(datetime.datetime.fromtimestamp(time.time()))
à 2018-03-12 20:50:35.826073
import datetime, time
print(datetime.datetime.fromtimestamp(time.time()))
à 2018-03-12 20:50:35.826073
l 一段時間:
import datetime
a = datetime.timedelta(weeks = 1, days = 1, hours = 1, minutes = 1, seconds = 1, milliseconds = 1, microseconds = 1)
# days屬性計算weeks與days總和,seconds屬性計算hours、minutes與seconds總和,microseconds屬性計算milliseconds與microseconds總和
print(a.days, a.seconds, a.microseconds) à 8 3661 1001
# 僅能以秒計算全部時間的長度
print(a.total_seconds()) à 694861.001001
print(a) à 8 days, 1:01:01.001001
import datetime
a = datetime.timedelta(weeks = 1, days = 1, hours = 1, minutes = 1, seconds = 1, milliseconds = 1, microseconds = 1)
# days屬性計算weeks與days總和,seconds屬性計算hours、minutes與seconds總和,microseconds屬性計算milliseconds與microseconds總和
print(a.days, a.seconds, a.microseconds) à 8 3661 1001
# 僅能以秒計算全部時間的長度
print(a.total_seconds()) à 694861.001001
print(a) à 8 days, 1:01:01.001001
l 時間點與一段時間的運算:
import datetime
a = datetime.datetime.now()
print(a) à 2018-03-13 08:28:51.926122
b = datetime.timedelta(days = 1000)
print(a + b) à 2020-12-07 08:28:51.926122
import datetime
a = datetime.datetime.now()
print(a) à 2018-03-13 08:28:51.926122
b = datetime.timedelta(days = 1000)
print(a + b) à 2020-12-07 08:28:51.926122
l 暫停到某個指定時間點:
import datetime, time
a = datetime.datetime.now()
b = datetime.timedelta(days = 3)
while datetime.datetime.now() < a + b:
time.sleep(1)
import datetime, time
a = datetime.datetime.now()
b = datetime.timedelta(days = 3)
while datetime.datetime.now() < a + b:
time.sleep(1)
l datetime物件轉換成字串:
import datetime
a = datetime.datetime(2018, 6, 21, 13, 2, 1)
# %Y代表年;%y代表年
# %m代表月;%B代表月;%b代表月
# %d代表月的第幾日;%j代表年的第幾日
# %w代表星期;%A代表星期;%a代表星期
print(a.strftime("%Y, %y, %m, %B, %b, %d, %j, %w, %A, %a"))
à 2018, 18, 06, June, Jun, 21, 172, 4, Thursday, Thu
# %H代表24小時制;%I代表12小時制
# %M代表分鐘
# %S代表秒鐘
# %p代表"AM"或"PM";%%代表"%"字元
print(a.strftime("%H, %I, %M, %S, %p, %%"))
à 13, 01, 02, 01, PM, %
import datetime
a = datetime.datetime(2018, 6, 21, 13, 2, 1)
# %Y代表年;%y代表年
# %m代表月;%B代表月;%b代表月
# %d代表月的第幾日;%j代表年的第幾日
# %w代表星期;%A代表星期;%a代表星期
print(a.strftime("%Y, %y, %m, %B, %b, %d, %j, %w, %A, %a"))
à 2018, 18, 06, June, Jun, 21, 172, 4, Thursday, Thu
# %H代表24小時制;%I代表12小時制
# %M代表分鐘
# %S代表秒鐘
# %p代表"AM"或"PM";%%代表"%"字元
print(a.strftime("%H, %I, %M, %S, %p, %%"))
à 13, 01, 02, 01, PM, %
l 字串轉換成datetime物件:
import datetime
print(datetime.datetime.strptime("June 21, 2018", "%B %d, %Y"))
à 2018-06-21 00:00:00
print(datetime.datetime.strptime("2018/06/21 13:02:01", "%Y/%m/%d %H:%M:%S"))
à 2018-06-21 13:02:01
import datetime
print(datetime.datetime.strptime("June 21, 2018", "%B %d, %Y"))
à 2018-06-21 00:00:00
print(datetime.datetime.strptime("2018/06/21 13:02:01", "%Y/%m/%d %H:%M:%S"))
à 2018-06-21 13:02:01
threading模組
l 多執行緒(Multithreading)指同時執行著不同的程式碼行。
l 無傳入引數到執行緒的目標函式內:
import time, threading
print("Start of Program")
def takeANap():
time.sleep(5)
print("Wake Up")
aThread = threading.Thread(target = takeANap)
aThread.start()
print("End of Program") à
Start of Program
End of Program
>>> Wake Up
import time, threading
print("Start of Program")
def takeANap():
time.sleep(5)
print("Wake Up")
aThread = threading.Thread(target = takeANap)
aThread.start()
print("End of Program") à
Start of Program
End of Program
>>> Wake Up
l 有傳入引數到執行緒的目標函式內:
import threading
aThread = threading.Thread(target = print, args = ["Hello", "World"], kwargs = {"sep": " Poor "})
aThread.start() à Hello Poor World
import threading
aThread = threading.Thread(target = print, args = ["Hello", "World"], kwargs = {"sep": " Poor "})
aThread.start() à Hello Poor World
l Thread物件的join()方法來定住,直到所有執行緒都完成才放行:
import time, threading
print("Start of Program")
def takeANap():
time.sleep(5)
print("Wake Up")
aThread = threading.Thread(target = takeANap)
bThread = threading.Thread(target = print, args = ["Hello", "World"], kwargs = {"sep": " Poor "})
aThread.start()
bThread.start()
aThread.join()
bThread.join()
print("End of Program") à
Start of Program
Hello Poor World
Wake Up
End of Program
import time, threading
print("Start of Program")
def takeANap():
time.sleep(5)
print("Wake Up")
aThread = threading.Thread(target = takeANap)
bThread = threading.Thread(target = print, args = ["Hello", "World"], kwargs = {"sep": " Poor "})
aThread.start()
bThread.start()
aThread.join()
bThread.join()
print("End of Program") à
Start of Program
Hello Poor World
Wake Up
End of Program
subprocess模組
l 從Python啟動其他應用程式,每個處理程序可有多個執行緒,然而處理程序不像執行緒,不能直接讀寫另一個處理程序的變數。
l Popen物件:
import subprocess
a = subprocess.Popen(r"C:\Windows\System32\calc.exe")
# Popen物件的poll()方法,程式仍在執行返回None,程式無錯結束返回退出碼(Exit Code)0,程式出錯結束返回退出碼不為0(多為1)
print(a.poll() == None) à True
# Popen物件的wait()方法,等著執行完程式碼,再繼續執行其他程式碼,返回值是退出碼
print(a.wait()) à 0
print(a.poll()) à 0
import subprocess
a = subprocess.Popen(r"C:\Windows\System32\calc.exe")
# Popen物件的poll()方法,程式仍在執行返回None,程式無錯結束返回退出碼(Exit Code)0,程式出錯結束返回退出碼不為0(多為1)
print(a.poll() == None) à True
# Popen物件的wait()方法,等著執行完程式碼,再繼續執行其他程式碼,返回值是退出碼
print(a.wait()) à 0
print(a.poll()) à 0
l 對Popen()傳入命令提示列引數開啟檔案:
import subprocess
subprocess.Popen([r"C:\Windows\notepad.exe", "test.txt"])
subprocess.Popen([r"C:\Python36\python.exe", "test.py"])
# shell = True只在Windows系統中有需要用到
subprocess.Popen(["start", "test2.txt"], shell = True)
import subprocess
subprocess.Popen([r"C:\Windows\notepad.exe", "test.txt"])
subprocess.Popen([r"C:\Python36\python.exe", "test.py"])
# shell = True只在Windows系統中有需要用到
subprocess.Popen(["start", "test2.txt"], shell = True)
六、發送Email和文字簡訊
SMTP負責對別人傳送Email
l import smtplib
# 連接到SMTP伺服器,第一個引數是SMTP伺服器網域名稱,第二個引數是連接埠埠號
# 支援TLS埠號587:smtpObj = smtplib.SMTP("smtp.example.com", 587)
# 支援SSL埠號465:smtpObj = smtplib.SMTP_SSL("smtp.example.com", 465)
smtpObj = smtplib.SMTP_SSL("smtp.ntnu.edu.tw", 465)
# 傳送SMTP的"Hello"訊息,返回值250代表傳送訊息成功
print(smtpObj.ehlo())
# 啟動TLS加密才需要使用,返回值220代表伺服器已準備好
# smtpObj.starttls()
# 登入SMTP伺服器,返回值235代表授權驗證成功
# 若是使用Gmail,Gmail對Google帳號提供一個附加的安全功能稱之為應用程式密碼(Application-Specific Passwords)
smtpObj.login("myAccount@ntnu.edu.tw", "myPassword")
# 傳送Email,以2個換行符號將主旨和郵件的內文分隔,返回的字典以鍵值對的形式,記載傳送失敗的每個收件人
smtpObj.sendmail("from@example.com", "to@example.com", "Subject: Test\n\nContent: Test")
# 切斷SMTP伺服器連線,返回值221代表連線結束
print(smtpObj.quit())
# 連接到SMTP伺服器,第一個引數是SMTP伺服器網域名稱,第二個引數是連接埠埠號
# 支援TLS埠號587:smtpObj = smtplib.SMTP("smtp.example.com", 587)
# 支援SSL埠號465:smtpObj = smtplib.SMTP_SSL("smtp.example.com", 465)
smtpObj = smtplib.SMTP_SSL("smtp.ntnu.edu.tw", 465)
# 傳送SMTP的"Hello"訊息,返回值250代表傳送訊息成功
print(smtpObj.ehlo())
# 啟動TLS加密才需要使用,返回值220代表伺服器已準備好
# smtpObj.starttls()
# 登入SMTP伺服器,返回值235代表授權驗證成功
# 若是使用Gmail,Gmail對Google帳號提供一個附加的安全功能稱之為應用程式密碼(Application-Specific Passwords)
smtpObj.login("myAccount@ntnu.edu.tw", "myPassword")
# 傳送Email,以2個換行符號將主旨和郵件的內文分隔,返回的字典以鍵值對的形式,記載傳送失敗的每個收件人
smtpObj.sendmail("from@example.com", "to@example.com", "Subject: Test\n\nContent: Test")
# 切斷SMTP伺服器連線,返回值221代表連線結束
print(smtpObj.quit())
IMAP負責收回給您的Email
l 在命令提示字元輸入pip install imapclient,下載並安裝IMAPClient模組。
在命令提示字元輸入pip install pyzmail(若安裝失敗,改輸入easy_install pyzmail),下載並安裝PyzMail模組。
在命令提示字元輸入pip install pyzmail(若安裝失敗,改輸入easy_install pyzmail),下載並安裝PyzMail模組。
l import imapclient, pprint
# 連接到IMAP伺服器,第一個引數是IMAP伺服器網域名稱,第二個引數是SSL加密
imapObj = imapclient.IMAPClient("imap.mail.yahoo.com", ssl = True)
# 登入IMAP伺服器
# 若是使用Gmail,Gmail對Google帳號提供一個附加的安全功能稱之為應用程式密碼(Application-Specific Passwords)
imapObj.login("myAccount@yahoo.com.tw", "myPassword")
pprint.pprint(imapObj.list_folders())
# 選取資料夾,readonly = True以唯讀防止任何更動Email資料夾的動作
imapObj.select_folder("Inbox", readonly = True)
# 執行尋找,字串串列為IMAP搜尋鍵(Search Key),參考下列說明
# 若是使用Gmail,可使用Gmail網頁上方的搜尋列:UIDs = imapObj.gmail_search("Test")
UIDs = imapObj.search(["SINCE", "21-Jun-2017", "BEFORE", "21-Jun-2018"])
pprint.pprint(UIDs)
# 收取Email,第一個引數是UID串列,第二個引數是所有內文
rawMessages = imapObj.fetch([8755], [b"BODY[]"])
# 從原始訊息中取得Email地址
import pyzmail
message = pyzmail.PyzMessage.factory(rawMessages[8755][b"BODY[]"])
print(message.get_subject())
print(message.get_addresses("from"))
print(message.get_addresses("to"))
print(message.get_addresses("cc"))
print(message.get_addresses("bcc"))
# 從原始訊息中取得內文,如果Email是純文字格式,PzyMessage物件會把html_part屬性設成None
print(message.text_part != None)
print(message.text_part.get_payload().decode(message.text_part.charset))
# 從原始訊息中取得內文,如果Email是HTML格式,PzyMessage物件會把text_part屬性設成None
print(message.html_part != None)
print(message.html_part.get_payload().decode(message.html_part.charset))
# 切斷IMAP伺服器連線
imapObj.logout()
# 連接到IMAP伺服器,第一個引數是IMAP伺服器網域名稱,第二個引數是SSL加密
imapObj = imapclient.IMAPClient("imap.mail.yahoo.com", ssl = True)
# 登入IMAP伺服器
# 若是使用Gmail,Gmail對Google帳號提供一個附加的安全功能稱之為應用程式密碼(Application-Specific Passwords)
imapObj.login("myAccount@yahoo.com.tw", "myPassword")
pprint.pprint(imapObj.list_folders())
# 選取資料夾,readonly = True以唯讀防止任何更動Email資料夾的動作
imapObj.select_folder("Inbox", readonly = True)
# 執行尋找,字串串列為IMAP搜尋鍵(Search Key),參考下列說明
# 若是使用Gmail,可使用Gmail網頁上方的搜尋列:UIDs = imapObj.gmail_search("Test")
UIDs = imapObj.search(["SINCE", "21-Jun-2017", "BEFORE", "21-Jun-2018"])
pprint.pprint(UIDs)
# 收取Email,第一個引數是UID串列,第二個引數是所有內文
rawMessages = imapObj.fetch([8755], [b"BODY[]"])
# 從原始訊息中取得Email地址
import pyzmail
message = pyzmail.PyzMessage.factory(rawMessages[8755][b"BODY[]"])
print(message.get_subject())
print(message.get_addresses("from"))
print(message.get_addresses("to"))
print(message.get_addresses("cc"))
print(message.get_addresses("bcc"))
# 從原始訊息中取得內文,如果Email是純文字格式,PzyMessage物件會把html_part屬性設成None
print(message.text_part != None)
print(message.text_part.get_payload().decode(message.text_part.charset))
# 從原始訊息中取得內文,如果Email是HTML格式,PzyMessage物件會把text_part屬性設成None
print(message.html_part != None)
print(message.html_part.get_payload().decode(message.html_part.charset))
# 切斷IMAP伺服器連線
imapObj.logout()
l 搜尋鍵(Search Key):
返回此資料夾中所有郵件:
["ALL"]
返回給予的日期之前、當天、之後所接收的郵件:
["BEFORE", "21-Jun-2018"]、["ON", "21-Jun-2018"]、["SINCE", "21-Jun-2018"]
返回給予的字串出現在主旨、內文、兩者之中的郵件:
["SUBJECT", "String"]、["BODY", "String"]、["TEXT", "String"]
返回給予的字串出現在郵件地址之中的郵件:
["FROM", "String"]、["TO", "String"]、["CC", "String"]、["BCC", "String"]
返回已讀或未讀的所有郵件:
["SEEN"]、["UNSEEN"]
返回已回覆或未回覆的所有郵件:
["ANSWERED"]、["UNANSWERED"]
返回已刪除或未刪除的所有郵件:
["DELETED"]、["UNDELETED"]
返回草稿或非草稿的所有郵件:
["DRAFT"]、["UNDRAFT"]
返回緊急或不緊急的所有郵件:
["FLAGGED"]、["UNFLAGGED"]
返回大於或小於n個位元組的所有郵件:
["LARGER", "n"]、["SMALLER", "n"]
返回不含給予字串的所有郵件:
["NOT", ["SUBJECT", "String"]]
返回含有第一個或第二個給予字串的所有郵件:
["OR", ["SUBJECT", "String"], ["BODY", "String"]]
返回此資料夾中所有郵件:
["ALL"]
返回給予的日期之前、當天、之後所接收的郵件:
["BEFORE", "21-Jun-2018"]、["ON", "21-Jun-2018"]、["SINCE", "21-Jun-2018"]
返回給予的字串出現在主旨、內文、兩者之中的郵件:
["SUBJECT", "String"]、["BODY", "String"]、["TEXT", "String"]
返回給予的字串出現在郵件地址之中的郵件:
["FROM", "String"]、["TO", "String"]、["CC", "String"]、["BCC", "String"]
返回已讀或未讀的所有郵件:
["SEEN"]、["UNSEEN"]
返回已回覆或未回覆的所有郵件:
["ANSWERED"]、["UNANSWERED"]
返回已刪除或未刪除的所有郵件:
["DELETED"]、["UNDELETED"]
返回草稿或非草稿的所有郵件:
["DRAFT"]、["UNDRAFT"]
返回緊急或不緊急的所有郵件:
["FLAGGED"]、["UNFLAGGED"]
返回大於或小於n個位元組的所有郵件:
["LARGER", "n"]、["SMALLER", "n"]
返回不含給予字串的所有郵件:
["NOT", ["SUBJECT", "String"]]
返回含有第一個或第二個給予字串的所有郵件:
["OR", ["SUBJECT", "String"], ["BODY", "String"]]
l 更改大小限制:
搜尋比對找出大量郵件有大小限制,更改限制從預設10000bytes改成10000000bytes:
import imaplib
imaplib._MAXLINE = 10000000
搜尋比對找出大量郵件有大小限制,更改限制從預設10000bytes改成10000000bytes:
import imaplib
imaplib._MAXLINE = 10000000
l 刪除電子郵件:
import imapclient
imapObj = imapclient.IMAPClient("imap.mail.yahoo.com", ssl = True)
imapObj.login("myAccount@yahoo.com.tw", "myPassword")
imapObj.select_folder("Inbox", readonly = False)
UIDs = imapObj.search(["SINCE", "21-Jun-2017"])
# 永久刪除,少數如Gmail呼叫.delete_message()就已永久刪除
imapObj.delete_messages(UIDs)
imapObj.expunge()
imapObj.logout()
import imapclient
imapObj = imapclient.IMAPClient("imap.mail.yahoo.com", ssl = True)
imapObj.login("myAccount@yahoo.com.tw", "myPassword")
imapObj.select_folder("Inbox", readonly = False)
UIDs = imapObj.search(["SINCE", "21-Jun-2017"])
# 永久刪除,少數如Gmail呼叫.delete_message()就已永久刪除
imapObj.delete_messages(UIDs)
imapObj.expunge()
imapObj.logout()
使用Twilio傳送簡訊
l 未註冊使用Twilio,故略。
七、處理影像圖片
影像圖片的基礎
l 在命令提示字元輸入pip install pillow,下載並安裝Pillow模組。
l RGBA值:
RGBA值是0至255的整數,以(0, 0, 0, 0)符號來指定,代表(R紅, G綠, B藍, Alpha透明度):
from PIL import ImageColor
# 色彩名稱不分大小寫
print(ImageColor.getcolor("red", "RGBA")) à (255, 0, 0, 255)
print(ImageColor.getcolor("RED", "RGBA")) à (255, 0, 0, 255)
print(ImageColor.getcolor("Black", "RGBA")) à (0, 0, 0, 255)
print(ImageColor.getcolor("CornflowerBlue", "RGBA")) à (100, 149, 237, 255)
RGBA值是0至255的整數,以(0, 0, 0, 0)符號來指定,代表(R紅, G綠, B藍, Alpha透明度):
from PIL import ImageColor
# 色彩名稱不分大小寫
print(ImageColor.getcolor("red", "RGBA")) à (255, 0, 0, 255)
print(ImageColor.getcolor("RED", "RGBA")) à (255, 0, 0, 255)
print(ImageColor.getcolor("Black", "RGBA")) à (0, 0, 0, 255)
print(ImageColor.getcolor("CornflowerBlue", "RGBA")) à (100, 149, 237, 255)
l 座標、方框多元組(Box Tuple)與資料型別:
原點(Origin)是影像左上角的像素,以(0, 0)符號來指定,代表(寬, 高),方框的座標是以左和上座標為起始,但右下角座標則超出右和下座標(本章節,本書範例檔zophie.png皆在目前工作目錄):
from PIL import Image
a = Image.open("zophie.png")
print(a.size) à (816, 1088)
print(a.filename) à zophie.png
print(a.format) à PNG
print(a.format_description) à Portable network graphics
a.save("zophie.jpg")
原點(Origin)是影像左上角的像素,以(0, 0)符號來指定,代表(寬, 高),方框的座標是以左和上座標為起始,但右下角座標則超出右和下座標(本章節,本書範例檔zophie.png皆在目前工作目錄):
from PIL import Image
a = Image.open("zophie.png")
print(a.size) à (816, 1088)
print(a.filename) à zophie.png
print(a.format) à PNG
print(a.format_description) à Portable network graphics
a.save("zophie.jpg")
l 使用.getpixel()顯示影像圖片座標的RGBA值:
from PIL import Image
a = Image.open("zophie.png")
print(a.getpixel((408, 544))) à (99, 72, 55)
from PIL import Image
a = Image.open("zophie.png")
print(a.getpixel((408, 544))) à (99, 72, 55)
影像圖片的處理
l 使用Image.new()新增影像圖片:
from PIL import Image
a = Image.new("RGBA", (100, 200), "CornflowerBlue")
a.save("cornflowerBlueImage.png")
b = Image.new("RGBA", (100, 200), (210, 105, 30, 255))
b.save("chocolateImage.png")
# 若無傳入第三引數背景色彩,預設為(0, 0, 0, 0)
c = Image.new("RGBA", (100, 100))
c.save("transparentImage.png")
from PIL import Image
a = Image.new("RGBA", (100, 200), "CornflowerBlue")
a.save("cornflowerBlueImage.png")
b = Image.new("RGBA", (100, 200), (210, 105, 30, 255))
b.save("chocolateImage.png")
# 若無傳入第三引數背景色彩,預設為(0, 0, 0, 0)
c = Image.new("RGBA", (100, 100))
c.save("transparentImage.png")
l 使用.crop()裁切影像圖片、使用.copy()複製影像圖片、使用.paste()貼上影像圖片:
from PIL import Image
a = Image.open("zophie.png")
b = a.crop((335, 345, 565, 560))
aWidth, aHeight = a.size
bWidth, bHeight = b.size
c = a.copy()
for left in range(0, aWidth, bWidth):
for top in range(0, aHeight, bHeight):
# 貼上的是透明背景圖片,須新增第三引數c.paste(b, (left, top), b)
c.paste(b, (left, top))
c.save("tiledImage.png")
from PIL import Image
a = Image.open("zophie.png")
b = a.crop((335, 345, 565, 560))
aWidth, aHeight = a.size
bWidth, bHeight = b.size
c = a.copy()
for left in range(0, aWidth, bWidth):
for top in range(0, aHeight, bHeight):
# 貼上的是透明背景圖片,須新增第三引數c.paste(b, (left, top), b)
c.paste(b, (left, top))
c.save("tiledImage.png")
l 使用.resize()縮放影像圖片:
from PIL import Image
a = Image.open("zophie.png")
aWidth, aHeight = a.size
b = a.resize((int(aWidth / 2), int(aHeight / 2)))
b.save("quartersizedImage.png")
from PIL import Image
a = Image.open("zophie.png")
aWidth, aHeight = a.size
b = a.resize((int(aWidth / 2), int(aHeight / 2)))
b.save("quartersizedImage.png")
l 使用.rotate()逆時針旋轉影像圖片:
from PIL import Image
a = Image.open("zophie.png")
a.rotate(90).save("rotated90Image.png")
a.rotate(350).save("rotated350Image.png")
# expand = True會放大整個影像圖的版面尺度
a.rotate(350, expand = True).save("rotated350Image_expanded.png")
from PIL import Image
a = Image.open("zophie.png")
a.rotate(90).save("rotated90Image.png")
a.rotate(350).save("rotated350Image.png")
# expand = True會放大整個影像圖的版面尺度
a.rotate(350, expand = True).save("rotated350Image_expanded.png")
l 使用.transpose()翻轉影像圖片:
from PIL import Image
a = Image.open("zophie.png")
a.transpose(Image.FLIP_LEFT_RIGHT).save("horizontalFlipImage.png")
a.transpose(Image.FLIP_TOP_BOTTOM).save("verticalFlipImage.png")
from PIL import Image
a = Image.open("zophie.png")
a.transpose(Image.FLIP_LEFT_RIGHT).save("horizontalFlipImage.png")
a.transpose(Image.FLIP_TOP_BOTTOM).save("verticalFlipImage.png")
l 使用.putpixel()修改單個像素:
from PIL import Image, ImageColor
a = Image.new("RGBA", (200, 200))
for x in range(200):
for y in range(100):
a.putpixel((x, y), (210, 210, 210))
for x in range(200):
for y in range(100, 200):
a.putpixel((x, y), ImageColor.getcolor("darkgray", "RGBA"))
a.save("putPixelImage.png")
from PIL import Image, ImageColor
a = Image.new("RGBA", (200, 200))
for x in range(200):
for y in range(100):
a.putpixel((x, y), (210, 210, 210))
for x in range(200):
for y in range(100, 200):
a.putpixel((x, y), ImageColor.getcolor("darkgray", "RGBA"))
a.save("putPixelImage.png")
影像圖片的繪製
l 以下圖形繪製,fill和outline引數是選擇性的,若沒有指定,預設白色。
l 點(Point):
from PIL import Image, ImageDraw
a = Image.new("RGBA", (200, 200), "White")
# .point(xy, fill),如.point([60, 80, 120, 140], (100, 149, 237, 255))
ImageDraw.Draw(a).point([(60, 80), (120, 140)], "CornflowerBlue")
a.save("pointImage.png")
from PIL import Image, ImageDraw
a = Image.new("RGBA", (200, 200), "White")
# .point(xy, fill),如.point([60, 80, 120, 140], (100, 149, 237, 255))
ImageDraw.Draw(a).point([(60, 80), (120, 140)], "CornflowerBlue")
a.save("pointImage.png")
l 線(Line):
from PIL import Image, ImageDraw
a = Image.new("RGBA", (200, 200), "White")
# .line(xy, fill, width),如.line([60, 80, 120, 140], (100, 149, 237, 255), 5)
ImageDraw.Draw(a).line([(60, 80), (120, 140)], "CornflowerBlue", 5)
a.save("lineImage.png")
from PIL import Image, ImageDraw
a = Image.new("RGBA", (200, 200), "White")
# .line(xy, fill, width),如.line([60, 80, 120, 140], (100, 149, 237, 255), 5)
ImageDraw.Draw(a).line([(60, 80), (120, 140)], "CornflowerBlue", 5)
a.save("lineImage.png")
l 矩形(Rectangle):
from PIL import Image, ImageDraw
a = Image.new("RGBA", (200, 200), "White")
# .rectangle(xy, fill, outline),如.rectangle([60, 80, 120, 140], (100, 149, 237, 255), (0, 0, 0, 255))
ImageDraw.Draw(a).rectangle([(60, 80), (120, 140)], "CornflowerBlue", "Black")
a.save("rectangleImage.png")
from PIL import Image, ImageDraw
a = Image.new("RGBA", (200, 200), "White")
# .rectangle(xy, fill, outline),如.rectangle([60, 80, 120, 140], (100, 149, 237, 255), (0, 0, 0, 255))
ImageDraw.Draw(a).rectangle([(60, 80), (120, 140)], "CornflowerBlue", "Black")
a.save("rectangleImage.png")
l 橢圓(Ellipse):
from PIL import Image, ImageDraw
a = Image.new("RGBA", (200, 200), "White")
# .ellipse(xy, fill, outline),如.ellipse([60, 80, 120, 140], (100, 149, 237, 255), (0, 0, 0, 255))
ImageDraw.Draw(a).ellipse([(60, 80), (120, 140)], "CornflowerBlue", "Black")
a.save("ellipseImage.png")
from PIL import Image, ImageDraw
a = Image.new("RGBA", (200, 200), "White")
# .ellipse(xy, fill, outline),如.ellipse([60, 80, 120, 140], (100, 149, 237, 255), (0, 0, 0, 255))
ImageDraw.Draw(a).ellipse([(60, 80), (120, 140)], "CornflowerBlue", "Black")
a.save("ellipseImage.png")
l 多邊形(Polygon):
from PIL import Image, ImageDraw
a = Image.new("RGBA", (200, 200), "White")
# .polygon(xy, fill, outline),如.polygon([60, 80, 90, 100, 120, 80, 120, 140, 90, 120, 60, 140], (100, 149, 237, 255), (0, 0, 0, 255))
ImageDraw.Draw(a).polygon([(60, 80), (90, 100), (120, 80), (120, 140), (90, 120), (60, 140)], "CornflowerBlue", "Black")
a.save("polygonImage.png")
from PIL import Image, ImageDraw
a = Image.new("RGBA", (200, 200), "White")
# .polygon(xy, fill, outline),如.polygon([60, 80, 90, 100, 120, 80, 120, 140, 90, 120, 60, 140], (100, 149, 237, 255), (0, 0, 0, 255))
ImageDraw.Draw(a).polygon([(60, 80), (90, 100), (120, 80), (120, 140), (90, 120), (60, 140)], "CornflowerBlue", "Black")
a.save("polygonImage.png")
l 繪製文字:
from PIL import Image, ImageDraw, ImageFont
import os
a = Image.new("RGBA", (200, 200), "white")
# .text(xy, text, fill, font)
ImageDraw.Draw(a).text((60, 80), "Hello", fill = "Purple")
# ImageFont.truetype(代表字型TrueType檔的字串, 字型大小點數)
arialFont = ImageFont.truetype(os.path.join("FONT_FOLDER", "arial.ttf"), 32)
ImageDraw.Draw(a).text((120, 140), "World", fill = "Gray", font = arialFont)
# .textsize(text, font)返回文字的寬度與高度,做為繪製文字時的參考
print(ImageDraw.Draw(a).textsize("Poor", arialFont)) à (69, 29)
a.save("textImage.png")
from PIL import Image, ImageDraw, ImageFont
import os
a = Image.new("RGBA", (200, 200), "white")
# .text(xy, text, fill, font)
ImageDraw.Draw(a).text((60, 80), "Hello", fill = "Purple")
# ImageFont.truetype(代表字型TrueType檔的字串, 字型大小點數)
arialFont = ImageFont.truetype(os.path.join("FONT_FOLDER", "arial.ttf"), 32)
ImageDraw.Draw(a).text((120, 140), "World", fill = "Gray", font = arialFont)
# .textsize(text, font)返回文字的寬度與高度,做為繪製文字時的參考
print(ImageDraw.Draw(a).textsize("Poor", arialFont)) à (69, 29)
a.save("textImage.png")
八、以GUI自動化來控制鍵盤和滑鼠
關於GUI自動化
l 在命令提示字元輸入pip install pyautogui,下載並安裝PyAutoGUI模組。
l 暫停與失效安全防護(Fail-Safe):
import pyautogui
# 暫停1.5秒
pyautogui.PAUSE = 1.5
# 失效安全防護,把滑鼠游標移到畫面左上角,這會引起pyautogui產生pyautogui.FailSageException例外異常
pyautogui.FAILSAFE = True
import pyautogui
# 暫停1.5秒
pyautogui.PAUSE = 1.5
# 失效安全防護,把滑鼠游標移到畫面左上角,這會引起pyautogui產生pyautogui.FailSageException例外異常
pyautogui.FAILSAFE = True
l 螢幕的解析度:
import pyautogui
# 如果螢幕的解析度設為1920*1080,則左上角的座標為(0, 0),右下角的座標為(1919, 1079)
print(pyautogui.size()) à (1920, 1080)
import pyautogui
# 如果螢幕的解析度設為1920*1080,則左上角的座標為(0, 0),右下角的座標為(1919, 1079)
print(pyautogui.size()) à (1920, 1080)
滑鼠
l 取得滑鼠游標位置:
import pyautogui
print(pyautogui.position())
import pyautogui
print(pyautogui.position())
l 絕對位置移動滑鼠游標:
import pyautogui
for i in range(5):
pyautogui.moveTo(100, 100, duration = 0.5)
pyautogui.moveTo(200, 100, duration = 0.5)
pyautogui.moveTo(200, 200, duration = 0.5)
pyautogui.moveTo(100, 200, duration = 0.5)
import pyautogui
for i in range(5):
pyautogui.moveTo(100, 100, duration = 0.5)
pyautogui.moveTo(200, 100, duration = 0.5)
pyautogui.moveTo(200, 200, duration = 0.5)
pyautogui.moveTo(100, 200, duration = 0.5)
l 相對位置移動滑鼠游標:
import pyautogui
for i in range(5):
pyautogui.moveRel(100, 0, duration = 0.5)
pyautogui.moveRel(0, 100, duration = 0.5)
pyautogui.moveRel(-100, 0, duration = 0.5)
pyautogui.moveRel(0, -100, duration = 0.5)
import pyautogui
for i in range(5):
pyautogui.moveRel(100, 0, duration = 0.5)
pyautogui.moveRel(0, 100, duration = 0.5)
pyautogui.moveRel(-100, 0, duration = 0.5)
pyautogui.moveRel(0, -100, duration = 0.5)
l 絕對位置拖曳滑鼠游標:
import time, pyautogui
# 可在5秒內移至小畫家畫面
time.sleep(5)
distance = 400
while distance > 200:
pyautogui.dragTo(distance, distance, duration = 0.2)
distance -= 10
pyautogui.dragTo(distance * 2, distance, duration = 0.2)
pyautogui.dragTo(distance * 2, distance * 2, duration = 0.2)
distance -= 10
pyautogui.dragTo(distance, distance * 2, duration = 0.2)
import time, pyautogui
# 可在5秒內移至小畫家畫面
time.sleep(5)
distance = 400
while distance > 200:
pyautogui.dragTo(distance, distance, duration = 0.2)
distance -= 10
pyautogui.dragTo(distance * 2, distance, duration = 0.2)
pyautogui.dragTo(distance * 2, distance * 2, duration = 0.2)
distance -= 10
pyautogui.dragTo(distance, distance * 2, duration = 0.2)
l 相對位置拖曳滑鼠游標:
import time, pyautogui
# 可在5秒內移至小畫家畫面
time.sleep(5)
distance = 200
while distance > 0:
pyautogui.dragRel(distance, 0, duration = 0.2)
distance -= 5
pyautogui.dragRel(0, distance, duration = 0.2)
pyautogui.dragRel(-distance, 0, duration = 0.2)
distance -= 5
pyautogui.dragRel(0, -distance, duration = 0.2)
import time, pyautogui
# 可在5秒內移至小畫家畫面
time.sleep(5)
distance = 200
while distance > 0:
pyautogui.dragRel(distance, 0, duration = 0.2)
distance -= 5
pyautogui.dragRel(0, distance, duration = 0.2)
pyautogui.dragRel(-distance, 0, duration = 0.2)
distance -= 5
pyautogui.dragRel(0, -distance, duration = 0.2)
l 按一下滑鼠:
pyautogui.click()功能已整合pyautogui.mouseDown()按下滑鼠按鍵與pyautogui.mouseUp()放開滑鼠按鍵。
pyautogui.click(x, y, button = "left或middle或right")已整合pyautogui.rightClick()按下滑鼠右鍵與pyautogui.middleClick()按下滑鼠中間鍵。
import pyautogui
pyautogui.click()
pyautogui.click(100, 150, button = "left")
pyautogui.click()功能已整合pyautogui.mouseDown()按下滑鼠按鍵與pyautogui.mouseUp()放開滑鼠按鍵。
pyautogui.click(x, y, button = "left或middle或right")已整合pyautogui.rightClick()按下滑鼠右鍵與pyautogui.middleClick()按下滑鼠中間鍵。
import pyautogui
pyautogui.click()
pyautogui.click(100, 150, button = "left")
l 按二下滑鼠:
import pyautogui
pyautogui.doubleClick()
pyautogui.doubleClick(100, 150, button = "left")
import pyautogui
pyautogui.doubleClick()
pyautogui.doubleClick(100, 150, button = "left")
l 捲動滑鼠:
import time, pyautogui
# 可在5秒內移至有捲軸的瀏覽器畫面
time.sleep(5)
pyautogui.scroll(100)
import time, pyautogui
# 可在5秒內移至有捲軸的瀏覽器畫面
time.sleep(5)
pyautogui.scroll(100)
螢幕
l 比對目前螢幕畫面與螢幕截圖,特定座標像素色彩是否相同:
import pyautogui
# 若需要將螢幕截圖存檔,再加入"screenshotImage.png"
a = pyautogui.screenshot("screenshotImage.png")
print(pyautogui.pixelMatchesColor(50, 200, a.getpixel((50, 200))))
import pyautogui
# 若需要將螢幕截圖存檔,再加入"screenshotImage.png"
a = pyautogui.screenshot("screenshotImage.png")
print(pyautogui.pixelMatchesColor(50, 200, a.getpixel((50, 200))))
l 比對目前螢幕畫面與影像圖片,若相同,返回螢幕畫面4點座標:
import pyautogui
# 返回找到的1個螢幕畫面4點座標
print(pyautogui.locateOnScreen("object.png"))
# 返回找到的全部螢幕畫面4點座標
print(list(pyautogui.locateAllOnScreen("object.png")))
import pyautogui
# 返回找到的1個螢幕畫面4點座標
print(pyautogui.locateOnScreen("object.png"))
# 返回找到的全部螢幕畫面4點座標
print(list(pyautogui.locateAllOnScreen("object.png")))
l 返回螢幕畫面4點座標的中心座標,並點按該中心座標:
import pyautogui
a = pyautogui.locateOnScreen("object.png")
b = pyautogui.center(a)
pyautogui.click(b)
import pyautogui
a = pyautogui.locateOnScreen("object.png")
b = pyautogui.center(a)
pyautogui.click(b)
鍵盤
l 從鍵盤傳送字串:
import pyautogui
pyautogui.click()
pyautogui.typewrite("Hello World\n")
pyautogui.typewrite("Hello Poor World", 0.1)
import pyautogui
pyautogui.click()
pyautogui.typewrite("Hello World\n")
pyautogui.typewrite("Hello Poor World", 0.1)
l 從鍵盤按下按鍵:
import pyautogui
# 查閱按鍵
print(pyautogui.KEYBOARD_KEYS)
pyautogui.click()
pyautogui.typewrite(["o", "r", "left", "left", "P", "o"], 0.1)
import pyautogui
# 查閱按鍵
print(pyautogui.KEYBOARD_KEYS)
pyautogui.click()
pyautogui.typewrite(["o", "r", "left", "left", "P", "o"], 0.1)
l 按下和放開鍵盤按鍵:
pyautogui.press()功能已整合pyautogui.keyDown()按下鍵盤按鍵與pyautogui.keyUp()放開鍵盤按鍵。
import pyautogui
pyautogui.click()
pyautogui.keyDown("shift")
pyautogui.press("4")
pyautogui.keyUp("shift")
pyautogui.press()功能已整合pyautogui.keyDown()按下鍵盤按鍵與pyautogui.keyUp()放開鍵盤按鍵。
import pyautogui
pyautogui.click()
pyautogui.keyDown("shift")
pyautogui.press("4")
pyautogui.keyUp("shift")
l 按下和放開鍵盤按鍵-快速鍵(Hotkey)、快捷鍵(Shortcut)組合:
import pyautogui, time
pyautogui.click()
pyautogui.typewrite("In IDLE, Alt-3 comments out a line.")
time.sleep(2)
pyautogui.hotkey("alt", "3")
import pyautogui, time
pyautogui.click()
pyautogui.typewrite("In IDLE, Alt-3 comments out a line.")
time.sleep(2)
pyautogui.hotkey("alt", "3")
九、Python自動化的樂趣-第11章至第18章-實作專題參考程式碼
第11章-實作專題參考程式碼
l 命令提示行郵件處理程式:
#! python3
import sys, time
from selenium import webdriver
if len(sys.argv) == 3:
chromedriverPath = r"C:\Users\Timmy\Documents\Python\chromedriver.exe"
driver = webdriver.Chrome(chromedriverPath)
driver.get("https://webmail.ntnu.edu.tw/v2/")
userElement = driver.find_element_by_name("user")
userElement.send_keys("myAccount")
pswdElement = driver.find_element_by_name("pswd")
pswdElement.send_keys("myPassword")
lnbnElement = driver.find_element_by_name("loginbutton")
lnbnElement.click()
time.sleep(5)
compElement = driver.find_element_by_tag_name("a")
compElement.click()
time.sleep(5)
subjElement = driver.find_element_by_name("subject")
subjElement.send_keys(sys.argv[2])
emaiElement = driver.find_element_by_name("to")
emaiElement.send_keys(sys.argv[1])
sdbnElement = driver.find_element_by_name("sendbutton")
sdbnElement.click()
else:
print("pythonScript emailAddress subject")
#! python3
import sys, time
from selenium import webdriver
if len(sys.argv) == 3:
chromedriverPath = r"C:\Users\Timmy\Documents\Python\chromedriver.exe"
driver = webdriver.Chrome(chromedriverPath)
driver.get("https://webmail.ntnu.edu.tw/v2/")
userElement = driver.find_element_by_name("user")
userElement.send_keys("myAccount")
pswdElement = driver.find_element_by_name("pswd")
pswdElement.send_keys("myPassword")
lnbnElement = driver.find_element_by_name("loginbutton")
lnbnElement.click()
time.sleep(5)
compElement = driver.find_element_by_tag_name("a")
compElement.click()
time.sleep(5)
subjElement = driver.find_element_by_name("subject")
subjElement.send_keys(sys.argv[2])
emaiElement = driver.find_element_by_name("to")
emaiElement.send_keys(sys.argv[1])
sdbnElement = driver.find_element_by_name("sendbutton")
sdbnElement.click()
else:
print("pythonScript emailAddress subject")
l 照片影像網站的下載:
import os, requests, bs4
url = https://bulbapedia.bulbagarden.net/wiki/Bulbasaur_(Pok%C3%A9mon)
os.makedirs("pokemon", exist_ok = True)
for pokedex in range(807):
print("Downloading page %s..."%url)
aRes = requests.get(url)
aRes.raise_for_status()
aBeaSou = bs4.BeautifulSoup(aRes.text, "html.parser")
aTagLis = aBeaSou.select("a.image img")
picUrl = ("https:" + aTagLis[0].get("src"))
print("Downloading image %s..."%(picUrl))
bRes = requests.get(picUrl)
bRes.raise_for_status()
imageFile = open(os.path.join("pokemon",os.path.basename(picUrl)), "wb")
for chunk in bRes.iter_content(100000):
imageFile.write(chunk)
imageFile.close()
bTagLis = aBeaSou.select("td[style='text-align: left'] a")
url = "https://bulbapedia.bulbagarden.net" + bTagLis[0].get("href")
print("Done.")
import os, requests, bs4
url = https://bulbapedia.bulbagarden.net/wiki/Bulbasaur_(Pok%C3%A9mon)
os.makedirs("pokemon", exist_ok = True)
for pokedex in range(807):
print("Downloading page %s..."%url)
aRes = requests.get(url)
aRes.raise_for_status()
aBeaSou = bs4.BeautifulSoup(aRes.text, "html.parser")
aTagLis = aBeaSou.select("a.image img")
picUrl = ("https:" + aTagLis[0].get("src"))
print("Downloading image %s..."%(picUrl))
bRes = requests.get(picUrl)
bRes.raise_for_status()
imageFile = open(os.path.join("pokemon",os.path.basename(picUrl)), "wb")
for chunk in bRes.iter_content(100000):
imageFile.write(chunk)
imageFile.close()
bTagLis = aBeaSou.select("td[style='text-align: left'] a")
url = "https://bulbapedia.bulbagarden.net" + bTagLis[0].get("href")
print("Done.")
l 2048:
import random
from selenium import webdriver
from selenium.webdriver.common.keys import Keys
chromedriverPath = r"C:\Users\Timmy\Documents\Python\chromedriver.exe"
driver = webdriver.Chrome(chromedriverPath)
driver.get("https://gabrielecirulli.github.io/2048/")
htmlElement = driver.find_element_by_tag_name("html")
arrows = [Keys.UP, Keys.DOWN, Keys.LEFT, Keys.RIGHT]
lowerElement = driver.find_element_by_css_selector("div.lower")
while not lowerElement.is_displayed():
htmlElement.send_keys(random.sample(arrows, 1))
print("Game over! or You win!")
import random
from selenium import webdriver
from selenium.webdriver.common.keys import Keys
chromedriverPath = r"C:\Users\Timmy\Documents\Python\chromedriver.exe"
driver = webdriver.Chrome(chromedriverPath)
driver.get("https://gabrielecirulli.github.io/2048/")
htmlElement = driver.find_element_by_tag_name("html")
arrows = [Keys.UP, Keys.DOWN, Keys.LEFT, Keys.RIGHT]
lowerElement = driver.find_element_by_css_selector("div.lower")
while not lowerElement.is_displayed():
htmlElement.send_keys(random.sample(arrows, 1))
print("Game over! or You win!")
l 連結驗證:
import requests, bs4, webbrowser
aRes = requests.get("https://simp.stpi.narl.org.tw/")
aRes.raise_for_status()
aBeaSou = bs4.BeautifulSoup(aRes.text, "html.parser")
aTagLis = aBeaSou.select("a[href]")
for i in aTagLis:
url = i.get("href")
print(url)
try:
bRes = requests.get(url)
bRes.raise_for_status()
print("Open Web Browser\n")
webbrowser.open(url)
except Exception as error:
print(str(error) + "\n")
import requests, bs4, webbrowser
aRes = requests.get("https://simp.stpi.narl.org.tw/")
aRes.raise_for_status()
aBeaSou = bs4.BeautifulSoup(aRes.text, "html.parser")
aTagLis = aBeaSou.select("a[href]")
for i in aTagLis:
url = i.get("href")
print(url)
try:
bRes = requests.get(url)
bRes.raise_for_status()
print("Open Web Browser\n")
webbrowser.open(url)
except Exception as error:
print(str(error) + "\n")
第12章-實作專題參考程式碼
l 乘法表:
#! python3
import openpyxl, sys
from openpyxl.styles import Font
from openpyxl.utils import get_column_letter, column_index_from_string
aBook = openpyxl.Workbook()
aSheet = aBook.active
n = int(sys.argv[1])
for i in range(1, n + 1):
aSheet["A" + str(i + 1)] = i
aSheet["A" + str(i + 1)].font = Font(bold = True)
aSheet[get_column_letter(i + 1) + str(1)] = i
aSheet[get_column_letter(i + 1) + str(1)].font = Font(bold = True)
for j in range(1, n + 1):
for k in range(1, n + 1):
aSheet[get_column_letter(k + 1) + str(j + 1)] = "=A" + str(j + 1) + "*" + get_column_letter(k + 1) + "1"
aBook.save("multiplicationTable.xlsx")
#! python3
import openpyxl, sys
from openpyxl.styles import Font
from openpyxl.utils import get_column_letter, column_index_from_string
aBook = openpyxl.Workbook()
aSheet = aBook.active
n = int(sys.argv[1])
for i in range(1, n + 1):
aSheet["A" + str(i + 1)] = i
aSheet["A" + str(i + 1)].font = Font(bold = True)
aSheet[get_column_letter(i + 1) + str(1)] = i
aSheet[get_column_letter(i + 1) + str(1)].font = Font(bold = True)
for j in range(1, n + 1):
for k in range(1, n + 1):
aSheet[get_column_letter(k + 1) + str(j + 1)] = "=A" + str(j + 1) + "*" + get_column_letter(k + 1) + "1"
aBook.save("multiplicationTable.xlsx")
l 插入空白列的程式:
#! python3
import openpyxl, sys
from openpyxl.utils import get_column_letter, column_index_from_string
# 本書範例檔example.xlsx在目前工作目錄
aBook = openpyxl.load_workbook("example.xlsx")
aSheet = aBook["Sheet1"]
bSheet = aBook["Sheet2"]
n = int(sys.argv[1])
m = int(sys.argv[2])
for g in range(1, n):
for h in range(1, aSheet.max_column + 1):
bSheet[get_column_letter(h) + str(g)] = aSheet[get_column_letter(h) + str(g)].value
for i in range(n, aSheet.max_row + 1):
for j in range(1, aSheet.max_column + 1):
bSheet[get_column_letter(j) + str(i + m)] = aSheet[get_column_letter(j) + str(i)].value
aBook.save("blankRowInserter.xlsx")
#! python3
import openpyxl, sys
from openpyxl.utils import get_column_letter, column_index_from_string
# 本書範例檔example.xlsx在目前工作目錄
aBook = openpyxl.load_workbook("example.xlsx")
aSheet = aBook["Sheet1"]
bSheet = aBook["Sheet2"]
n = int(sys.argv[1])
m = int(sys.argv[2])
for g in range(1, n):
for h in range(1, aSheet.max_column + 1):
bSheet[get_column_letter(h) + str(g)] = aSheet[get_column_letter(h) + str(g)].value
for i in range(n, aSheet.max_row + 1):
for j in range(1, aSheet.max_column + 1):
bSheet[get_column_letter(j) + str(i + m)] = aSheet[get_column_letter(j) + str(i)].value
aBook.save("blankRowInserter.xlsx")
l 試算表的儲存格轉置程式:
import openpyxl
from openpyxl.utils import get_column_letter, column_index_from_string
# 本書範例檔example.xlsx在目前工作目錄
aBook = openpyxl.load_workbook("example.xlsx")
aSheet = aBook["Sheet1"]
bSheet = aBook["Sheet2"]
for i in range(1, aSheet.max_row + 1):
for j in range(1, aSheet.max_column + 1):
bSheet[get_column_letter(i) + str(j)] = aSheet[get_column_letter(j) + str(i)].value
aBook.save("transpose.xlsx")
import openpyxl
from openpyxl.utils import get_column_letter, column_index_from_string
# 本書範例檔example.xlsx在目前工作目錄
aBook = openpyxl.load_workbook("example.xlsx")
aSheet = aBook["Sheet1"]
bSheet = aBook["Sheet2"]
for i in range(1, aSheet.max_row + 1):
for j in range(1, aSheet.max_column + 1):
bSheet[get_column_letter(i) + str(j)] = aSheet[get_column_letter(j) + str(i)].value
aBook.save("transpose.xlsx")
l 將文字檔寫入試算表:
import openpyxl, os
from openpyxl.utils import get_column_letter, column_index_from_string
aBook = openpyxl.Workbook()
aSheet = aBook.active
colNum = 1
for pathName, folderName, fileName in os.walk(r"C:\Users\Timmy\Desktop"):
for aFile in fileName:
if aFile.endswith(".txt"):
txtFile = open(pathName + "\\" + aFile, "r")
lyricsList = txtFile.readlines()
txtFile.close()
rowNum = 1
for i in lyricsList:
aSheet[get_column_letter(colNum) + str(rowNum)] = i
rowNum += 1
colNum += 1
aBook.save("txtFile.xlsx")
import openpyxl, os
from openpyxl.utils import get_column_letter, column_index_from_string
aBook = openpyxl.Workbook()
aSheet = aBook.active
colNum = 1
for pathName, folderName, fileName in os.walk(r"C:\Users\Timmy\Desktop"):
for aFile in fileName:
if aFile.endswith(".txt"):
txtFile = open(pathName + "\\" + aFile, "r")
lyricsList = txtFile.readlines()
txtFile.close()
rowNum = 1
for i in lyricsList:
aSheet[get_column_letter(colNum) + str(rowNum)] = i
rowNum += 1
colNum += 1
aBook.save("txtFile.xlsx")
l 將試算表寫入文字檔:
import openpyxl
from openpyxl.utils import get_column_letter, column_index_from_string
# 本書範例檔example.xlsx在目前工作目錄
aBook = openpyxl.load_workbook("example.xlsx")
aSheet = aBook.active
for i in range(1, aSheet.max_column + 1):
txtFile = open(str(i) + ".txt", "w")
for j in range(1, aSheet.max_row + 1):
txtFile.write(str(aSheet[get_column_letter(i) + str(j)].value) + "\n")
txtFile.close()
import openpyxl
from openpyxl.utils import get_column_letter, column_index_from_string
# 本書範例檔example.xlsx在目前工作目錄
aBook = openpyxl.load_workbook("example.xlsx")
aSheet = aBook.active
for i in range(1, aSheet.max_column + 1):
txtFile = open(str(i) + ".txt", "w")
for j in range(1, aSheet.max_row + 1):
txtFile.write(str(aSheet[get_column_letter(i) + str(j)].value) + "\n")
txtFile.close()
第13章-實作專題參考程式碼
l PDF偏執狂-加密程式:
#! python3
import os, PyPDF2, sys
for pathName, folderName, fileName in os.walk(r"C:\Users\Timmy\Desktop"):
for aFile in fileName:
if aFile.endswith(".pdf"):
aReader = PyPDF2.PdfFileReader(open(pathName + "\\" + aFile, "rb"))
aWriter = PyPDF2.PdfFileWriter()
for i in range(aReader.numPages):
aWriter.addPage(aReader.getPage(i))
aWriter.encrypt(sys.argv[1])
bFile = open(aFile.strip(".pdf") + "_encrypted.pdf", "wb")
aWriter.write(bFile)
bFile.close()
#! python3
import os, PyPDF2, sys
for pathName, folderName, fileName in os.walk(r"C:\Users\Timmy\Desktop"):
for aFile in fileName:
if aFile.endswith(".pdf"):
aReader = PyPDF2.PdfFileReader(open(pathName + "\\" + aFile, "rb"))
aWriter = PyPDF2.PdfFileWriter()
for i in range(aReader.numPages):
aWriter.addPage(aReader.getPage(i))
aWriter.encrypt(sys.argv[1])
bFile = open(aFile.strip(".pdf") + "_encrypted.pdf", "wb")
aWriter.write(bFile)
bFile.close()
l PDF偏執狂-解密程式:
#! python3
import os, PyPDF2, sys
for pathName, folderName, fileName in os.walk(r"C:\Users\Timmy\Desktop"):
for aFile in fileName:
if aFile.endswith(".pdf"):
aReader = PyPDF2.PdfFileReader(open(pathName + "\\" + aFile, "rb"))
if aReader.isEncrypted == True:
try:
if aReader.decrypt(sys.argv[1]) != 1:
raise Exception("Password for " + aFile + " Is Not Correct")
aWriter = PyPDF2.PdfFileWriter()
for i in range(aReader.numPages):
aWriter.addPage(aReader.getPage(i))
bFile = open(aFile.strip(".pdf") + "_decrypted.pdf", "wb")
aWriter.write(bFile)
bFile.close()
except Exception as err:
print("An Error Happened: " + str(err))
#! python3
import os, PyPDF2, sys
for pathName, folderName, fileName in os.walk(r"C:\Users\Timmy\Desktop"):
for aFile in fileName:
if aFile.endswith(".pdf"):
aReader = PyPDF2.PdfFileReader(open(pathName + "\\" + aFile, "rb"))
if aReader.isEncrypted == True:
try:
if aReader.decrypt(sys.argv[1]) != 1:
raise Exception("Password for " + aFile + " Is Not Correct")
aWriter = PyPDF2.PdfFileWriter()
for i in range(aReader.numPages):
aWriter.addPage(aReader.getPage(i))
bFile = open(aFile.strip(".pdf") + "_decrypted.pdf", "wb")
aWriter.write(bFile)
bFile.close()
except Exception as err:
print("An Error Happened: " + str(err))
l 自訂邀請函並儲存成Word檔:
import docx
# 本書範例檔guests.txt在目前工作目錄
aFile = open("guests.txt", "r")
guestsList = aFile.readlines()
aFile.close()
aDocx = docx.Document()
num = 0
for i in guestsList:
aDocx.add_paragraph("It would be a pleasure to have the company of", "Body Text")
aDocx.add_paragraph(i.strip("\n"), "Title")
aDocx.add_paragraph("at 11010 Memory Lane one the Evening of", "Body Text")
aDocx.add_paragraph("April 1st", "Subtitle")
aDocx.add_paragraph("at 7 o'clock", "Intense Quote")
aDocx.paragraphs[4 + 5 * num].runs[0].add_break(docx.enum.text.WD_BREAK.PAGE)
num += 1
aDocx.save("guests.docx")
import docx
# 本書範例檔guests.txt在目前工作目錄
aFile = open("guests.txt", "r")
guestsList = aFile.readlines()
aFile.close()
aDocx = docx.Document()
num = 0
for i in guestsList:
aDocx.add_paragraph("It would be a pleasure to have the company of", "Body Text")
aDocx.add_paragraph(i.strip("\n"), "Title")
aDocx.add_paragraph("at 11010 Memory Lane one the Evening of", "Body Text")
aDocx.add_paragraph("April 1st", "Subtitle")
aDocx.add_paragraph("at 7 o'clock", "Intense Quote")
aDocx.paragraphs[4 + 5 * num].runs[0].add_break(docx.enum.text.WD_BREAK.PAGE)
num += 1
aDocx.save("guests.docx")
l 暴力PDF密碼破解程式:
import PyPDF2
# 本書範例檔dictionary.txt在目前工作目錄
aFile = open("dictionary.txt", "r")
dictionaryList = aFile.readlines()
aFile.close()
# 本書範例檔encrypted.pdf在目前工作目錄
aReader = PyPDF2.PdfFileReader(open("encrypted.pdf", "rb"))
for i in dictionaryList:
upperI = i.strip("\n")
lowerI = upperI.lower()
if aReader.decrypt(upperI) == 1:
print("Password: " + upperI)
break
if aReader.decrypt(lowerI) == 1:
print("Password: " + lowerI)
break
print("Done")
import PyPDF2
# 本書範例檔dictionary.txt在目前工作目錄
aFile = open("dictionary.txt", "r")
dictionaryList = aFile.readlines()
aFile.close()
# 本書範例檔encrypted.pdf在目前工作目錄
aReader = PyPDF2.PdfFileReader(open("encrypted.pdf", "rb"))
for i in dictionaryList:
upperI = i.strip("\n")
lowerI = upperI.lower()
if aReader.decrypt(upperI) == 1:
print("Password: " + upperI)
break
if aReader.decrypt(lowerI) == 1:
print("Password: " + lowerI)
break
print("Done")
第14章-實作專題參考程式碼
l Excel轉CSV的程式:
import os, openpyxl, csv
for excelFile in os.listdir("."):
# Skip non-xlsx files, load the workbook object.
if not excelFile.endswith(".xlsx"):
continue
wb = openpyxl.load_workbook(excelFile)
for sheetName in wb.sheetnames:
# Loop through every sheet in the workbook.
sheet = wb[sheetName]
# Create the CSV filename from the Excel filename and sheet title.
csvFile = open(excelFile.strip(".xlsx") + "_" + sheetName + ".csv", "w", newline = "")
# Create the csv.writer object for this CSV file.
csvWriter = csv.writer(csvFile)
# Loop through every row in the sheet.
for rowNum in range(1, sheet.max_row + 1):
rowData = [] # append each cell to this list
# Loop through each cell in the row.
for colNum in range(1, sheet.max_column + 1):
# Append each cell's data to rowData.
rowData.append(sheet.cell(row = rowNum, column = colNum).value)
# Write the rowData list to the CSV file.
csvWriter.writerow(rowData)
csvFile.close()
import os, openpyxl, csv
for excelFile in os.listdir("."):
# Skip non-xlsx files, load the workbook object.
if not excelFile.endswith(".xlsx"):
continue
wb = openpyxl.load_workbook(excelFile)
for sheetName in wb.sheetnames:
# Loop through every sheet in the workbook.
sheet = wb[sheetName]
# Create the CSV filename from the Excel filename and sheet title.
csvFile = open(excelFile.strip(".xlsx") + "_" + sheetName + ".csv", "w", newline = "")
# Create the csv.writer object for this CSV file.
csvWriter = csv.writer(csvFile)
# Loop through every row in the sheet.
for rowNum in range(1, sheet.max_row + 1):
rowData = [] # append each cell to this list
# Loop through each cell in the row.
for colNum in range(1, sheet.max_column + 1):
# Append each cell's data to rowData.
rowData.append(sheet.cell(row = rowNum, column = colNum).value)
# Write the rowData list to the CSV file.
csvWriter.writerow(rowData)
csvFile.close()
第15章-實作專題參考程式碼
l 修飾美化碼表:
import time, pyperclip
print("Press ENTER to begin. Afterwards, press ENTER to click the stopwatch. Press Ctrl-C to quit.")
lapNum = 1
infoList = []
input()
print("Started.")
startTime = time.time()
lastTime = startTime
try:
while True:
input()
lapTime = round(time.time() - lastTime, 2)
totalTime = round(time.time() - startTime, 2)
infoStr = "Lap # " + str(lapNum).rjust(3) + ": " + str(totalTime).rjust(6) + " (" + str(lapTime).rjust(6) + ")"
print(infoStr, end="")
lastTime = time.time()
lapNum += 1
infoList.append(infoStr)
except KeyboardInterrupt:
info = "\r\n".join(infoList)
pyperclip.copy(info)
print("\nInformation is copied to clipboard.")
import time, pyperclip
print("Press ENTER to begin. Afterwards, press ENTER to click the stopwatch. Press Ctrl-C to quit.")
lapNum = 1
infoList = []
input()
print("Started.")
startTime = time.time()
lastTime = startTime
try:
while True:
input()
lapTime = round(time.time() - lastTime, 2)
totalTime = round(time.time() - startTime, 2)
infoStr = "Lap # " + str(lapNum).rjust(3) + ": " + str(totalTime).rjust(6) + " (" + str(lapTime).rjust(6) + ")"
print(infoStr, end="")
lastTime = time.time()
lapNum += 1
infoList.append(infoStr)
except KeyboardInterrupt:
info = "\r\n".join(infoList)
pyperclip.copy(info)
print("\nInformation is copied to clipboard.")
l Web漫畫圖片的排程下載:
import requests, bs4, os, sys, shutil
url = "https://xkcd.com"
aRes = requests.get(url)
aRes.raise_for_status()
aBeaSou = bs4.BeautifulSoup(aRes.text, "html.parser")
aTag = aBeaSou.select("a[rel='prev']")[0]
num = int(aTag.get("href").strip("/")) + 1
url = url + "/" + str(num) + "/"
while True:
print("Downloading page %s..."%(url))
bRes = requests.get(url)
bRes.raise_for_status()
bBeaSou = bs4.BeautifulSoup(bRes.text, "html.parser")
bTagLis = bBeaSou.select("#comic img")
comicUrl = "http:" + bTagLis[0].get("src")
print("Downloading image %s..."%(comicUrl))
cRes = requests.get(comicUrl)
cRes.raise_for_status()
imageName = str(num) + "_" + os.path.basename(comicUrl)
for iImageFile in os.listdir(r".\xkcd"):
if iImageFile == imageName:
print("The image file already exists.")
sys.exit()
imageFile = open(os.path.join("xkcd", imageName), "wb")
for chunk in cRes.iter_content(1000000):
imageFile.write(chunk)
imageFile.close()
shutil.copy(".\\xkcd\\" + imageName, r"C:\Users\Timmy\Desktop")
prevLink = bBeaSou.select("a[rel='prev']")[0]
url = "https://xkcd.com" + prevLink.get("href")
num = int(prevLink.get("href").strip("/"))
print("Done.")
import requests, bs4, os, sys, shutil
url = "https://xkcd.com"
aRes = requests.get(url)
aRes.raise_for_status()
aBeaSou = bs4.BeautifulSoup(aRes.text, "html.parser")
aTag = aBeaSou.select("a[rel='prev']")[0]
num = int(aTag.get("href").strip("/")) + 1
url = url + "/" + str(num) + "/"
while True:
print("Downloading page %s..."%(url))
bRes = requests.get(url)
bRes.raise_for_status()
bBeaSou = bs4.BeautifulSoup(bRes.text, "html.parser")
bTagLis = bBeaSou.select("#comic img")
comicUrl = "http:" + bTagLis[0].get("src")
print("Downloading image %s..."%(comicUrl))
cRes = requests.get(comicUrl)
cRes.raise_for_status()
imageName = str(num) + "_" + os.path.basename(comicUrl)
for iImageFile in os.listdir(r".\xkcd"):
if iImageFile == imageName:
print("The image file already exists.")
sys.exit()
imageFile = open(os.path.join("xkcd", imageName), "wb")
for chunk in cRes.iter_content(1000000):
imageFile.write(chunk)
imageFile.close()
shutil.copy(".\\xkcd\\" + imageName, r"C:\Users\Timmy\Desktop")
prevLink = bBeaSou.select("a[rel='prev']")[0]
url = "https://xkcd.com" + prevLink.get("href")
num = int(prevLink.get("href").strip("/"))
print("Done.")
第16章-實作專題參考程式碼
l 隨機分配例行工作的Email程式:
import random, smtplib
emails = ["alice@example.com", "bob@example.com", "carol@example.com", "david@example.com"]
chores = ["dishes", "bathroom", "vacuum", "walk dog"]
matches = {}
for i in emails:
randomChore = random.choice(chores)
chores.remove(randomChore)
matches.setdefault(i, randomChore)
smtpObj = smtplib.SMTP_SSL("smtp.ntnu.edu.tw", 465)
smtpObj.ehlo()
smtpObj.login("myAccount@ntnu.edu.tw", "myPassword")
for j, k in matches.items():
smtpObj.sendmail("myAccount@ntnu.edu.tw", j, "Subject: Random Chore\n\nRandom Chore: %s"%k)
smtpObj.quit()
import random, smtplib
emails = ["alice@example.com", "bob@example.com", "carol@example.com", "david@example.com"]
chores = ["dishes", "bathroom", "vacuum", "walk dog"]
matches = {}
for i in emails:
randomChore = random.choice(chores)
chores.remove(randomChore)
matches.setdefault(i, randomChore)
smtpObj = smtplib.SMTP_SSL("smtp.ntnu.edu.tw", 465)
smtpObj.ehlo()
smtpObj.login("myAccount@ntnu.edu.tw", "myPassword")
for j, k in matches.items():
smtpObj.sendmail("myAccount@ntnu.edu.tw", j, "Subject: Random Chore\n\nRandom Chore: %s"%k)
smtpObj.quit()
l 帶傘的提醒程式:
未註冊使用Twilio,故略。
未註冊使用Twilio,故略。
l 自動取消訂閱:
import imapclient, pyzmail, bs4, webbrowser
imapObj = imapclient.IMAPClient("imap.mail.yahoo.com", ssl = True)
imapObj.login("myAccount@yahoo.com.tw", "myPassword")
imapObj.select_folder("Inbox", readonly = True)
UIDs = imapObj.search(["ALL"])
print(UIDs)
for i in UIDs:
print("Search %s..."%i)
rawMessages = imapObj.fetch([i], [b"BODY[]"])
message = pyzmail.PyzMessage.factory(rawMessages[i][b"BODY[]"])
if message.html_part == None:
continue
if message.html_part.charset == None:
continue
aText = message.html_part.get_payload().decode(message.html_part.charset)
aBeaSou = bs4.BeautifulSoup(aText, "html.parser")
# 因沒有取消訂閱的連結,將改為尋找特定格式的連結
aTagLis = aBeaSou.select("span a")
if len(aTagLis) >= 1:
for j in range(len(aTagLis)):
webbrowser.open(aTagLis[j].get("href"))
imapObj.logout()
import imapclient, pyzmail, bs4, webbrowser
imapObj = imapclient.IMAPClient("imap.mail.yahoo.com", ssl = True)
imapObj.login("myAccount@yahoo.com.tw", "myPassword")
imapObj.select_folder("Inbox", readonly = True)
UIDs = imapObj.search(["ALL"])
print(UIDs)
for i in UIDs:
print("Search %s..."%i)
rawMessages = imapObj.fetch([i], [b"BODY[]"])
message = pyzmail.PyzMessage.factory(rawMessages[i][b"BODY[]"])
if message.html_part == None:
continue
if message.html_part.charset == None:
continue
aText = message.html_part.get_payload().decode(message.html_part.charset)
aBeaSou = bs4.BeautifulSoup(aText, "html.parser")
# 因沒有取消訂閱的連結,將改為尋找特定格式的連結
aTagLis = aBeaSou.select("span a")
if len(aTagLis) >= 1:
for j in range(len(aTagLis)):
webbrowser.open(aTagLis[j].get("href"))
imapObj.logout()
l 利用Email控制您的電腦:
參考本書範例檔torrentStarter.py,故略。
參考本書範例檔torrentStarter.py,故略。
第17章-實作專題參考程式碼
l 擴充和修改本章程式專題的程式範例:
import os
from PIL import Image
SQUARE_FIT_SIZE = 1500
LOGO_FILENAME = "catlogo.png"
logoImage = Image.open(LOGO_FILENAME)
logoWidth, logoHeight = logoImage.size
os.makedirs("withLogo", exist_ok = True)
for originFilename in os.listdir("."):
filename = originFilename.lower()
if not (filename.endswith(".png") or filename.endswith(".jpg") or filename.endswith(".gif") or filename.endswith(".bmp")) or filename == LOGO_FILENAME:
continue
aImage = Image.open(filename)
aWidth, aHeight = aImage.size
if aWidth > SQUARE_FIT_SIZE or aHeight > SQUARE_FIT_SIZE:
if aWidth > aHeight:
aHeight = int((SQUARE_FIT_SIZE / aWidth) * aHeight)
aWidth = SQUARE_FIT_SIZE
else:
aWidth = int((SQUARE_FIT_SIZE / aHeight) * aWidth)
aHeight = SQUARE_FIT_SIZE
print("Resizing %s..."%(filename))
aImage = aImage.resize((aWidth, aHeight))
if aWidth >= (logoWidth * 3) and aHeight >= (logoHeight * 3):
print("Adding logo to %s..."%(filename))
aImage.paste(logoImage, (aWidth - logoWidth, aHeight - logoHeight), logoImage)
aImage.save(os.path.join("withLogo", filename))
import os
from PIL import Image
SQUARE_FIT_SIZE = 1500
LOGO_FILENAME = "catlogo.png"
logoImage = Image.open(LOGO_FILENAME)
logoWidth, logoHeight = logoImage.size
os.makedirs("withLogo", exist_ok = True)
for originFilename in os.listdir("."):
filename = originFilename.lower()
if not (filename.endswith(".png") or filename.endswith(".jpg") or filename.endswith(".gif") or filename.endswith(".bmp")) or filename == LOGO_FILENAME:
continue
aImage = Image.open(filename)
aWidth, aHeight = aImage.size
if aWidth > SQUARE_FIT_SIZE or aHeight > SQUARE_FIT_SIZE:
if aWidth > aHeight:
aHeight = int((SQUARE_FIT_SIZE / aWidth) * aHeight)
aWidth = SQUARE_FIT_SIZE
else:
aWidth = int((SQUARE_FIT_SIZE / aHeight) * aWidth)
aHeight = SQUARE_FIT_SIZE
print("Resizing %s..."%(filename))
aImage = aImage.resize((aWidth, aHeight))
if aWidth >= (logoWidth * 3) and aHeight >= (logoHeight * 3):
print("Adding logo to %s..."%(filename))
aImage.paste(logoImage, (aWidth - logoWidth, aHeight - logoHeight), logoImage)
aImage.save(os.path.join("withLogo", filename))
l 在硬碟中找出照片資料夾:
import os
from PIL import Image
for pathName, folderName, fileName in os.walk("C:\\"):
numPhotoFiles = 0
numNonPhotoFiles = 0
for aFile in fileName:
# Check if file extension isn't .png or .jpg.
if not (aFile.endswith(".png") or aFile.endswith(".jpg")):
numNonPhotoFiles += 1
continue
# Open image file using Pillow.
aImage = Image.open(os.path.join(pathName, aFile))
aWidth, aHeight = aImage.size
# Check if width & height are larger than 500.
if aWidth > 500 and aHeight > 500:
# Image is large enough to be considered a photo.
numPhotoFiles += 1
else:
# Image is too small to be a photo.
numNonPhotoFiles += 1
# If more than half of files were photos, print the absolute path of the folder.
if numPhotoFiles >= numNonPhotoFiles:
print(os.path.abspath(pathName))
import os
from PIL import Image
for pathName, folderName, fileName in os.walk("C:\\"):
numPhotoFiles = 0
numNonPhotoFiles = 0
for aFile in fileName:
# Check if file extension isn't .png or .jpg.
if not (aFile.endswith(".png") or aFile.endswith(".jpg")):
numNonPhotoFiles += 1
continue
# Open image file using Pillow.
aImage = Image.open(os.path.join(pathName, aFile))
aWidth, aHeight = aImage.size
# Check if width & height are larger than 500.
if aWidth > 500 and aHeight > 500:
# Image is large enough to be considered a photo.
numPhotoFiles += 1
else:
# Image is too small to be a photo.
numNonPhotoFiles += 1
# If more than half of files were photos, print the absolute path of the folder.
if numPhotoFiles >= numNonPhotoFiles:
print(os.path.abspath(pathName))
l 自訂的座位卡:
import os
from PIL import Image, ImageDraw, ImageFont
os.makedirs("seatCards", exist_ok = True)
# 本書範例檔guests.txt在目前工作目錄
txtFile = open("guests.txt")
names = []
for i in txtFile.readlines():
names.append(i.strip("\n"))
txtFile.close()
aImage = Image.new("RGBA", (361, 289), "SkyBlue")
bImage = Image.open("tulip.png")
aImage.paste(bImage, (-72, 72), bImage)
ImageDraw.Draw(aImage).line([(0, 0), (360, 0), (360, 288), (0, 288), (0, 0)], "Black", 1)
arialFont = ImageFont.truetype(os.path.join("FONT_FOLDER", "arial.ttf"), 32)
for j in names:
cImage = aImage.copy()
ImageDraw.Draw(cImage).text((40, 40), j, fill = "Black", font = arialFont)
cImage.save(os.path.join("seatCards", j + ".png"))
import os
from PIL import Image, ImageDraw, ImageFont
os.makedirs("seatCards", exist_ok = True)
# 本書範例檔guests.txt在目前工作目錄
txtFile = open("guests.txt")
names = []
for i in txtFile.readlines():
names.append(i.strip("\n"))
txtFile.close()
aImage = Image.new("RGBA", (361, 289), "SkyBlue")
bImage = Image.open("tulip.png")
aImage.paste(bImage, (-72, 72), bImage)
ImageDraw.Draw(aImage).line([(0, 0), (360, 0), (360, 288), (0, 288), (0, 0)], "Black", 1)
arialFont = ImageFont.truetype(os.path.join("FONT_FOLDER", "arial.ttf"), 32)
for j in names:
cImage = aImage.copy()
ImageDraw.Draw(cImage).text((40, 40), j, fill = "Black", font = arialFont)
cImage.save(os.path.join("seatCards", j + ".png"))
第18章-實作專題參考程式碼
l 裝忙程式:
import time, pyautogui
try:
while True:
for i in range(60 * 10):
time.sleep(1)
pyautogui.moveRel(1, 1, duration = 1)
except KeyboardInterrupt:
print("Done")
import time, pyautogui
try:
while True:
for i in range(60 * 10):
time.sleep(1)
pyautogui.moveRel(1, 1, duration = 1)
except KeyboardInterrupt:
print("Done")
l 即時通訊機器人:
import time, pyautogui
# 以facebook示範
time.sleep(5)
messenger = pyautogui.locateOnScreen("messenger.png")
pyautogui.click(pyautogui.center(messenger))
time.sleep(5)
friendName = pyautogui.locateOnScreen("friendName.png")
pyautogui.click(pyautogui.center(friendName))
time.sleep(1)
inputText = pyautogui.locateOnScreen("inputText.png")
pyautogui.click(pyautogui.center(inputText))
pyautogui.typewrite("Hello World")
pyautogui.press("enter")
import time, pyautogui
# 以facebook示範
time.sleep(5)
messenger = pyautogui.locateOnScreen("messenger.png")
pyautogui.click(pyautogui.center(messenger))
time.sleep(5)
friendName = pyautogui.locateOnScreen("friendName.png")
pyautogui.click(pyautogui.center(friendName))
time.sleep(1)
inputText = pyautogui.locateOnScreen("inputText.png")
pyautogui.click(pyautogui.center(inputText))
pyautogui.typewrite("Hello World")
pyautogui.press("enter")
沒有留言:
張貼留言