---
# System prepended metadata

title: 快樂的大數據實作課程

---

# 快樂的大數據實作課程

[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

```