# 快樂的大數據實作課程 [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 ```