Python下用Scrapy和MongoDB構建爬蟲系統(1)

木羊同學發表於2015-04-24

這篇文章將根據真實的兼職需求編寫一個爬蟲,使用者想要一個Python程式從Stack Overflow抓取資料,獲取新的問題(問題標題和URL)。抓取的資料應當存入MongoDB。值得注意的是,Stack Overflow已經提供了可用於讀取同樣資料的API。但是使用者想要一個爬蟲,那就給他一個爬蟲。

像往常一樣,在開始任何抓取工作前,一定要先檢視該網站的使用/服務條款,要尊重 robots.txt 檔案。抓取行為應該遵守道德,不要在很短時間內發起大量請求,從而導致網站遭受泛洪攻擊。對待那些你要抓取的網站,要像對待自己的一樣。

安裝

我們需要Scrapy庫(v0.24.4),以及用於在MongoDB中儲存資料的PyMongo庫(v2.7.2)。同樣需要安裝MongoDB。

Scrapy

如果使用OSX或某種Linux,使用pip安裝Scrapy(啟用命令列):

如果使用Windows的機器,你需要手動安裝一堆依賴庫(木羊吐槽:Win下也是有pip的po主你不要黑她,經測可以用上面命令直接安裝成功)。請參考官方文件詳細說明以及我建立的Youtube視訊。

一旦Scrapy安裝完畢,可在Python命令列中使用這個命令驗證:

如果沒有出錯,安裝就完成了。

PyMongo

下一步,使用pip安裝PyMongo:

現在可以開始構建爬蟲了。

Scrapy工程

先建立一個新的Scrapy工程:

這條命令建立了許多檔案和資料夾,其中包含一套有助於你快速開始的基本模板:

提取資料

items.py檔案用於定義儲存“容器”,用來儲存將要抓取的資料。

StackItem()類繼承自Item (文件),主要包含一些Scrapy已經為我們建立好的預定義物件:

新增一些想要收集的項。使用者想要每條問題的標題和URL。那麼,照這樣更新items.py:

建立蜘蛛

在“spiders”目錄下建立一個名為stack_spider.py的檔案。這裡是見證奇蹟發生的地方—-比如在這裡告訴Scrapy怎麼去找到我們想要的指定資料。正如你想的那樣,對於每一個獨立的網頁,stack_spider.py都是不同的。

我們從定義一個類開始,這個類繼承Scrapy的Spider,並新增一些必須的屬性:

最初一些變數的含義很容易理解(文件):

  • 定義蜘蛛的名字。
  • allowed_domains 包含構成許可域的基礎URL,供蜘蛛去爬。
  • start_urls 是一個URL列表,蜘蛛從這裡開始爬。蜘蛛從start_urls中的URL下載資料,所有後續的URL將從這些資料中獲取。

XPath選擇器

接下來,Scrapy使用XPath選擇器在一個網站上提取資料。也就是說,我們可以通過一個給定的XPath選擇HTML資料的特定部分。正如Scrapy所稱,“XPath是一種選擇XML節點的語言,也可以用於HTML。”

使用Chrome的開發者工具,可以很容易找到一個特定的Xpath。簡單地檢查一個特定的HTML元素,複製XPath,然後修改(如有需要)。

開發者工具同時為使用者提供在JavaScript控制檯測試XPath選擇器的功能,使用$x,如$x("//img"):

繼續,通過定義的XPath告訴Scrapy去哪裡尋找資訊。在Chrom中導航至Stack Overflow網址,尋找XPath選擇器。

右鍵點選第一條問題,選擇“插入元素”:

現在從<div class="summary">, //*[@id="question-summary-27624141"]/div[2]中抓取XPath,然後在JavaScript控制檯測試它:

也許你會說,這隻選擇了一條問題。現在需要改變XPath去抓取所有的問題。有什麼想法?很簡單://div[@class="summary"]/h3

什麼意思呢?本質上,這條XPath是說:抓取<div>的子樹中所有這一類<h3>元素的總集。在JavaScript控制檯中測試XPath。

請注意我們不會使用Chrome開發者工具的實際輸出。在大多數案例中,這些輸出僅僅是一個參考,便於直接找到能用的XPath。

現在更新stack_spider.py指令碼:

提取資料

我們仍然需要解析和抓取想要的資料,它符合<div class="summary"&gt<h3&gt。繼續,像這樣更新stack_spider.py:

我們將遍歷問題,從抓取的資料中分配標題和URL的值。一定要利用Chrome開發者工具的JavaScript控制檯測試XPath的選擇器,例如$x('//div[@class="summary"]/h3/a[@class="question-hyperlink"]/text()')$x('//div[@class="summary"]/h3/a[@class="question-hyperlink"]/@href')

測試

準備好第一次測試了嗎?只要簡單地在“stack”目錄中執行下面命令:

隨著Scrapy堆疊跟蹤,你應該看到50條問題的標題和URL輸出。你可以用下面這條小命令輸出一個JSON檔案:

我們已經基於要尋找的資料實現了爬蟲。現在需要將抓取的資料存入MongoDB。

在MongoDB中儲存資料

每當有一項返回,我們想驗證資料,然後新增進一個Mongo集合。

第一步是建立一個我們計劃用來儲存所有抓取資料的資料庫。開啟settings.py,指定管道然後加入資料庫設定:

管道管理

我們建立了爬蟲去抓取和解析HTML,而且已經設定了資料庫配置。現在要在pipelines.py中通過一個管道連線兩個部分。

連線資料庫

首先,讓我們定義一個函式去連線資料庫:

這裡,我們建立一個類,MongoDBPipeline(),我們有一個建構函式初始化類,它定義Mongo的設定然後連線資料庫。

處理資料

下一步,我們需要定義一個函式去處理被解析的資料:

我們建立一個資料庫連線,解包資料,然後將它存入資料庫。現在再測試一次!

測試

再次,在“stack”目錄下執行下面命令:

萬歲!我們已經成功將我們爬下了的資料存入資料庫:

總結

這是一個用Scrapy爬取網頁的簡單示例。真實兼職工作需要能跟蹤分頁連結的指令碼,用CrawlSpider(文件)抓取每一個頁面,非常容易實現。自己動手實現下,在下面Github倉庫連結中寫一個評論,快速檢視程式碼。需要幫助?從這個指令碼開始,它已經很接近完成了。然後檢視第二部分,它包含完整的解決方案。

你可以從Github repo中下載完整的程式碼。如果有問題請跟貼評論。謝謝閱讀!

新年快樂

相關文章