• 沒有找到結果。

第三章 資料處理

3.1 D ATA C RAWLING

3.1.2 KKBOX 排行榜

化。我們透過檢視網頁原始碼以及輔助工具「InfoLite」對 HTML 框架進行解析,

檢查排行榜內的資料分別被放置在 HTML 的哪些標籤中,再利用 Python 的 Request 套件來獲取網頁資訊 ,將網頁內容按照日期處理,並且轉換型態儲存 到 CSV(Comma-Separated Values)檔中,以下是在抓取資料上所使用的方式。

1. Datetime12

KKBOX 排行榜是日曆選單式網頁,儲存著歷年來每日的排行榜資訊,網址 Url 依據日期進行轉換,為了讓程式碼能夠自動抓取當天排行榜,利用了 Python 的 套件 Time ,來幫助取得當日日期。

利用 Time 中的 Strftime 函式,我們可以自行定義想要抓取的日期樣式,像 是「 strftime(“%Y-%m-%d-%H:%M:%S”) 」可以得到「2016-03-17-18:06:48」

的字串,透過這個方法我們可以避免掉格式問題直接將日期格式處理成我們所需

12資料來源:https://docs.python.org/2/library/time.html

「20160301」後會因為迴圈遞減到「20160300」,而非我們所要的「20160229」。

另外由於抓到的日期會以 Datetime 的格式儲存,如「 2016-02-29 」,為了方便 處理,我們透過 String 中的 Split 函式將字串中的「 - 」當作切割點,製作 出字串陣列「 “2016” , “02” , “29” 」並進行重組,產生「20160229」

的連續字串。

2. Request13

HTTP,Hypertext Transfer Protocol,是瀏覽器與網站的溝通語言,其中 瀏覽器指的是 Client 端,Web Browser;而網站指的是 Server 端,Web Server。

在應用上主要以 Client 端發出 Request 讓 Server 端接收並且做出回應。

Request 在 Python 上的功能包含了 Get、Post、Put、Delete、Head、Options 等。我們可以透過 Get 要求伺服器端將網頁資訊完整的傳遞過來,內容包含了網 址 Url、Headers、Content、History、Status_code 等等,其中,Content 是以 網頁原始碼的形式寫成,如果想要將格式去除,只取得網頁上的資訊,那便必須 使用 Parser 進行語法分析,才能夠將其分割。

3. BeautifulSoup14

BeautifulSoup,是用 Python 編寫的一個 HTML/XML 解析套件,能夠迅速地 處理複雜的網頁文檔,並且生成剖析樹(Parse Tree),提供許多簡單、實用的內 建函式,幫助我們進行網頁架構的處理。

從 Request 中 獲 得 HTML 文 本 後 , 需 先 對 架 構 進 行 解 析 , 我 們 透 過

13資料來源:http://docs.python-requests.org/en/master/

14資料來源:https://www.crummy.com/software/BeautifulSoup

BeautifulSoup 的 Prettify 函式來將文本進行整理輸出,以便理清 KKBOX 排行 榜的網頁結構性。KKBOX 的網頁架構可以展開成一個大型的樹,每一個節點 (Node)都代表了一個標籤,透過標籤我們能夠搜索到文本的任一角落。

在 BeautifulSoup 中,仍將 Parent、Sibling、Children 的關係以 Tag 的方 式儲存,因此可以用資料結構的方式進行探查,另外其他還包含了幾個內容並非 以 Tag 方式儲存,以下兩種型態不能使用一般資料結構的節點來處理,因為它們 被儲存為 List 的形式:

表 5 BeautifulSoup Contents 與 String 比較

Contents 以搜尋的方式呈現,可直接抓出該位置之中的所有內容,其中也包含 了其 HTML 的標籤

String 當標籤中僅僅含有一個 NavigableString 時,可以直接使用此功能來 得到標籤中的字串,不會連同框架一起抓取。且 String 套件不僅只有 CSS。InfoLite 是可以安裝在 Google Chrome 瀏覽器上的擴充程式,透過 InfoLite 我們可以輕鬆選定網頁上的任何一個位置或資料來查詢此筆資料是被放置在 HTML 中的哪個位置,利用這個方法,我們快速的掌握了 KKBOX 排行榜的各欄位 之關係。KKBOX 排行榜網頁,排行榜的內容儲存在名叫「charts-top100」的 class 當中,撇除其他額外的網頁內容,主要有幾個分層,如圖 4 所示。

‧ 國

立 政 治 大 學

Na tiona

l Ch engchi University

23

圖 4 KKBOX 排行榜網站 HTML 分層架構

在 Content 當中,我們所需的資料全都儲存於「Chart-top 100」的 Class 當中,其中排行榜的前一百名歌曲被分成三個部分,「First」第一名、「Top 20」

儲存了第二到第 20 名的歌曲、「Top 100」則儲存第 21 到第 100 名的歌曲。

理清資料的位置後,我們嘗試進行內容的抓取。在 BeautifulSoup 中,抓取 資料有兩種方式,「Search」以及「Select」。

搜尋模式(Search),透過找到節點的方式直接去搜尋該節點中的所有內容,

函式為 find_all( name , attrs , recursive , text , **kwargs )。搜尋運 用的方式很廣泛且靈活,我們能夠在函式中填入單個或多個搜尋參數進行比對,

也可以在參數中訂立條件式 re_compile 進行比較,或是透過 css 進行搜尋。而 這些透過搜尋所得到的資料將皆以集合的方式儲存其中。

CSS 選擇器(Select),和搜尋不同的地方在於 Select 是選擇一個節點位置,

而該位置則取決於輸入的參數,此方式將網頁視為一層層的結構,透過這個語法 我們可以分次的解剖其內容,並且透過節點方式取出資料。Select 查詢的類型 大致上可分為四種,「Tag 標籤」、「CSS Name」、「Tag ID」、「Attribute」。以下 我們將這兩大類型的內容做的整理。

Search

搜尋比對 透過輸入單個或多個標籤、字串、內容等等的方式來找出在此節 點之中所有與其相同之內容或標籤

搜尋比較 透過 re_compile()函式,我們可以對節點中的內容進行查對比 較,和搜尋比對不同的是,搜尋比對會將與其搜尋內容完全一樣 的標籤或內容呈現出來,而搜尋比較則是將與其相關的內容都一 併找出。舉例來說,透過搜尋比對找尋 ‘b’ ,得到的結果會是:

「<b>...</b>」的標籤與內容,而搜尋比較則會同時得到:

「<b>...</b>」與「<body>...</body>」的標籤與內容

CSS 搜尋 在 Python 中,Class 屬於保留字之一,因此在 find_all 函式中 可以透過「find_all(class_=‘item’)」的方式來搜尋我們所要 的內容

Select

Tag 標籤 直接透過標籤名稱查詢,可以一次輸入多個,程式碼將會自動逐 層查找。如果輸入「soup.select("html head title”)」,程式 碼將會到 HTML 層中的 Head 標籤,再進入 Head 標籤中找出名為 title 的標籤內容,如「<title>...</title>」

CSS Name 透過 Class 的名稱來進行查詢,可直接進入該分層,並且抓取資 料

Tag ID 透過該標籤的 id 內容進行查詢,將 id 相同者全數搜尋出來 Attribute 透過存在的某種屬性來進行查詢,另外也可以透過屬性值來進行

查詢,該方法將會找出該位置內所有屬性相同者

另外,選擇器(Select)得到的內容與搜尋(Search)得到的內容不同,皆會以 List 的方式儲存起來,而長度則依據選擇器所搜尋到的資料量來定奪,搜尋到 一筆則陣列的長度為 1。

Search 與 Select 兩種模式的操作方式不盡相同,Search 的使用比較像是 針對單筆或不大量的資料進行查找,透過標籤名稱查詢會因標籤名稱相同,找到 諸多不必要的資料,如果要撇除不必要的資料,勢必得將搜尋的條件設立的更加 嚴謹,但如此一來將會失去靈活性,另外我們所欲得到的資料只有標籤當中的字 串內容,但我們無法得知我們的資料當中將會有哪些字串,因此不能使用搜尋比

Class 的方法,我們可以直接進入到排行榜所在的節點,接著分層進入到 First、

Top 20、Top 100 之中抓取資料。

Now Prev Artist Song First_rank Release_date Ranking_date 1 2 林俊傑 不為誰而作的歌 首次第 37 名 20151204 20151204 20160125

透過 BeautifulSoup 解析後,不論該 HTML 的編碼是哪一種,BeautifulSoup 皆會將其轉換成 Unicode 呈現,而輸出則皆會以 UTF-8 輸出,然而在輸出 artist Linux 則多半是使用 Unicode 編碼,所以執行上雖然不會發生錯誤,但系統因為 沒有辦法自動執行 UTF-8 編碼,因此會將內容以 Unicode 編碼對應,導致寫入亂 碼的結果。