IMPORTHTML 只能整張表格、整份清單一起抓。如果我只想要網頁上的所有標題,或是每個連結實際指向的網址,就要請出 IMPORTXML,用 XPath 告訴它要哪一塊。
XPath 看起來很像密碼,不過常用的寫法就那幾種,這篇逐一示範,最後講哪些網頁抓不到。
IMPORTXML
IMPORTXML 會讀取網址的內容,把符合 XPath 的部分放進試算表。
語法
- 網址:完整網址,要加 https://,用雙引號包起來,也可以放在別的儲存格再參照。
- XPath查詢:要選哪些元素的描述,同樣用雙引號包起來。
- 地區:選填,用來解析數字、日期的地區代碼;沒填就用檔案的地區設定。本文的範例都用不到。
公式本身已經用雙引號包字串,XPath 裡面要放引號的話,用單引號:"//a[@class='nav']"。
網址我通常放在別的儲存格,公式比較短,要換頁面也只改一格。下面的範例都在 A1 放同一個網址,維基百科的 Mohs scale(莫氏硬度)條目,網址是:
https://en.wikipedia.org/wiki/Mohs_scale_of_mineral_hardness
公式放在 C1,結果會從 C1 往下展開。文中的數字是 2026 年 10 月的頁面。維基百科會被編輯,哪天你看到的數字不一樣是正常的。
XPath 基本寫法
選標籤://h1、//h2
// 的意思是「不管在文件的哪個位置」,後面接標籤名稱。先抓頁面的大標題:
抓頁面中所有 h1 標籤的文字
=IMPORTXML(A1, "//h1")這個頁面只有一個 h1,C1 會得到 Mohs scale。
第一次在檔案裡用 IMPORTXML(或 IMPORTHTML、IMPORTDATA、IMPORTFEED),儲存格會先是 #REF!,畫面上方出現黃色橫幅:「警告:某些公式正試圖傳送資料到外部或接收外部的資料。」右邊有「瞭解詳情」和「允許存取」,按「允許存取」之後,這份檔案裡的這幾個函式才會真的去抓資料。IMPORTRANGE 另有一套「連結試算表」的授權卡片,不走這個橫幅,做法見 IMPORTRANGE 跨試算表同步。
再來抓所有的 h2,也就是各段落的標題:
抓頁面中所有 h2 標籤的文字
=IMPORTXML(A1, "//h2")來看看結果,共 9 列:
| 列 | C |
|---|---|
| 1 | Contents |
| 2 | Reference minerals |
| 3 | Examples |
| 4 | Use |
| 5 | Comparison with Vickers scale |
| 6 | Footnotes |
| 7 | See also |
| 8 | References |
| 9 | Further reading |
第 1 列的 Contents 是維基百科目錄區塊的標題,不是條目的段落。想把它排除,可以加條件,後面的練習會做。
選屬性://a/@href
標籤上的屬性用 @ 開頭。連結的目標網址放在 a 標籤的 href 屬性裡,所以:
抓頁面中所有連結的網址
=IMPORTXML(A1, "//a/@href")這一天的頁面有 429 個連結,前三個是:
| 列 | C |
|---|---|
| 1 | #bodyContent |
| 2 | /wiki/Main_Page |
| 3 | /wiki/Wikipedia:Contents |
第一個 #bodyContent 是跳到頁面內某處的連結,第 2、3 個只有路徑沒有網域,拿去用之前要自己補上 https://en.wikipedia.org。同一個頁面的寫法也不統一,後面還有直接寫完整網址的,真的要整批使用,我會先掃一遍再決定怎麼處理。
標籤換成別的也一樣,//img/@src 就是頁面上所有圖片的來源路徑。
加條件:[@class='...']
方括號裡放條件,@class='wikitable' 的意思是「class 屬性正好等於 wikitable」。想知道頁面上有幾個這種表格,用 COUNTA 數一下:
數 class 正好是 wikitable 的表格有幾個
=COUNTA(IMPORTXML(A1, "//table[@class='wikitable']"))結果是 2。但莫氏硬度那張主表格的 class 是 wikitable sortable,兩個詞,所以沒被選到。「等於」就是整個字串完全一樣,多一個字都不行。
來比較三種寫法,各用一格公式,放在 E1 到 E3:
| 儲存格 | XPath | 結果 |
|---|---|---|
E1 | //table[@class='wikitable'] | 2 |
E2 | //table[contains(@class,'wikitable')] | 3 |
E3 | //table[@class='wikitable sortable'] | 1 |
HTML 的 class 常常有好幾個詞,用「等於」很容易漏掉。E2 的 contains 比較保險。
包含就好:contains()
contains(@屬性, '文字') 的意思是「屬性裡有這段文字就算」。上面的 E2 就是這個寫法,連 wikitable sortable 也選到了,所以是 3 個。
它也可以用在 href 上。我想找所有網址裡有 Vickers 的連結:
抓網址裡含有 Vickers 的連結
=IMPORTXML(A1, "//a[contains(@href,'Vickers')]/@href")來看看結果:
| 列 | C |
|---|---|
| 1 | #Comparison_with_Vickers_scale |
| 2 | https://en.wikipedia.org/wiki/Vickers_hardness_test |
一個是頁面內跳到「Comparison with Vickers scale」那一段的連結,另一個是 Vickers 硬度試驗的條目。
取文字:text()
text() 取的是標籤「直接包著」的文字。莫氏硬度表格的第 2 欄是礦物名稱,每個名稱都包在 a 連結裡面。先不加 text(),直接選第 2 欄的儲存格:
抓硬度表第 2 欄的儲存格,名稱在連結裡面,會一併取到
=IMPORTXML(A1, "//table[contains(@class,'sortable')]//td[2]")這樣會得到 10 列礦物名稱:
| 列 | C |
|---|---|
| 1 | Talc |
| 2 | Gypsum |
| 3 | Calcite |
| 4 | Fluorite |
| 5 | Apatite |
第 6 到 10 列依序是 Orthoclase feldspar、Quartz、Topaz、Corundum、Diamond。其中 Orthoclase 和 feldspar 在原始碼裡中間隔著換行標籤,IMPORTXML 把兩段直接接起來,第 6 列的值是 Orthoclasefeldspar,中間沒有空格。要用這欄去比對或查詢的話,先留意這一列。
改成 td[2]/text() 的話,名字不是 td 直接包著的,而是在 a 裡面,所以什麼都選不到:
td 底下沒有直接的文字,什麼都選不到
=IMPORTXML(A1, "//table[contains(@class,'sortable')]//td[2]/text()")會得到 #N/A,點儲存格的提示是「匯入的內容空白。」。
要取文字就得往下寫到 a:td[2]/a/text()。這樣會得到 11 列而不是 10 列,因為 Orthoclase 和 feldspar 被換行標籤切成兩段文字,各占一列。所以沒有特別需求的話,我會直接選元素本身,不加 text()。
不管用哪一種,查詢寫完我都會用 COUNTA 或 ROWS 數一下結果筆數,看是不是自己預期的數字。
不會寫 XPath 的話
我自己寫 XPath 的流程是這樣的:在 Chrome 上對想抓的字按右鍵,選「檢查」,開發者工具會停在那個元素。再對它按右鍵,選「Copy」>「Copy XPath」,路徑就複製下來了。開發者工具也可以用 F12 或 Ctrl+Shift+I(Mac 為 Cmd+Option+I)打開。
貼進去之前要注意三件事:
- Chrome 複製出來的 XPath 引號是雙引號,像
//*[@id="total"],放進公式要改成單引號。 - 它常常給一長串從頭走到尾的絕對路徑,網頁一改版就斷。如果元素本身有 class 或 id,我會改成上面的
[@class=...]或contains寫法,比較耐用。 - 開發者工具顯示的是瀏覽器整理過的結構,路徑裡的
/tbody/常常是瀏覽器自己補的,伺服器送出的原始碼裡未必有。貼上後選不到東西時,先試著把/tbody/拿掉。
抓不到的時候
IMPORTXML 讀的是伺服器回傳的 HTML,不會像瀏覽器那樣執行頁面上的 JavaScript。所以有幾種情況會抓不到:
- 內容是 JavaScript 之後才填進去的。很多購物網站、股價頁面是這樣,瀏覽器看得到,原始碼裡卻沒有那個數字。
- 要登入才看得到的頁面。公式沒有地方輸入帳號密碼。
- 網站不讓 Google 的抓取程式進去。
判斷是哪一種,我會在 Chrome 開網頁後按 Ctrl+U(Mac 為 Cmd+Option+U)看原始碼,再用 Ctrl+F(Mac 為 Cmd+F)搜尋想抓的字。搜得到,表示伺服器有送,XPath 寫對就抓得到。搜不到,就是 JavaScript 填的,換 XPath 也沒用,要看看網站有沒有公開的資料下載或 API,需要自動化的話再考慮 Apps Script。
抓不到時的錯誤碼,常見是 #N/A,提示會告訴你是哪一種:XPath 選不到東西是「匯入的內容空白。」;網址不存在(404)是「在指定網址找不到資源。」。
抓公開網頁前,先看一下網站的使用條款,也可以在網址後面加 /robots.txt,看對方有沒有不讓機器人抓取的設定,有的話就不要抓。多久更新一次、同一份試算表放太多匯入函式會怎樣、為什麼不能用 NOW() 強迫更新(網址串上 NOW() 會得到 #ERROR!),這些寫在 網頁資料匯入函式 那篇,這裡不重講。
抓回來的文字常常夾著空格、符號或奇怪的格式,整理的方法接著看 整理文字資料 和 髒資料清理分工。
練習
排除目錄的標題
同一個 Mohs scale 頁面,//h2 會多抓到一個「Contents」。觀察原始碼,其他 8 個 h2 都有 id 屬性,Contents 那個沒有。請寫出只抓有 id 的 h2 的公式,網址放在 A1。
數表格的個數
請寫出公式,算出 class 裡有 wikitable 這個詞的表格共有幾個,網址放在 A1。
換一個你常看的公開網頁,試著抓抓看它的標題和連結吧!
我是喜特先生,Mr. Sheet,我們下個教學見!
接下來可以
這篇在技能樹的 Lv.3「資料整合與自動化」,模組「處理網頁資料」(第 1/1 篇)。讀完這篇,路線上的下一個模組是「AI 幫你清理資料」。
回到技能樹相關文章
查看所有文章留言討論
共 0 則留言
