# 快樂的大數據實作課程
[TOC]
9/27 許正乾
---
1. 安裝了[anaconda](https://medium.com/python4u/anaconda%E4%BB%8B%E7%B4%B9%E5%8F%8A%E5%AE%89%E8%A3%9D%E6%95%99%E5%AD%B8-f7dae6454ab6)
2. 使用jupyter
3. BeautifulSoup 是一個解析網頁用的套件
. 教學pip 下載套件
```bash
pip3 --version
```
可以看pip的版本
``` bash
pip3 install pyprind
```
安裝pyprind這個套件
conda路徑的輸出
```bash
# MacOS
export PATH=$PATH:/usr/local/anaconda3/bin/
# 或
export PATH=$PATH:/anaconda3/bin/
```
安裝Pyprind
(出現No module named 'pyprind'的話)
```bash
conda install pyprind
# 若無效則可用下一行這種
conda install -c conda-forge pyprind
```
windows的conda [參考文件](https://oranwind.org/bid-data-mac-os-an-zhuang-)
Windows安裝Python後要設定的的環境變數
`C:\Users\<-你的使用者名稱->\AppData\Local\Programs\Python\Python36\Scripts\`
在jupyter中新增文件
加入下方的code
```python
from urllib.parse import urlparse
import urllib.request
import requests
from bs4 import BeautifulSoup
import pyprind
CodeRange = range(2301,2500)
domain = "http://stock.nlog.cc"
headers = {'User-Agent':'Mozilla/5.0 (X11; Linux i686; rv:47.0) Gecko/20100101 Firefox/47.0'}
## Operating Profit Margin module ##
pbar = pyprind.ProgBar(len(CodeRange), track_time=True)
for i in CodeRange:
url = "http://stock.nlog.cc/b/"+str(i)
#print(url)
try:
req = urllib.request.Request(url = url, headers=headers)
page = urllib.request.urlopen(req)
content = page.read()
bs = BeautifulSoup(content, 'html.parser')
data01 = bs.find_all("table",{"class":"x"})
rows01 = data01[1].find_all('tr')[3]
#print(rows.text)
col01 = rows01.find_all("td")[0] # col is str
newestOIM = float(col01.text.strip(" %")) # convert str to float
if newestOIM >= 10.0:
print(url)
print(rows01.text)
print(newestOIM)
#writer = fo.write(rows.text)
except:
url = "http://stock.nlog.cc/b/"+str(i)
continue
#pbar.update()
print(pbar)
```
然後按下Run
code就會動了!
10/4 葉建夆
---
### 什麼是網路爬蟲
本日的[SLIDO](https://app.sli.do/event/1ytggjq8)
為什麼要做爬蟲
- 可以由電腦自動在網路上面抓資料的程式,可以節省時間
- 可以減少資料的成本
- 在開發爬蟲時建議使用Chrome作為瀏覽器
- 以監控匯率為例,下為範例程式碼
```python
# -*- coding: utf-8 -*
"""
┏┓ ┏┓
┏━┛┻━━━━┛┻━┓
┃ ☃ ┃
┃ ┳┛ ┗┳ ┃
┃ ┻ ┃
┗━┓ ┏━┛
┳┛ ┗━┓
┃ ┃
┃ ┣┓
┃ ┏┛
┗┓┓┏━━━━━┳┓┏┛
┃┫┫ ┃┫┫
┗┻┛ ┗┻┛
God Bless,Never Bug 20190919 by Jimmy 抓取台銀最新時間匯率, 並且存成excel檔案
"""
import requests #處理request用的
import pandas as pd # 處理表格用的(Excel)
from bs4 import BeautifulSoup
# import 需要⽤用到的 module
url = 'https://rate.bot.com.tw/xrt?Lang=zh-TW' # 要抓取的網址
req = requests.get(url)
# 發送requests
bs = BeautifulSoup(req.text, 'html.parser') # 將response的內容放入beautiful soup
time = bs.find('span', {'class': 'time'}).text # 查詢時間: 找到⼀一個span tag ,其class name = time print('掛牌時間:', time)
print('=' * 50)
# target 1 -> 時間
table = bs.find('table', {'class': 'table table-striped table-bordered table-condensed table-hover'})
tbody = table.find('tbody')
# 從⽬目標最外層一層一層tag查詢
# 查詢⼀個 table, 其class name = table table-striped table-bordered table-condensed table-hover
# 由於該table內只有一層tbody, 且沒有其他屬性, 因此就無須指定
data_list = []
for tr in tbody.find_all('tr'):
currency = tr.find('div', {'hidden-phone print_show'}).text.strip()
# 連續查詢 tr class 為 hidden-phone print_show 的 div tag
cash_buy = tr.find('td', {'data-table':'本行現金買入'}).text.strip()
cash_sell = tr.find('td', {'data-table':'本行現金賣出'}).text.strip()
real_buy = tr.find('td', {'data-table':'本行即期買入'}).text.strip()
real_sell = tr.find('td', {'data-table':'本行即期賣出'}).text.strip()
data_list.append([currency, cash_buy, cash_sell, real_buy, real_sell])
df = pd.DataFrame(data_list, columns = ['幣別', '本⾏買入(現金)', '本行賣出(現金)', '本⾏買入(即期)', '本⾏賣出(即期)'])
df.to_excel('台銀匯率.xlsx')
```
> 下下禮拜見[name=葉建夆]
>
10/18 葉建夆
---
### 本次教材 : [TMU 網路爬蟲(二).ipynb ](https://drive.google.com/open?id=1WZD6Pf0PmM-3pW5dRlHPMkfVQlPpjBEn)
今天要教的部分是在"抓取的資料是表格"的狀況。
使用Pandas抓取網頁table及匯率
```python=
import pandas as pd
import requests
url = 'https://rate.bot.com.tw/xrt?Lang=zh-TW'
req = requests.get(url)
# 發送 requests
df = pd.read_html(req.text)[0].dropna(axis=1)
# 刪除有空值的資料
# axis = 1代表針對橫列做處理;反之,axis = 0是針對縱行做處理
for i in df.values.tolist():
data_list.append(i[0:5])
data_list = [i[0:5] for i in df.values]
# 留下僅存需要的資料
new_df = pd.DataFrame(data_list, columns=['幣別', '現金本行買入', '現金本行賣出', '即期本行買入', '即期本行賣出'])
# 將資料格式轉為data frame
new_df['幣別'] = new_df['幣別'].apply(lambda x: x.split(' ')[0])
# 資料清洗
print(new_df)
new_df.to_excel('台銀匯率.xlsx')
```
參考:[什麼是lambda ](https://openhome.cc/Gossip/Python/LambdaExpression.html)
參考:[ DataFrame 的 apply函數](https://blog.csdn.net/qq_19528953/article/details/79348929)
什麼時候該用BeautifulSoup 什麼時候該用pandas 是用經驗來判斷。如果網頁有很單純的表格,那麼就用pandas。如果網頁很複雜,那麼就比較適合使用BeautifulSoup。
使用pandas抓取日幣歷史匯率
-----
```python
import requests
import pandas as pd
url = 'https://rate.bot.com.tw/xrt/quote/day/JPY'
req = requests.get(url)
df = pd.read_html(req.text)[0]
df = df.dropna(axis=1)
df.columns = ['時間', '幣別', '現金本行買入', '現金本行賣出', '即期本行買入', '即期本行賣出']
print(df)
df.to_excel('jpy.xlsx')
```
### 情境:
你老闆要你定期抓日幣匯率,低到0.28以下的時候要通知你老闆。
抓取純日幣匯率
-----
```python
import requests
import pandas as pd
import datetime
import sys
target_price = 0.28
# 設定目標價格
while True:
url = 'https://rate.bot.com.tw/xrt?Lang=zh-TW'
req = requests.get(url)
# 先向網站發送requests
df = pd.read_html(req.text)[0]
# 用pd將網頁中的html讀入
df = df.dropna(axis=1)
# 先去除有na值的欄位
df = df[df.columns[:5]]
df.columns = ['幣別', '現金買入', '現金賣出', '即期買入', '即期賣出']
# 只取前五個我們所需要的欄位並重新命名
df = df.query('幣別=="日圓 (JPY) 日圓 (JPY)"')
# 查詢我們要的幣別
df.index = df['幣別']
# 更換index以方便後面做取值
real_sell = float(df['即期賣出']['日圓 (JPY) 日圓 (JPY)'])
# 取出值之後轉為float
now = datetime.datetime.now().time()
if real_sell < target_price:
# 檢查是否小於目標價格
#sys.exit()
#Jupyter Notebook不支援sys.exit()
break
elif now >= datetime.time(16, 1, 0):
# 檢查是否超過銀行關門時間
#sys.exit()
#Jupyter Notebook不支援sys.exit()
break
else:
print(now, real_sell)
continue
```
> 剛好最近有出國的計畫[name=葉建夆]
>
參考:[while迴圈的用法與說明](http://tw.gitbook.net/python/python_while_loop.html)
自我挑戰作業
-----
> 1.將上述監測日幣匯率是否小於0.28的程式改為每日執行的排程
> 2.抓到這個[網頁](https://www.twse.com.tw/exchangeReport/STOCK_DAY?response=html&date=20191018&stockNo=1101) 裡面10/18的收盤價
> [name=葉建夆]
>
自我挑戰作業解答
-----
```python
#自我挑戰作業1的解答
#大家加油~
```
```python
#自我挑戰作業2的解答
import requests
import pandas as pd
date = '108/10/18'
url = 'https://www.twse.com.tw/exchangeReport/STOCK_DAY?response=html&date=20191018&stockNo=1101'
req = requests.get(url)
df = pd.read_html(req.text)[0]
df.index = df[('108年10月 1101 台泥 各日成交資訊', '日期')]
price = df[('108年10月 1101 台泥 各日成交資訊', '收盤價')][date]
print('date:', date, 'price:', price)
```
10/25 Fay Wang
---
### 本次教材 : [匯率資料長條圖-20191025.ipynb](https://)
小訣竅
* [Jupyter Notebook快捷鍵](http://opus.konghy.cn/ipynb/jupyter-notebook-keyboard-shortcut.html)
* 顯示程式碼行號 View > Toggle Line Number
* Control+Enter 直接執行目前列
* Control+/ 註解(去註解)目前選取範圍或目前那列
* pwd 顯示目前目錄位置
* ESC+a 在目前列之上新增一列
* ESC+b 在目前列之下新增一列
* dd(連續按兩下d) 刪除目前列
首先要安裝套件:
方法一: 在anaconda prompt 裡安裝:
```bash
conda install -c conda-forge matplotlib
conda install -c anaconda seaborn
```
方法二: 直接在notebook裡安裝
```bash
!conda install matplotlib
!conda install seaborn
```
本日的程式碼
```python
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
import re
#讀入上ㄧ堂製作好的台銀匯率.xlsx
data = pd.read_excel('台銀匯率.xlsx')
# 查看前五筆資料
data.head()
# 刪除多餘的欄位
data.drop(columns=data.columns[0],inplace=True)
# 或
# data = data.drop(columns=data.columns[0])
# 更改欄位名稱
data.rename(columns={'現金本行買入':'現金買入',
'現金本行賣出':'現金賣出',
'即期本行買入':'即期買入',
'即期本行賣出':'即期賣出'},inplace=True)
data.head()
# 將數值型態的資料,進行型態轉換
data['現金賣出'] = data['現金賣出'].apply(pd.to_numeric, errors='coerce')
# 根據指定欄位排序
data = data.sort_values(by='現金賣出',ascending=False)
data.head()
data[data.columns[1:]] = data[data.columns[1:]].apply(pd.to_numeric, errors='coerce')
#繪製長條圖
# 設定畫布大小
plt.figure(figsize=(20,18))
# 設定中文字型
#plt.rcParams['font.sans-serif'] = ['SimHei']
#plt.rcParams['font.family']='sans-serif'
# 設定字型大小
# plt.rc('font', size =14)
# 繪製長條圖
plt.bar(data['幣別'],data['現金賣出'], width=0.5, align='center')
# 加上數字
# xlocs, xlabs = plt.xticks()
# for i, v in enumerate(round(data['現金賣出'],3)):
# plt.text(xlocs[i] - 0.30, v + 0.02, str(v))
# 設定X和Y軸說明、標題
plt.xlabel('幣別')
plt.ylabel('現金賣出價格')
plt.title('台銀匯率')
#增加格線
#plt.grid(True)
#存圖至本機中並指定DPI為100
plt.savefig('匯率排名.jpg',dpi=100)
plt.show()
#再來是試著改用Seaborn繪圖,比較漂亮
#
# 直接刪除空值(主要是針對NA的南非幣)
data.dropna(axis=0,inplace=True)
#進行index reset,否則英鎊在Excel檔內的index是2,就算現金賣出是第1名,也會被繪製在第2位
data.reset_index(drop=True,inplace=True)
plt.figure(figsize=(12, 18))
# 設定字型、畫布樣式
#下面這個比較複雜,如果只是要設定字型的話,不用這麼複雜
#sns.set_style("darkgrid",{"font.sans-serif":['simhei','Droid Sans Fallback']}
#Windows的朋友請服用這行
sns.set(font='Microsoft JhengHei')
#Mac的朋友請服用這行
sns.set(font='Arial Unicode MS')
#以上請根據OS 2選1
sns.set_context(context="notebook",font_scale=1)
# bar 有很多參數可以設定 例如顏色 調色盤等等
# 繪製長條圖
g = sns.barplot(x=data['幣別'], y=data['現金賣出'])
# 標示數值
for index, row in data.iterrows():
g.text(x=index,y=row['現金賣出'],s= round(row['現金賣出'],3),
color='black', ha="center",
fontsize=10)
# 設定labels和標題
g.axes.set_title("台銀匯率",fontsize=16)
g.set_xlabel("幣別",size=16)
g.set_ylabel("現金賣出價格",size=16)
plt.show()
```
台中公車脫班練習
```python
#讀入脫班次數csv
data_bus = pd.read_csv('台中公車脫班次數.csv')
#去除掉空值
data_bus.dropna(axis=0,inplace=True)
#僅留下2019/7/1的資料
data_bus.drop(columns=data_bus.columns[2:],inplace=True)
# 更改欄位名稱
data_bus.rename(columns={'RouteID':'路線名稱',
'2019/7/1':'脫班次數'},inplace=True)
#以脫班次數排序(由大排到小)
data_bus = data_bus.sort_values(by='脫班次數',ascending=False)
#取前10名
data_bus = data_bus.head(10)
#重新編寫index
data_bus.reset_index(drop=True,inplace=True)
plt.figure(figsize=(12, 18))
# 設定字型
#Windows的朋友請服用這行
sns.set(font='Microsoft JhengHei')
#Mac的朋友請服用這行
sns.set(font='Arial Unicode MS')
#以上請根據OS 2選1
#
sns.set_context(context="notebook",font_scale=1)
# 繪製長條圖
g = sns.barplot(y=data_bus['路線名稱'], x=data_bus['脫班次數'],palette=sns.light_palette('green'))
# 標示數值
for index, row in data_bus.iterrows():
g.text(y=index,x=row['脫班次數'],s= round(row['脫班次數'],3),
color='black', ha="center",
fontsize=10)
# 設定labels和標題
g.axes.set_title("7/1路線與脫班次數",fontsize=16)
g.set_ylabel("路線名稱",size=16)
g.set_xlabel("脫班次數",size=16)
plt.show()
```
練習
-----
>(1)
>針對現金賣出重新排序資料
>並查看結果
>(2)
>繪製7/1的公車脫班次數最高的前10筆班次:
>要將日期的欄位名稱(如2019/7/1)改成脫班次數
>(3)更換調色盤
>(4)將直條圖轉為橫條圖
>[台中公車脫班次數.zip](https://drive.google.com/file/d/1vebUrdGftVsHqUKZ8W90tKpiVZgox91O/view?usp=sharing)
Mac使用者缺乏中文字型時的解法
-----
>[安裝simhei字體](https://medium.com/@wulala505/matplotlib-pyplot-%E5%9C%A8mac%E8%A8%AD%E5%AE%9A%E7%B9%81%E9%AB%94%E4%B8%AD%E6%96%87%E5%AD%97%E5%9E%8B-88f5b027a352)
>或是使用plt.rcParams['font.sans-serif'] = ['Arial Unicode MS']
參考文件:
[pandas針對非數值型態時,可採取的轉型方法](https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.to_numeric.html)
[Matplotlib.bar 文件說明](https://matplotlib.org/3.1.1/api/_as_gen/matplotlib.pyplot.bar.html)
[Seaborn參考文件1](https://seaborn.pydata.org/generated/seaborn.set_style.html)
[Seaborn參考文件2](https://seaborn.pydata.org/generated/seaborn.set_context.html)
[Seaborn參考文件3](https://seaborn.pydata.org/generated/seaborn.barplot.html)
[Seaborn調色盤1](https://python-graph-gallery.com/197-available-color-palettes-with-matplotlib/)
[Seaborn調色盤2](https://seaborn.pydata.org/tutorial/color_palettes.html)
11/01 Fay Wang
---
### 本次教材 : [日幣資料折線圖.zip](https://)及[jpy.xlsx](https://)
前情提要:先安裝ploty
```bash
conda install -c plotly plotly
```
本日的code
```python
import pandas as pd
import numpy as np
import datetime
import matplotlib.pyplot as plt
import seaborn as sns
import plotly.graph_objects as go
import plotly
# 讀入爬蟲結果的excel
# 變數名稱盡量不要取跟函數的參數名稱一樣,會精神錯亂
data_new = pd.read_excel('jpy.xlsx',index_col=0)
# 查看前五筆資料
data_new.head()
# 查看資料型態
data_new.dtypes
# 將「時間」欄位的資料型態,修改成時間的型態
data_new['時間'] = pd.to_datetime(data_new['時間'])
# 時間欄位的資料型態改變了
data_new.dtypes
data_new.head()
data_new.drop(columns=['幣別'],inplace=True)
# 將寬的dataframe改成長的dataframe
draw_df = pd.melt(frame=data_new,id_vars='時間',var_name='匯率類別',value_vars=data_new.columns[1:],value_name='匯率值')
#查看前五筆資料
draw_df.head()
# 只擷取資料的日期(因整份資料的日期皆相同,隨便拿一筆即可)
date = draw_df.loc[1,'時間'].strftime(format='%Y-%m-%d')
date
#繪製現金買入的折線圖
# 定義畫布和大小
plt.figure(figsize=(12,10))
# 定義字型
#windows用這個
plt.rcParams['font.sans-serif'] = ['SimHei']
#windows還是不行的話,試試這個
plt.rcParams['font.sans-serif'] = ['Microsoft JhengHei']
#mac用這個
plt.rcParams['font.sans-serif'] = ['Arial Unicode MS']
# 設定X和Y軸字體大小
sns.set_context(context="paper",font_scale=1)
# Mac 可用以下指令
# plt.rcParams['font.sans-serif'] = ['Arial Unicode MS']
# 繪製折線圖
ax = sns.lineplot(x='時間',y='現金本行買入', data=data)
# 設標題
ax.set_title('{} 日圓現金本行買入變化圖'.format(date),size=18)
# X和Y軸標題
ax.set_xlabel('{} 各時段'.format(date),size=16)
ax.set_ylabel('{} 日圓'.format(date),size=16)
plt.show()
```
```python
from pandas.plotting import register_matplotlib_converters
register_matplotlib_converters()
# 定義畫布和大小
plt.figure(figsize=(12,10))
# 定義字型
#plt.rcParams['font.sans-serif'] = ['SimHei']
plt.rcParams['font.sans-serif'] = ['Arial Unicode MS']
# 設定X和Y軸字體大小
sns.set_context(context="paper",font_scale=1)
# Mac 可用以下指令
# plt.rcParams['font.sans-serif'] = ['Arial Unicode MS']
# 繪製折線圖
ax = sns.lineplot(x='時間',y='匯率值',hue='匯率類別', data=draw_df)
# 設標題
ax.set_title('{} 日圓變化圖'.format(date),size=18)
# X和Y軸標題
ax.set_xlabel('{} 各時段'.format(date),size=16)
ax.set_ylabel('{} 日圓'.format(date),size=16)
# 設legend字體大小
plt.legend(loc='lower right',fontsize='x-large')
plt.show()
```
練習
-----
用seaborn繪製公車TXG1在7月1日到7月30日的折線圖
用plotly繪製公車TXG1在7月1日到7月30日的折線圖
用plotly繪製公車前四筆在7月1日到7月30日的折線圖在同一張圖上
```python
```