啟動爬蟲
在上一節中,我們已經創建好了我們的scrapy項目,看着這一大堆文件,想必很多人都會一臉懵逼,我們應該怎么啟動這個爬蟲呢?
既然我們采用cmd命令創建了scrapy爬蟲,那就得有始有終有逼格,我們仍然采用程序員的正統方式——cmd的方式運行它
scrapy crawl jobbole
當我們在cmd中輸入這條命令后,我們的爬蟲也就開始運行了。但是如果每次都需要這樣才能啟動,不僅費時費力,也難以在IDE中調試程序。面對這種情況,我們可以采取使用python來實現自動命令行的啟動。好吧,真香!
於是我們在我們的項目中創建一個main.py文件
編寫以下代碼
# Author :Albert Shen
# -*- coding: utf-8 -*-
from scrapy.cmdline import execute
import sys
import os
if __name__ == '__main__':
sys.path.append(os.path.dirname(os.path.abspath(__file__)))
execute(["scrapy", "crawl", "jobbole"])
運行main.py,我們就會發現,scrapy成功開始運行,並將運行結果輸出到了console窗口,此時我們也就可以充分利用IDE的優勢,進行便捷的調試與運行。
初嘗爬蟲
既然我們的爬蟲已經可以運行了,那么應該如何編寫邏輯才能爬取到我們想要的數據呢?
首先我們打一個斷點
此時大家注意response對象的text變量,看起來是否很像網頁的html代碼。為了確認這個猜測是否正確,我們可以將text變量的值復制出來,拷貝到一個html文件中,打開發現確實是目標網頁的html源代碼。
這是因為當程序開始運行,scrapy獲取網頁數據后,調用了此文件中的parse函數,同時將獲取到的數據傳遞給了resposne參數。這正是scrapy框架的強大之處,將前面一系列與目標網頁相關的操作進行了封裝,我們只需要關心怎么從網頁源代碼中獲得想要的信息即可,所以我們后續的操作將主要圍繞這response參數來進行。
如果大家嘗試一些其他網頁,可能會出現獲得的網頁與我們想要的網頁不同的情況,這多是因為目標網頁需要登錄驗證或采取了反爬蟲策略,這一部分我們將在后續的文章中涉及。
xpath
既然我們已經獲得了網頁的源代碼,那么我們應該怎么解析數據呢?可能細心的讀者會注意到response.text的值是一個字符串,那么采用正則表達式不失為一種可靠的方式。但是作為一個成熟的爬蟲框架,scrapy為我們提供了一種更加簡便准確的方式——xpath。將我們的jobbole.py文件修改為這樣
# -*- coding: utf-8 -*-
import scrapy
class JobboleSpider(scrapy.Spider):
name = 'jobbole'
allowed_domains = ['blog.jobbole.com']
start_urls = ['http://blog.jobbole.com/all-posts/']
def parse(self, response):
articles = response.xpath('//a[@class="archive-title"]/text()').extract()
print(articles)
pass
運行程序,打斷點調試,我們發現,articles變量是一個list,包含20個字符串,正好就是目標網頁的20篇文章的標題。通過一行即能實現精確的目標數據提取,正是依靠xpath。
在學習xpath之前,讀者最好能對前端,尤其是HTML語言有一定了解,至少需要知道一些基本的概念。
HTML語言是一種超級文本標記語言,與后端的C,java,python等不同,HTML不是編程語言,而是標記語言,是通過一系列標簽來描述網頁。如果對此沒有概念的讀者可以簡單的將其理解為HTML語言是通過一句句話告訴瀏覽器,首先我在這要放一段文字,然后要在這那一張圖片等等,類似於畫圖。
HTML標記標簽通常被稱為HTML標簽。是由尖括號<>包圍的關鍵字,如<html>,<h1></h1>等。標簽之間的部分被稱為元素,同時每個標簽也有屬性,例如
<a href="http://www.w3school.com.cn">This is a link</a>
其中<a></a>標簽表示這是一個鏈接,This is a link 是顯示給閱讀者的字符,href是它的一個屬性,表示目標網址是http://www.w3school.com.cn。真實的顯示效果如下圖所示
點擊它就能跳轉到目標網頁。
如果想要深入的了解HTML的知識,可以在w3school上進行學習:http://www.w3school.com.cn/
xpath正是基於此的。常用的xpath語法如下圖所示(來源:w3school)
w3school關於xpath的教程:http://www.w3school.com.cn/xpath/index.asp
舉一些例子
大家如果想要深入了解xpath,也建議到w3school進行進一步學習。如果對前端實在不熟悉的讀者,也可以跟着筆者這個系列的教程,相信經過一段時間的練習,也能夠熟練掌握相關知識。
有了上面的知識,我們來分析一下我們是怎么得到目標網頁的所有標題的呢?
在瀏覽器中打開目標網頁http://blog.jobbole.com/all-posts/,按f12(Chrome瀏覽器)打開開發者工具
1.我們可以在想要查看的元素處右擊,選擇“檢查”
2.在開發者攻擊中點擊2位置的圖標,然后點擊我們想要查看的元素
Chrome就會自動跳轉到目標元素的源代碼處。
<a class="archive-title" target="_blank" href="http://blog.jobbole.com/114331/" title="受 SQLite 多年青睞,C 語言到底好在哪兒?">受 SQLite 多年青睞,C 語言到底好在哪兒?</a>
目標元素幾個比較重要的信息為
1.這是一個<a></a> (鏈接)
2.目標元素包含多個屬性,其中一個屬性為class,值為archive-title,一個屬性為href,值為點擊這個標題將會跳轉的目標網頁的網址
3.包含一個屬性為title,其值與標簽之間的“元素”值相同。
articles = response.xpath('//a[@class="archive-title"]/text()').extract()
我們上述代碼中的 //a[@class="archive-title"] 表示取整個文檔中所有( // 表示整個文檔中的所有節點)包含class屬性(中括號[]表示對前面標簽的限制,如包含什么屬性),且屬性值為“archive-title”的a節點(標簽)。
我們可以搜索網頁的所有代碼,就會發現所有包含 archive-title 字符串的只有20處,正好是本頁所有文章的標題<a></a> 標簽的class屬性值,也就是說我們僅憑這一句話就精確地選到了我們想要的數據。
/text()表示我們想要獲得這些標簽的“元素”值(即標簽之間的內容,也就是會在網頁上顯示出來的內容),如果想要獲得標簽的某個屬性值,如href,則可以使用如下語句
response.xpath('//a[@class="archive-title"]/@href').extract()
因為我們取的是屬性,所以一定不要忘了@來表示屬性,如果沒有a,則會認為是目標a標簽下的href標簽,顯然是錯誤的。
extract()表示獲得 提取出來的數據的data變量,即我們指定的標簽中的內容。如果覺得這一句難以理解,讀者也可以將程序中的.extract()刪除,觀察結果。
彩蛋:在開發者工具中,右擊源代碼,我們可以選擇復制目標標簽的xpath。同理,由於動態網頁等原因,這種方式獲得的xpath可能與scrapy獲得的網頁不匹配。這種方式可以幫助大家更深入的理解xpath,但在后續的編程過程中,筆者還是建議大家自己進行分析。
As Albert says: 既然寫程序是為了偷懶,那寫程序的時候就不要偷懶了。
結語
在這一節中,我們了解了如何快捷地啟動scrapy,xpath基本語法,並嘗試進行了scrapy爬蟲的初次嘗試。在后面的章節中,我們將會對整篇網頁進行解析,並采用深度優先搜索遍歷jobbole的所有文章,解析數據,下載封面圖等。同時我們將使用到正則表達式以分析字符串來獲得我們想要的數據,由於篇幅限制,筆者將不會對正則表達式進行詳細介紹,建議大家提前了解一些正則表達式的基本知識。