使用Scrapy構建一個網絡爬蟲

分類:技術 時間:2017-01-13

記得n年前項目需要一個靈活的爬蟲工具,就組織了一個小團隊用Java實現了一個爬蟲框架,可以根據目標網站的結構、地址和需要的內容,做簡單的配置開發,即可實現特定網站的爬蟲功能。因為要考慮到各種特殊情形,開發還耗了不少人力。后來發現了Python下有這個Scrapy工具,瞬間覺得之前做的事情都白費了。對于一個普通的網絡爬蟲功能,Scrapy完全勝任,并把很多復雜的編程都包裝好了。本文會介紹如何Scrapy構建一個簡單的網絡爬蟲。

一個基本的爬蟲工具,它應該具備以下幾個功能:

  • 通過HTTP(S)請求,下載網頁信息
  • 解析網頁,抓取需要的內容
  • 保存內容
  • 從現有頁面中找到有效鏈接,從而繼續抓取下一個網頁

我們來看下Scrapy怎么做到這些功能的。首先準備Scrapy環境,你需要安裝Python(本文使用v2.7)和pip,然后用pip來安裝lxml和scrapy。個人強烈建議使用virtualenv來安裝環境,這樣不同的項目之間不會沖突。詳細步驟這里就不贅述了。對于Mac用戶要注意,當使用pip安裝lxml時,會出現類似于的下面錯誤:

Error: #include “xml/xmlversion.h” not found

解決這個問題,你需要先安裝Xcode的command line tools,具體的方法是在命令行執行下面的命令即可。

$ xcode-select --install

環境安裝好之后,我們來用Scrapy實現一個簡單的爬蟲,抓取本博客網站的文章標題,地址和摘要。

  1. 創建工程
$ scrapystartprojectmy_crawler

該命令會在當前目錄下創建一個名為”my_crawler”的工程,工程的目錄結構如下

my_crawler
|- my_crawler
||- spiders
|||- __init__.py
||- items.py
||- pipelines.py
||- setting.py
|- scrapy.cfg
  1. 設置待抓取內容的字段,本例中就是文章的標題,地址和摘要

修改”items.py”文件,在”MyCrawlerItem”類中加上如下代碼:

# -*- coding: utf-8 -*-
import scrapy
 
class MyCrawlerItem(scrapy.Item):
title = scrapy.Field()# 文章標題
url = scrapy.Field()# 文章地址
summary = scrapy.Field()# 文章摘要
pass
  1. 編寫網頁解析代碼

在”my_crawler/spiders”目錄下,創建一個名為”crawl_spider.py”文件(文件名可以任意取)。代碼如下

# -*- coding: utf-8 -*-
import scrapy
from scrapy.linkextractorsimport LinkExtractor
from scrapy.spidersimport CrawlSpider, Rule
 
from my_crawler.itemsimport MyCrawlerItem
 
class MyCrawlSpider(CrawlSpider):
name = 'my_crawler'# Spider名,必須唯一,執行爬蟲命令時使用
allowed_domains = ['bjhee.com']# 限定允許爬的域名,可設置多個
start_urls = [
quot;http://www.bjhee.comquot;,# 種子URL,可設置多個
]
 
rules = (# 對應特定URL,設置解析函數,可設置多個
Rule(LinkExtractor(allow=r'/page/[0-9] '),# 指定允許繼續爬取的URL格式,支持正則
callback='parse_item',# 用于解析網頁的回調函數名
follow=True
),
)
 
def parse_item(self, response):
# 通過XPath獲取Dom元素
articles = response.xpath('//*[@id=quot;mainquot;]/ul/li')
 
for articlein articles:
item = MyCrawlerItem()
item['title'] = article.xpath('h3[@class=quot;entry-titlequot;]/a/text()').extract()[0]
item['url'] = article.xpath('h3[@class=quot;entry-titlequot;]/a/@href').extract()[0]
item['summary'] = article.xpath('div[2]/p/text()').extract()[0]
yield item

對于XPath不熟悉的朋友,可以通過Chrome的debug工具獲取元素的XPath。

  1. 讓我們測試下爬蟲的效果

在命令行中輸入:

$ scrapycrawlmy_crawler

注意,這里的”my_crawler”就是你在”crawl_spider.py”文件中起的Spider名。

沒過幾秒鐘,你就會看到要抓取的字段內容打印在控制臺上了。就是這么神奇!Scrapy將HTTP(S)請求,內容下載,待抓取和已抓取的URL隊列的管理都封裝好了。你的主要工作基本上就是設置URL規則及編寫解析的方法。

我們將抓取的內容保存為JSON文件:

$ scrapycrawlmy_crawler -o my_crawler.json -t json

你可以在當前目錄下,找到文件”my_crawler.json”,里面保存的就是我們要抓取的字段信息。(參數”-t json”可以省去)

  1. 將結果保存到數據庫

這里我們采用MongoDB,你需要先安裝Python的MongoDB庫”pymongo”。編輯”my_crawler”目錄下的”pipelines.py”文件,在”MyCrawlerPipeline”類中加上如下代碼:

# -*- coding: utf-8 -*-
import pymongo
 
from scrapy.confimport settings
from scrapy.exceptions import DropItem
 
class MyCrawlerPipeline(object):
def __init__(self):
# 設置MongoDB連接
connection = pymongo.Connection(
settings['MONGO_SERVER'],
settings['MONGO_PORT']
)
db = connection[settings['MONGO_DB']]
self.collection = db[settings['MONGO_COLLECTION']]
 
# 處理每個被抓取的MyCrawlerItem項
def process_item(self, item, spider):
valid = True
for datain item:
if not data:# 過濾掉存在空字段的項
valid = False
raise DropItem(quot;Missing {0}!quot;.format(data))
 
if valid:
# 也可以用self.collection.insert(dict(item)),使用upsert可以防止重復項
self.collection.update({'url': item['url']}, dict(item), upsert=True)
 
return item

再打開”my_crawler”目錄下的”settings.py”文件,在文件末尾加上pipeline的設置:

ITEM_PIPELINES = {
'my_crawler.pipelines.MyCrawlerPipeline': 300,# 設置Pipeline,可以多個,值為執行優先級
}
 
# MongoDB連接信息
MONGO_SERVER = 'localhost'
MONGO_PORT = 27017
MONGO_DB = 'bjhee'
MONGO_COLLECTION = 'articles'
 
DOWNLOAD_DELAY=2# 如果網絡慢,可以適當加些延遲,單位是秒
  1. 執行爬蟲
$ scrapycrawlmy_crawler

別忘了啟動MongoDB并創建”bjhee”數據庫哦。現在你可以在MongoDB里查詢到記錄了。

總結下,使用Scrapy來構建一個網絡爬蟲,你需要做的就是:

  • “items.py”中定義爬取字段
  • 在”spiders”目錄下創建你的爬蟲,編寫解析函數和規則
  • “pipelines.py”中對爬取后的結果做處理
  • “settings.py”設置必要的參數

其他的事情,Scrapy都幫你做了。下圖就是Scrapy具體工作的流程。怎么樣?開始寫一個自己的爬蟲吧。

本例中的代碼可以在這里下載。


Tags: Scrapy

文章來源:http://python.jobbole.com/87243/


ads
ads

相關文章
ads

相關文章

ad