[Python網頁爬蟲] Scrapy的安裝與使用入門-2
Scrapy是一套開放原始碼框架,對於網頁爬蟲作業基本上會有幾個步驟,包括識別目標網址、取得頁面內容、解析以及儲存網頁等步驟,Scrapy框架中定義了完整的爬蟲流程與模組。透過它可以幫助我們快速且簡單的抓取HTML頁面、取得回傳資料。
在上一篇中我們已經建立了Scrapy爬蟲專案 my_spider_1,並且在專案資料夾中初始化了一個爬蟲程式(advertimes
)。接下來要在advertimes.py檔案中實際撰寫爬蟲的內容,來對目標網頁爬取資料。
提醒:
在這裡我們要抓取的目標頁面是 https://www.advertimes.com/global/
Scrapy爬蟲實作
爬取的方式可分為二層次,首先會爬取單一個頁面上的資料,接著會爬取下一個頁面的網頁資料。最後再修改程式,爬取該單一網頁至延伸至個內頁的資料。
單一網頁資料爬取
所謂單一網頁爬取,是指爬取的範圍僅限於單一頁面上的內容。
以此目標網站為例,我們要爬取的部分為頁面上的標題、摘要、更新日期以及內頁的連結。
尋找目標內容區塊
在此我們可以打開 Google Chrome的DevTools(可以從Chrome的主選單中選擇「更多工具 > 開發人員工具」或按下滑鼠右鍵單擊頁面元素,然後選擇「檢查」)來檢視HTML的結構,用以找尋目標區元素。
經檢視HTML的結構後,可以發現到框住目標內容區塊的最內層元素為 <ul class=”article-list”>
底下的 <li>
(如下圖)。
找出目標對應的XPATH規則
接下來,可以在DevTools最下方的位置,使用Cmd+F打開搜尋輸入方匡,尋找出xpath規則。
我們已知HTML的元素為<ul class=”article-list”>
底下的 <li>
(1的位置),在下方(2的位置)將它轉換為xpath表示:
//ul[@class="article-list"]/li
如果輸入的xpath正確的話,按下enter之後你會在HTML的元素的地方看到選定的元素變成黃色(1的位置),並且可以在右下方(3的位置)檢視一下符合這個xpath的數量,以本例來說,符合條件的元素有10筆(3的位置)。
接著,就可以透過response.xpath方法取得位置,並將它指定給變數articles:
articles = response.xpath('//ul[@class="article-list"]/li')
最後要把上面這一行寫在parse函式裡面:
def parse(self, response):
articles = response.xpath('//ul[@class="article-list"]/li')
這樣子就完成了一個目標定位。
取出各目標資料元素
接下來要開始取出目標內容區塊裡面的各個目標資料元素。
在articles 裡面包含著我們想要取得的目標資料,包括標題(title)、摘要(content)、更新日期(update_date)以及內頁的連結(link)。
我們一樣將它轉換為XPATH表示:
# 標題的XPATH
.//a/div[@class="article-list-txt"]/h3/text()
# 摘要的XPATH
.//a/div[@class="article-list-txt"]/p/text()
# 更新日期的XPATH
.//a/div[@class="article-list-txt"]//span[@class="update-date"]/text()
# 內頁的連結的XPATH
.//a/@href
其中,標題、摘要與更新日期的資料包夾在 <h3>
、<p>
與 <span>
的元素裡面,在這裡使用 text()
取得資料。
由於我們等一下要透過迴圈從articles開始向內取資料,在此要把response.xpath
改為article.xpath
title = article.xpath('.//a/div[@class="article-list-txt"]/h3/text()').get()content = article.xpath('.//a/div[@class="article-list-txt"]/p/text()').get()update_date = article.xpath('.//a/div[@class="article-list-txt"]//span[@class="update-date"]/text()').get()
而內頁的連結位置,則位在href屬性上,在這裡要使用 @href
取得資料。
link = article.xpath(".//a/@href").get()
for迴圈取出資料
使用for-in的迴圈將目標資料元素中的資料取出:
for article in articles:
link = article.xpath(".//a/@href").get()
title = article.xpath('.//a/div[@class="article-list-txt"]/h3/text()').get()
content = article.xpath('.//a/div[@class="article-list-txt"]/p/text()').get()
update_date = article.xpath('.//a/div[@class="article-list-txt"]//span[@class="update-date"]/text()').get()
yield回傳資料
最後使用yield回傳資料。yield是Python的關鍵字,類似函式中的return,只是回傳的是Generator。
yield {
'link':link,
'title':title,
'content':content,
'update_date':update_date
}
完成各項步驟後,將程式碼全部組合在一起,結果如下:
def parse(self, response):
articles = response.xpath('//ul[@class="article-list"]/li')
for article in articles:
link = article.xpath(".//a/@href").get()
title = article.xpath('.//a/div[@class="article-list-txt"]/h3/text()').get()
content = article.xpath('.//a/div[@class="article-list-txt"]/p/text()').get()
update_date = article.xpath('.//a/div[@class="article-list-txt"]//span[@class="update-date"]/text()').get()
yield {
'link':link,
'title':title,
'content':content,
'update_date':update_date
}
執行爬蟲程式:
完成爬蟲程式的撰寫後,就可以執行爬蟲程式。在這裡要輸入下面指令:
$ scrapy crawl advertimes
按下enter鍵執行,結果如下:
儲存資料
從上面的執行結果實在看不出什麼。我們可以把結果輸出存成檔案來觀察。在Scrapy crawl指令中,可以在後面加上「-o
」來指定輸出的檔案與格式。
CSV檔
$ scrapy crawl advertimes -o advertimes.csv
透過上面指令可以存成CSV檔,檔名為advertimes.csv
,檔名的部分可以自行命名。這個CSV檔會儲存在專案資料夾裡面。打開檔案就可以輕易的看到scrapy爬蟲取得的結果。如下圖:
JSON檔
除了儲存為CSV檔外,還可以選擇儲存為JSON檔案。
$ scrapy crawl advertimes -o advertimes.json
JSON檔案一樣會儲存在專案資料夾裡面。打開檔案就可以看到scrapy爬蟲取得的結果。如下圖:
處理編碼問題
可惜的是,上面儲存的結果裡面出現了人類無法閱讀的『亂碼』。這實際上是因為編碼的問題,在Scrapy爬蟲中要解決這個問題的方式很簡單,可以透過修改專案中的settings.py檔案來改善。
打開settings.py檔案,並且新增一項設定:
FEED_EXPORT_ENCODING="utf-8"
設定增加完畢後儲存檔案。刪除原來有亂碼的JSON檔案( advertimes.json
) 並重新執行一遍爬蟲指令:
$ scrapy crawl advertimes -o advertimes.json
結果,新產生的JSON檔案就可以正常顯示,沒有亂碼了。
以上是Scrapy爬蟲框架針對單一網頁的爬取方式,如果您曾經使用過其他爬蟲程式,應該會覺得透過Scrapy來處理資料會比較簡便。至於更多的網頁爬取細節包括如何爬取多個頁面,我們留待下一篇說明。