Scrapy 入門學習筆記(2) -- xpath 與 css 解析以及解析網頁樣本

來源:互聯網
上載者:User

最近學慣用 Scrapy 架構寫爬蟲,簡單來說爬蟲就是從網上抓取網頁,解析網頁,然後進行資料的儲存與分析,將從網頁的解析到資料的轉換儲存。將學習過程中用到的解析技術,Scrapy 的各個模組使用與進階到分布式爬蟲學到的知識點、遇到的問題以及解決方案記錄於此,以作總結與備忘,也希望對需要的同學有所協助。

本篇主要講解 xpath 、css 解析網頁的文法以及在 Scrapy 中的使用方式 一. xpath 簡介與文法概要

xpath 是 w3c 的一種標準。簡單來說就是可以讓我們以路徑的形式訪問 html 網頁中的各個元素。其中最主要的兩個 為 // 與 /。前者代表 路徑下的所有元素, 後者代表路徑下的子項目。具體文法如下: 基本文法:

question      # 選取所有 question 元素的所有子節點/question     #選取根項目 questionquestion/a    # 選取 question 元素下所有為 a 的子項目//div         # 選取所有的 div 元素,不論其出現在文檔的任何地方question//div # 選取 question 元素下所有的 div 後代元素 (/ 選取的是直接子項目,這裡是所有的後代元素)question//span/text() #選取 question 元素下所有 span 元素中的文本值question//a/@href     #選取 question 元素下所有 a 元素中的 href 屬性值。 @ 後面可以是任意屬性名稱,均可以取到值
帶有限定性質的文法
/question/div[1]        # 選取 question 的第一個 div 子項目。 注意這裡第一個是從索引 1 開始的/question/div[last()]   # 選取 question 第最後一個 div 子項目/question/div[last()-1] # 選取 question 的倒數第二個 div 子項目//div[@lang]            # 選取所有擁有lang 屬性的 div 元素//div[@lang='eng']      # 選取所有 lang 屬性為 eng 的 div 元素
其他文法補充
/div/*    # 選取屬於 div 元素的所有子節點//*       # 選取所有元素//div/a | //div/p #選 取所有 div 元素的 a 元素或者 p 元素//span | //input  # 選取文檔中所有的 span 和 input 元素
二. css 文法概要

熟悉前端的同學對 css 選取器一定不會陌生,比如 jquery 中通過各種 css 選取器文法進行 DOM 操作等。這裡對其文法進行簡要的總結,便於複習。 基本查詢文法

 *        # 選取所有節點#title    # 選取 id 為 title 的元素.col-md   # 選取所有 class 包含 col-md 的元素li a      # 選取所有 li 下的 a 元素ul + p    # 選取 ul 後面的第一個 p 元素div#title > ul   # 選取 id 為 title 的 div 的第一個 ul 子項目ul ~ p    # 選取 與 url 相鄰的所有 p 元素span#title ::text  # 選取 id 為 title 的 span 元素的文本值a.link::attr(href) # 選取 class 為 link 的 a 元素的 href 屬性值
屬性相關查詢文法
a[title]  # 選取所有有 title 屬性的 a 元素a[href='http://stackoverflow.com/'] # 選取所有 href 屬性為 http://stackoverflow.com/ 的 a 元素a[href*="stackoverflow"] # 選取所有 href 屬性包含 stackoverflow 的 a 元素a[href^='https'] # 選取所有 href 屬性值以 https 開頭的 a 元素a[href$='.jpg']  # 選取所有 href 屬性值以 .jpg 為結尾的 a 元素input[type=radio]:checked # 選擇選中的 radio 的元素
其他文法
div:not(.title)   # 選取所有 class 不是 title 的 div 元素li:nth-child(3) # 選取第三個元素tr:nth-child(2n) # 第偶數個元素
三. Selector 文法簡介 以及 StackoverFlow 問題列表解析樣本

介紹完了上面的解析文法,下面來具體看一下在 Scrapy 中的使用。

Scrapy 提供了 Selector 類來對網頁進行,它可以接收一段 HTML 程式碼進行構建,我們的 parse 方法中傳遞迴來的 response 是一個 HTMLResponse 對象,它內建了兩個方法 css() 和 xpath() 方法使我們可以方便的使用上面提高的兩種方法做解析.

通過 css() 或者 xpath() 解析返回的是一個 SelectorList 對象,為了擷取到其中的元素或者文本、屬性值,可以使用 extract() 或者 extract_first() 方法來進行擷取。extract_first() 方法在沒有值的時候返回為 None, 如果直接使用索引 0 進行擷取會引發錯誤,因此推薦前者。

下面我們使用這兩種方式來對 StackoverFlow 的問題列表進行解析,擷取到一個問題中的資料。

其問題介面和原始碼如下:

問題清單項目

列表原始碼

某一個問題的原始碼

可以看到,問題列表位於 id 為 question 的 div 元素下,每個問題布局用 class=question-summary 表示,後面的 id 用來標識每一個問題,可以擷取之後與網域名稱進行拼接訪問到具體的問題詳情介面。下面我們就圖中標註的標題、投票數,查看人數、回答人數以及標籤進行解析。 tip: 這裡為了距離分別使用了 xpath 和 css 兩種方式,但實際情況一般都是組合使用來達到最簡潔的解析。官方文檔建議在使用 class 進行解析時要用 css 解析方式。 css 解析

def parse_by_css(self, response):       '''       每個網頁中有 50 個問題,遍曆解析後儲存到 mongoDB 資料庫中       :param response:       :return:       '''       questions = response.css('div.question-summary')       for question in questions:           # 投票的數量是在 class=vote 的 div 下的 strong 中, css 通過 ::text 或者 ::attr(屬性名稱)           # 的方式來擷取文本或者某一個屬性值,因為最多隻有一個值,所以直接使用 extract_first() 來擷取到文本值即可           question_votes = question.css('.votes strong::text').extract_first()           # 標題是在 class=question-hyperlink 的 a 元素中           question_title = question.css("a.question-hyperlink::text").extract_first()           # 位於 class 為 answered 的 div 下的 strong 元素下           question_answers = question.css('.answered strong::text').extract_first()           # class 為 views 元素裡面的 title 屬性值           question_views = question.css('.views::attr(title)').extract_first()           # class 為 tags 的 div 元素下 所有 a 元素下的文本值,因為可能有多個標籤,所以使用 extract() 方法,返回一個 tag 文本組成的 list           tags = question.css('.tags a::text').extract()           pass
xpath 解析
# 元素解釋和上面的 css 解析程式一直,這裡只列出代碼不作贅述def parse_by_xpath(self, response):      questions = response.xpath("//div[@class='question-summary']")      for question in questions:          question_votes = question.xpath(".//div[@class='votes']//strong/text()").extract_first()          question_title = question.xpath(".//a[@class='question-hyperlink']/text()").extract_first()          question_answers = question.xpath(".//div[ contains(@class, 'answered')]/strong/text()").extract_first()          question_views = question.xpath(".//div[contains(@class, 'views')]/@title").extract_first()          tags = question.xpath(".//div[contains(@class, 'tags')]/a/text()").extract()          pass

解析到的結果如下:

可以看到資料都在裡面了,具體的解釋都在注釋裡面了,關於 Selector 的更詳細文法可以參閱 Scrapy 的官方文檔。本篇就簡要介紹到這裡,資料已經解析出來了,下一步就需要封裝為 Item 進行傳輸與處理了,下一篇將介紹 Item 的相關內容。包括建立與屬性,Item Loader 機制以及對資料進行過濾,處理的相關方法等。

相關文章

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.