想要開發Python網頁爬蟲的朋友,都會知道定位元素(Element)是一個非常重要的動作,在[Scrapy3教學]如何有效利用Scrapy框架建立網頁爬蟲看這篇就懂文章中,使用了Scrapy框架的bs4模組(Module),也就是BeautifulSoup的語法,來示範爬取目標網頁中的HTML元素(Element)。
但事實上,Scrapy框架本身就有提供自己的定位元素(Element)方法(Method),包含CSS與XPath兩種,而本文將延續使用[Scrapy3教學]如何有效利用Scrapy框架建立網頁爬蟲看這篇就懂文章的INSIDE硬塞的網路趨勢觀察網站-AI新聞為例,先來和大家分享在Scrapy框架中,如何利用CSS的定位元素(Element)方法(Method),爬取想要的網頁內容,重點包含:
- Scrapy CSS方法取得單一元素值
- Scrapy CSS方法取得多個元素值
- Scrapy CSS方法取得子元素值
- Scrapy CSS方法取得元素屬性值
一、Scrapy CSS方法取得單一元素值
CSS(Cascading Style Sheets)階層樣式表相信大家都不陌生,可以自訂樣式的類別來裝飾網頁,像是字體顏色、粗體等,所以在利用Scrapy框架開發網頁爬蟲時,也就能夠利用CSS樣式類別,來定位想要爬取的網頁元素(Element)。
前往INSIDE硬塞的網路趨勢觀察網站-AI新聞,在文章標題的地方,點擊滑鼠右鍵,選擇檢查,可以看到它的CSS樣式類別如下範例:
假設想要在Scrapy框架中,利用CSS樣式類別來取得網頁的單一元素值,也就是單一文章的標題,就可以在spiders/inside.py的parse()方法(Method)中,使用css()方法(Method)來定位單一元素(Element),如下範例:
import scrapy class InsideSpider(scrapy.Spider): name = 'inside' allowed_domains = ['www.inside.com.tw'] start_urls = ['https://www.inside.com.tw/tag/ai'] def parse(self, response): title = response.css("a.js-auto_break_title::text").get() print(title)
接著,利用以下的指令執行inside網頁爬蟲:
$ scrapy crawl inside
執行結果
烘焙王!Google AI 未烤先猜你的配方會變甚麼食物,更創造混種甜點「breakie」、「cakie」
以上範例第10行,response就是Scrapy框架請求後的回應結果,接著,呼叫css()方法,傳入所要定位的HTML標籤<a>,點的後面加上它的CSS樣式類別,由於要取得元素(Element)的文字,所以在加上「::text」關鍵字,最後,呼get()方法(Method)取得單一元素(Element)。
二、Scrapy CSS方法取得多個元素值
而在Scrapy框架中,想要爬取網頁多個元素值,則呼叫getall()方法(Method)即可,如下範例:
import scrapy class InsideSpider(scrapy.Spider): name = 'inside' allowed_domains = ['www.inside.com.tw'] start_urls = ['https://www.inside.com.tw/tag/ai'] def parse(self, response): titles = response.css("a.js-auto_break_title::text").getall() print(titles)
執行結果
[ '烘焙王!Google AI 未烤先猜你的配方會變甚麼食物,更創造混種甜點「breakie」、「cakie」', '【Wired硬塞】你知道銀河系的歷史,已被重新改寫了嗎?', '最高明的攬客工具:電商、實體業者通用的中租零卡,為消費收付重新定義', '祖克柏放棄新年願望!2020 過的好嗎?盤點臉書滿城風雨的一年', 'LINE Clova 人工智慧應用確定登台,數位身分識別、智慧電話接聽服務導入應用', '跨界結盟、深化生態圈、會員經濟三策略,PChome 24h購物2021持續壯大電商藍圖', '擊敗萬人!交大 CGI 學生勇奪 AWS AI 自駕車世界冠軍季軍', '【Arm 專欄】最新 AI 調查報告: 一窺新冠疫情下企業對人工智慧的部署與管理', ... ]
可以看到getall()方法(Method)回傳的是一個串列(List),包含了所有樣式類別為「js-auto_break_title」的<a>標籤文字,接下來,利用迴圈即可取得其中的文章標題,如下範例:
import scrapy class InsideSpider(scrapy.Spider): name = 'inside' allowed_domains = ['www.inside.com.tw'] start_urls = ['https://www.inside.com.tw/tag/ai'] def parse(self, response): titles = response.css("a.js-auto_break_title::text").getall() for title in titles: print(title)
執行結果
烘焙王!Google AI 未烤先猜你的配方會變甚麼食物,更創造混種甜點「breakie」、「cakie」 【Wired硬塞】你知道銀河系的歷史,已被重新改寫了嗎? 最高明的攬客工具:電商、實體業者通用的中租零卡,為消費收付重新定義 祖克柏放棄新年願望!2020 過的好嗎?盤點臉書滿城風雨的一年 LINE Clova 人工智慧應用確定登台,數位身分識別、智慧電話接聽服務導入應用 跨界結盟、深化生態圈、會員經濟三策略,PChome 24h購物2021持續壯大電商藍圖 擊敗萬人!交大 CGI 學生勇奪 AWS AI 自駕車世界冠軍季軍 【Arm 專欄】最新 AI 調查報告: 一窺新冠疫情下企業對人工智慧的部署與管理 ...
本文所使用的是Scrapy框架最新版的get()及getall()方法(Method),大家可能也有看過其它的教學文章使用舊的extract_first()及extract()方法(Method),依據官方文件的說明,兩者皆支援使用,不過get()及getall()新方法(Method)讓程式碼兼具簡潔與可讀性,如下圖:
三、Scrapy CSS方法取得子元素值
在實務上利用Scrapy框架開發Python網頁爬蟲時,並不是每次想要爬取的網頁元素(Element)都會有CSS樣式類別可以定位,這時候,就會需要透過上層的父元素往下定位子元素。
假設INSIDE硬塞的網路趨勢觀察網站-AI新聞的文章標題<a>標籤沒有「js-auto_break_title」CSS樣式類別,而想要爬取<a>標籤的文字內容,該如何達成呢?如下圖:
這時候,就會需要在Scrapy框架中利用CSS樣式類別先定位到<h3>標籤,接著,再取得其下的子元素<a>標籤,如下範例:import scrapy class InsideSpider(scrapy.Spider): name = 'inside' allowed_domains = ['www.inside.com.tw'] start_urls = ['https://www.inside.com.tw/tag/ai'] def parse(self, response): titles = response.css("h3.post_title a::text").getall() for title in titles: print(title)
執行結果
烘焙王!Google AI 未烤先猜你的配方會變甚麼食物,更創造混種甜點「breakie」、「cakie」 【Wired硬塞】你知道銀河系的歷史,已被重新改寫了嗎? 最高明的攬客工具:電商、實體業者通用的中租零卡,為消費收付重新定義 祖克柏放棄新年願望!2020 過的好嗎?盤點臉書滿城風雨的一年 LINE Clova 人工智慧應用確定登台,數位身分識別、智慧電話接聽服務導入應用 跨界結盟、深化生態圈、會員經濟三策略,PChome 24h購物2021持續壯大電商藍圖 擊敗萬人!交大 CGI 學生勇奪 AWS AI 自駕車世界冠軍季軍 【Arm 專欄】最新 AI 調查報告: 一窺新冠疫情下企業對人工智慧的部署與管理
在範例中第10行,利用「post_title」CSS樣式類別定位到<h3>標籤後,接著一個空白,加上<a>標籤,意思就是取得<h3>標籤下的所有<a>標籤,由於要取得其中的文字,所以加上「::text」。
四、Scrapy CSS方法取得元素屬性值
此外,在開發Python網頁爬蟲時,也有機會爬取元素的屬性值(Attribute),舉例來說,最常見的就是<a>標籤的href屬性值(Attribute),也就是文章的連結網址,這時候只需要將「::text」關鍵字,修改為「::attr(屬性名稱)」即可,如下範例:
import scrapy class InsideSpider(scrapy.Spider): name = 'inside' allowed_domains = ['www.inside.com.tw'] start_urls = ['https://www.inside.com.tw/tag/ai'] def parse(self, response): urls = response.css("a.js-auto_break_title::attr(href)").getall() for url in urls: print(url)
執行結果
https://www.inside.com.tw/article/22196-google-ai-concocts-breakie-and-cakie-hybrid-baked-goods https://www.inside.com.tw/article/22194-The-Milky-Way-Gets-a-New-Origin-Story https://www.inside.com.tw/article/21978- https://www.inside.com.tw/article/22057-Mark-Zuckerberg-and-fb-2020 https://www.inside.com.tw/article/21982-LINE-Clova-TECHPULSE-2020 https://www.inside.com.tw/article/22090-pchome-1229 https://www.inside.com.tw/article/21962-aws-deepracer-league-announces-2020-championship-cup-winner-po-chun-hsu-of-taiwan https://www.inside.com.tw/article/21947-Arm-AI-report
五、小結
本文搭配實際的網站,示範Scrapy框架利用css()方法(Method)來定位網頁元素的基本用法,重點摘要如下:
- 取得單一元素值呼叫get()方法(Method)
- 取得多個元素值呼叫getall()方法(Method)
- 取得文字內容,加上「::text」關鍵字
- 取得屬性值則加上「::attr(屬性名稱)」關鍵字
希望對於想要學習Scrapy框架的朋友有所幫助,在下一篇文章中,將會來和大家分享另一個定位元素的方法(Method)-XPath,如果有任何的問題或想法,歡迎在底下留言和我交流分享唷 :)
如果您喜歡我的文章,請幫我按五下Like(使用Google或Facebook帳號免費註冊),支持我創作教學文章,回饋由LikeCoin基金會出資,完全不會花到錢,感謝大家。
這絕對是我看過最棒的Scrapy教學系列文章!以前不知道看了多少中、英文的Scrapy教學文章,總是落落長的程式碼和極簡略的說明;花了很長的時間閱讀,結果只學會了如何建立Scrapy專案而已。唯有本系列的教學,以最精簡的程式碼和最詳盡的解說,讓我第一次覺得自己真正學會了基本的Scrapy爬蟲技巧!
回覆刪除