爬剖HTML檔

1. Understanding HTML format

HTML檔案結構

HTML檔案的結構大致如下:

  • 首先會有一個檔案類別的宣告<!DOCTYPE html>,用以告訴第三方瀏覽器或應用程式說這是一個HTML5檔案;

  • 再來是成對標籤所組成的巢套結構,下例即有一對<html></html>包著一對<head></head>和一對<body></body>。

  • 另外<!---->包著的內容為註解,瀏覽器或程式遇到該區段的內容會略過不處理。

下圖可用以說明HTML檔案的巢套(一層包一層)結構(圖片來源https://www.w3schools.com/html/html_intro.asp)。

元素與屬性 Elements and Attributes

每一對標籤,我們把它稱為一個Element(HTML元素)。下二圖為兩個元素(elements),一對「標籤(tags)」前後包夾稱為一個「元素」,在Opening tag中除了標籤名外的其他資訊為「屬性(Attribute)」,一個屬性包含屬性名稱(Attribute name)和屬性值(Attribute value),屬性值多為文字,所以需要用雙引號括起來。

例如:以下自由時報新聞關鍵字查詢的結果以及pchome24h購物中心產品查詢的結果。可見ㄍ到<a></a>為一對elements、而網址則以attribute value指給href這個既定名稱的<a>的屬性。

2. HTML中的資料在哪裡?使用CSS Selector與XPath

那我們要的資料通常會怎麼放在HTML上呢?

  • <p> 通常如果是本文多會是用<p></p>,<p>的意義為paragraph;

  • <h1>如果是要取出新聞或文章標題的話,通常會是<h1>、<h2>等headings(標題);

  • <li>若回傳的搜尋結果的話,多半會是用<ul></ul>內包著<li></li> 表示,<ul>為unordered list(無序列表)、<li>為list item(列表中的項目)

  • <table>若是查詢資料結果為網頁「表格」多半用<table></table>包裹,裡面會有<th></th>、<tr></tr>、<td></td>等,分別為table header、table row、與table data。

  • <div>網頁中巢套的最厲害的是<div></div>為division的縮寫,也就是網頁的區塊,通常被用來區隔頁面中的區塊,是進行排版和視覺化的好幫手。

id與class的用途

在一個html檔案中,id是唯一的,而class則可以出現在好幾個地方。因此,若你要的資料外包一個有id的區塊,應該非常高興。例如下面的例子的CSS Selector可縮寫為 #newslistul li

使用Chrome DevTools獲取節點路徑

XPath and CSS selector: 一般來說,要獲取HTML文檔中的內容有兩種途徑,一種是CSS Selector,和CSS語法、概念完全相同;另一種是XPath,不是那麼常看見,但卻有支援一些CSS Selector沒支援的功能(例如用text()取出沒有HTML tag僅有純文字的部分)。CSS Selector和XPath是用來定義一個路徑,以選取HTML中的一個或者多個條件相同的元素。例如說,定義一條路徑來選取頁面上所有的標題,或選取所有標題背後的超鏈結,或選取頁面上搜尋結果的圖片路徑、或選取某PTT Web上討論版某篇文章所有回文者的ID。

使用Chrome DevTools找尋CSS Selector與XPath

對著你所要複製資料路徑(或者元素路徑)的元素按右鍵,就可以複製CSS seletor與XPath路徑,自由時報的搜尋結果為例,其在搜尋結果頁面的一則文章其CSS selector與XPath分別為

  • CSS selector: #newslistul > li:nth-child(1)

  • XPath: //*[@id="newslistul"]/li[1]

一般化路徑與簡化路徑

注意看上面的例子會發現他是從#newslistul這個id開始寫起,因為id在整個HTML內理論上是唯一的,所以前面的路徑都可以省了。而複製的路徑#newslistul > li:nth-child(1)表示#newsslistul這個id底下的第一個<li>,可以進一步修改路徑以 表示#newslistul底下的<li>我全都要了#newslistul li

若以XPath來看的話,複製的路徑://*[@id="newslistul"]/li[1]

  • //表示選取所有可能的情形

  • *表示任意一個element。因為有id的關係,所以可以忽略它本身是個甚麼物件,所以用//*代表即可

  • *[@id="newslistul"]表示任意一個id為newslistul的元素

  • /li[1]在前述標籤底下的表示第一個<li>

可更改路徑為選取全部的元素,而非只是第一個://*[@id="newslistul"]//li//li表示在前述標籤底下的所有<li>我都要

3. Parsing HTML: ptt as an example

Last updated

Was this helpful?