網頁爬蟲--scrapy入門


本篇從實際出發,展示如何用網頁爬蟲。並介紹一個流行的爬蟲框架~


1. 網頁爬蟲的過程

所謂網頁爬蟲,就是模擬瀏覽器的行為訪問網站,從而獲得網頁信息的程序。正因為是程序,所以獲得網頁的速度可以輕易超過單身多年的手速:)。通常適用於需要大量網頁信息的場合。

爬取網頁的流程為:訪問初始url -> 獲得返回的網頁,從這個網頁中得到新的url並放入待爬隊列 -> 訪問新的url -> ...依次循環。整體上來看就是一個廣度優先的過程,當然,新的url也不一定非要從返回的網頁中獲得。

一個簡單的網頁爬蟲應該包括以下部分:

  1. 一個url隊列。我們的爬蟲從這個隊列中讀取url,並將新的url放入這個隊列。這里最重要的是判重。簡單的哈希就能達到判重的目的,但是為了節約空間(url的數量往往很多),一般使用bloomfilter的思想。bloomfilter與普通的哈希算法最大的不同就是bloomfilter只需要一個bit來表示某個元素是否存在,所以能節約空間。bloomfilter有一個小缺點,即准確率並不是百分百:判斷一個元素是不是已經存在時,已有的有很小的可能會判斷為不存在,但是沒有的元素一定會判斷為不存在。
  2. 網頁爬取模塊。需要能模擬瀏覽器發送請求。
  3. 網頁分析模塊。爬下來的是網頁源碼,可以用正則或者其他方法提取我們需要的信息。
  4. 新的url生成模塊。生成新的url,放入隊列。

那么,最簡單的爬蟲就可以這么寫:

import Queue

start_url = "http://www.cnblogs.com/rubinorth"
url_queue = Queue.Queue()  # url隊列
url_queue.put(start_url) 

bloomfilter.put(start_url)
#### 一直循環到隊列為空 ####
while(True):
    if url_queue.size() > 0:
        current_url = url_queue.get()  # 隊首的url
        page = crawl(current_url)  # crawl為網頁爬取模塊,page是爬到的網頁源代碼
        next_urls = deal_page(page)  # deal_page為網頁分析模塊,next_urls是新的一些url
        
        for next_url in next_urls: 
            if not bloomfilter.has(next_url):  # 判重     
                bloomfilter.put(next_url)
                url_queue.put(next_url)
    else:
        break

2. 為什么選用scrapy

scrapy是目前一個比較流行的爬蟲框架,其基本原理與上面的爬蟲是一樣的,但是它提供了很多便利的功能。

首先,先簡要介紹一下scrapy各個模塊之間的關系和整個框架運行的流程。是時候祭出那張scrapy的經典圖了:
scrapy
從這張圖上看,scrapy包含了以下模塊:

  1. scrapy engine,主引擎。在處理數據流時負責管理整個系統,同時各種事件的觸發也由其負責。
  2. spider,即我們的爬蟲。主要的爬蟲代碼都在這部分中,包括發起請求,處理返回的網頁等等。
  3. spider middleware,spider中間件。中間件的一種,主要工作對spider發送的request做一些處理。
  4. scheduler,調度器。上面說到的url隊列就是調度器在管理,一方面接收spider發送的request請求,放入隊列中;另一方面會從隊首取出request交由downloader去下載網頁。
  5. downloader,下載器。將網頁的html源碼下載下來供之后的網頁分析和信息提取。
  6. downloader middleware,下載器中間件。中間件的一種,在下在網頁之前和之后都會運行,可以用來設置發送請求的header,cookies,代理ip以及處理一些錯誤返回的情況。
  7. item pipeline, 管道。一個網頁被爬取下來並解析之后,其后續的信息存儲之類的工作在pipeline中進行。當然也可以直接在spider中完成這些工作,但在pipeline中完成則顯得整個項目結構清晰。

上面列出的里面spider,pipeline需要自己寫,兩種middleware需要的話可以自己添加自己寫的。

光介紹給人感覺比較空洞,那下面就讓我們來使用scrapy實現一個簡單的爬蟲吧。


3. scrapy實現爬蟲

scrapy createproject cnblog_project

使用上面的命令創建一個scrapy工程之后,首先我們要寫的是spider。

class CnblogSpider(Spider):
    name = 'cnblog_spider'  # 爬蟲名字
    allowed_domain = ['cnblogs.com']  # 允許的domain

    def __init__(self):
        self.start_urls = ['http://www.cnblogs.com/rubinorth']

    def start_requests(self):
        return [Request(url, callback=self.parse_page) for url in self.start_urls]

    # 分析爬取的頁面並構造下一個頁面的請求
    def parse_page(self, response):
        logging.info("parse : " + response.url)

        sel = Selector(response)
        item = CnblogItem()

        # 提取頁面內容
        item['name'] = sel.xpath("//a[@id='Header1_HeaderTitle']/text()").extract()[0]
        yield item
        # 下一個頁面的請求
        new_url = get_new_url(response.body)  # 根據源碼分析出新的鏈接,需自己實現
        yield Request(new_url, callback=self.parse_page)

上面是一個簡單的爬蟲,start_urls是初始的url集合(上面只有一個),start_requests則根據start_urls構造Request,並交給調度器。parse_page中,response是返回的頁面的源碼;CnblogItem是scrapy提供的item組件,方便結構化地提取源碼中的數據,而yield item則會將這個item交給管道;yield Request(new_url, callback=self.parse_page)則會發送一個新的Request,發起下一輪的爬取。
items.py中只要這么寫:

class CnblogItem(scrapy.Item):
    name = scrapy.Field()

接着,我們需要寫pipelines.py

class CnblogPipeline(object):
    def process_item(self, item, spider):
        print item['name']
        return item

每個pipeline都必須有process_item這個方法。上面我們只是簡單地打印出了name。return item是考慮到可能有多個pipeline(return了之后可以讓其他pipeline處理)。
最后,只需要修改settings.py即可:

...
ITEM_PIPELINES = {
   'yelp_project.pipelines.CnblogPipeline': 304,
}
...

需要在setting中打開自己的pipeline。
好了,一個簡單的爬蟲就這么寫完了。注意我們並沒有用到中間件,也不需要寫自己的中間件。
最后, 命令行運行:

scrapy crawl cnblog_spider

參考資料

如何入門python爬蟲

轉載請注明出處:http://www.cnblogs.com/rubinorth/


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM