209190509更新
更新原因:實(shí)際使用下來有 bug,Power Query 對(duì)數(shù)據(jù)格式非常嚴(yán)格,月份輸入不是文本格式會(huì)報(bào)錯(cuò)。
更新內(nèi)容:使用 Text.From 函數(shù)將月份先轉(zhuǎn)換為文本然后做判斷長度和補(bǔ)足兩位的操作,修正了 bug;新加步驟轉(zhuǎn)換氣溫為數(shù)字格式;
因?yàn)?0190508中央氣象臺(tái)出現(xiàn)了0512最高溫39度的異常預(yù)報(bào),為了證明是錯(cuò)誤值,就簡(jiǎn)單做了一個(gè)上海月極值天氣的透視表,可以忽略。
某盤文件下載2 4dif
關(guān)于月份補(bǔ)足到兩位其實(shí) M 語言中有現(xiàn)成的函數(shù)可以用,可以參考 Text.PadStart/End 函數(shù)簡(jiǎn)介,但是我懶得改代碼了,就依然是原有的 If Else 條件判斷。
原文
說明:
excel 2016 最早期的 Power Query 有部分函數(shù)不支持,可能無法運(yùn)行。建議升級(jí)到最新。
2010 和 2013 版本的 Power Query 沒有測(cè)試。
作者有一點(diǎn)兒 Power Query 使用經(jīng)驗(yàn),M 語言只學(xué)了一天,做了這個(gè)模板,所以用這個(gè)代碼的注意檢查數(shù)據(jù)條數(shù)。
懶得寫的特別詳細(xì),所以不針對(duì)一點(diǎn)兒不懂 Power Query 的人。
某盤文件下載 f665
前期思路和準(zhǔn)備
要爬的網(wǎng)頁信息:天氣后報(bào)
URL 舉例:http://www.tianqihoubao.com/lishi/beijing/month/201904.html
拼音 beijing 用來控制是什么城市,201904 是年月。
這樣要爬的 URL 要設(shè)置三個(gè)變量,城市、年份、月份。理論上年份和月份可以是固定的 2011-2019 ,月份也可以是固定的 01-12 月。 考慮到每次都爬 9 年 12 個(gè)月的數(shù)據(jù)(多城市數(shù)據(jù)就更多)比較費(fèi)時(shí)間,大部分使用場(chǎng)景可能也不需要看這么久時(shí)間的天氣數(shù)據(jù),就設(shè)置可以自定義查詢。自定義輸入是通過引用 excel 的表實(shí)現(xiàn)的。
測(cè)試 Excel 表中直接輸入年份月份會(huì)默認(rèn)為數(shù)字、月份即使輸入01,表中也是默認(rèn)為 1。所以需要通過月份的位數(shù)判斷是不是要在前面加一位 0 。然后轉(zhuǎn)換年和月為文本格式。
測(cè)試Excel 表中直接刪除數(shù)據(jù)會(huì)形成空行,要求使用者右鍵刪除表行又多了好幾步操作,所以需要刪選三個(gè)表中的空行。

上述三個(gè)表名稱分別為:城市清單、年份、月份。
全部代碼
上面三個(gè)自定義參數(shù)的表設(shè)置后,直接復(fù)制以下代碼到 PowerQuery 的高級(jí)編輯器中可以直接保存運(yùn)行。
let
tianqi = (city,year,month)=>Table.PromoteHeaders(Web.Page(Web.Contents("http://www.tianqihoubao.com/lishi/"&city&"/month/"&year&month&".html")){0}[Data], [PromoteAllScalars=true]),
source = Excel.CurrentWorkbook(){[Name="城市清單"]}[Content],
添加年份 = Table.AddColumn(source, "yea", each Excel.CurrentWorkbook(){[Name="年份"]}[Content]),
添加月份 = Table.AddColumn(添加年份, "mont", each Excel.CurrentWorkbook(){[Name="月份"]}[Content]),
展開年份 = Table.ExpandTableColumn(添加月份, "yea", {"年份"}, {"年份"}),
展開月份 = Table.ExpandTableColumn(展開年份, "mont", {"月份"}, {"月份"}),
篩選拼音城市年月列不為空 = Table.SelectRows(展開月份, each [cit] <> null and [年份] <> null and [月份] <> null),
判斷月份是否要加0 = Table.AddColumn(篩選拼音城市年月列不為空, "月份2", each if Text.Length([月份]) = 1 then "0"&[月份] else [月份]),
更改年月列為文本 = Table.TransformColumnTypes(判斷月份是否要加0,{{"年份", type text}, {"月份2", type text}}),
添加網(wǎng)頁表格 = Table.AddColumn(更改年月列為文本, "data", each tianqi([cit],[年份],[月份2])),
展開網(wǎng)頁表格 = Table.ExpandTableColumn(添加網(wǎng)頁表格, "data", {"日期", "天氣狀況", "氣溫", "風(fēng)力風(fēng)向"}, {"日期", "天氣狀況", "氣溫", "風(fēng)力風(fēng)向"}),
拆分天氣列 = Table.SplitColumn(展開網(wǎng)頁表格, "天氣狀況", Splitter.SplitTextByDelimiter("/", QuoteStyle.Csv), {"白天天氣", "夜間天氣"}),
拆分氣溫列 = Table.SplitColumn(拆分天氣列, "氣溫", Splitter.SplitTextByDelimiter("/", QuoteStyle.Csv), {"最高氣溫", "最低氣溫"}),
拆分風(fēng)向列 = Table.SplitColumn(拆分氣溫列, "風(fēng)力風(fēng)向", Splitter.SplitTextByDelimiter("/", QuoteStyle.Csv), {"白天風(fēng)向", "夜晚風(fēng)向"}),
刪除攝氏度單位 = Table.ReplaceValue(拆分風(fēng)向列,"℃"," ",Replacer.ReplaceText,{"最高氣溫", "最低氣溫"}),
日期列變更為日期格式 = Table.TransformColumnTypes(刪除攝氏度單位,{{"日期", type date}}),
篩選日期為小于等于當(dāng)前日期 = Table.SelectRows(日期列變更為日期格式, each [日期] <= DateTime.Date(DateTime.LocalNow())),
刪除的列 = Table.RemoveColumns(篩選日期為小于等于當(dāng)前日期,{"cit", "年份", "月份", "月份2"})
in
刪除的列
代碼分步驟解釋
tianqi = (city,year,month)=>Table.PromoteHeaders(Web.Page(Web.Contents("http://www.tianqihoubao.com/lishi/"&city&"/month/"&year&month&".html")){0}[Data], [PromoteAllScalars=true]),
這里在開頭創(chuàng)建了一個(gè)自定義函數(shù) tianqi,參數(shù)有三個(gè) city,year, month 。使用 Web.Page 來獲得網(wǎng)頁表格,Table.PromoteHeaders 用來將第一行用作標(biāo)題。
網(wǎng)頁表格,抓起來一般是沒有標(biāo)題的,column1、column2 的類似標(biāo)題,如果爬出來之后再提升標(biāo)題,前面已經(jīng)設(shè)置好標(biāo)題的列會(huì)因?yàn)闃?biāo)題提升失去固定的標(biāo)題。
source = Excel.CurrentWorkbook(){[Name="城市清單"]}[Content], 添加年份 = Table.AddColumn(source, "yea", each Excel.CurrentWorkbook(){[Name="年份"]}[Content]), 添加月份 = Table.AddColumn(添加年份, "mont", each Excel.CurrentWorkbook(){[Name="月份"]}[Content]), 展開年份 = Table.ExpandTableColumn(添加月份, "yea", {"年份"}, {"年份"}), 展開月份 = Table.ExpandTableColumn(展開年份, "mont", {"月份"}, {"月份"}),
按照三個(gè) excel 表名稱添加展開三個(gè)自定義參數(shù)的表。這幾個(gè)步驟運(yùn)行完的結(jié)果:

篩選拼音城市年月列不為空 = Table.SelectRows(展開月份, each [cit] <> null and [年份] <> null and [月份] <> null), 判斷月份是否要加0 = Table.AddColumn(篩選拼音城市年月列不為空, "月份2", each if Text.Length([月份]) = 1 then "0"&[月份] else [月份]), 更改年月列為文本 = Table.TransformColumnTypes(判斷月份是否要加0,{{"年份", type text}, {"月份2", type text}}),
如步驟名稱,是開頭提過的要對(duì)三個(gè)參數(shù)源表的處理。運(yùn)行結(jié)果:

添加網(wǎng)頁表格 = Table.AddColumn(更改年月列為文本, "data", each tianqi([cit],[年份],[月份2])), 展開網(wǎng)頁表格 = Table.ExpandTableColumn(添加網(wǎng)頁表格, "data", {"日期", "天氣狀況", "氣溫", "風(fēng)力風(fēng)向"}, {"日期", "天氣狀況", "氣溫", "風(fēng)力風(fēng)向"}),
使用開頭聲明的自定義函數(shù)添加一列,然后展開列中表格包含的每一列。

到這一步,抓取數(shù)據(jù)的部分就做完了,接下來是正常使用 Power Query 處理數(shù)據(jù)的部分。
拆分天氣列 = Table.SplitColumn(展開網(wǎng)頁表格, "天氣狀況", Splitter.SplitTextByDelimiter("/", QuoteStyle.Csv), {"白天天氣", "夜間天氣"}), 拆分氣溫列 = Table.SplitColumn(拆分天氣列, "氣溫", Splitter.SplitTextByDelimiter("/", QuoteStyle.Csv), {"最高氣溫", "最低氣溫"}), 拆分風(fēng)向列 = Table.SplitColumn(拆分氣溫列, "風(fēng)力風(fēng)向", Splitter.SplitTextByDelimiter("/", QuoteStyle.Csv), {"白天風(fēng)向", "夜晚風(fēng)向"}),
這里是拆分原表的列,Power Query 的內(nèi)建函數(shù) Table.SplitColumn 似乎沒辦法一次拆分多個(gè)列,原默認(rèn)代碼中的拆分后列名為 天氣狀況.1 和 天氣狀況.2,這里就是一個(gè)重命名的設(shè)置,為了減少步驟,這里我自定義了拆分后列名。

刪除攝氏度單位 = Table.ReplaceValue(拆分風(fēng)向列,"℃"," ",Replacer.ReplaceText,{"最高氣溫", "最低氣溫"}),
拆分后的氣溫包含攝氏度單位,這里使用替換為 null 的方式刪除符號(hào)。

日期列變更為日期格式 = Table.TransformColumnTypes(刪除攝氏度單位,{{"日期", type date}}), 篩選日期為小于等于當(dāng)前日期 = Table.SelectRows(日期列變更為日期格式, each [日期] <= DateTime.Date(DateTime.LocalNow())),
原網(wǎng)頁中的數(shù)據(jù)如果是超過當(dāng)前日期也會(huì)抓出來空白的內(nèi)容,所以這列做了一個(gè)條件篩選,篩選日期小于等于查詢運(yùn)行當(dāng)天日期的行。原抓出來的日期列為文本,這里先轉(zhuǎn)換為日期格式,然后做篩選。
M 語言中沒有工作表函數(shù) now() 來表示當(dāng)前時(shí)間,表示當(dāng)前日期(不含時(shí)間)是 DateTime.Date(DateTime.LocalNow())

刪除的列 = Table.RemoveColumns(篩選日期為小于等于當(dāng)前日期,{"cit", "年份", "月份", "月份2"})
刪除無用的列。


加載到 excel 工作表的數(shù)據(jù):
