概述
在上一篇文章《爬蟲學習之一個簡單的網路爬蟲》中我們對爬蟲的概念有了一個初步的認識,並且通過Python的一些第三方庫很方便的提取了我們想要的內容,但是通常面對工作當作複雜的需求,如果都按照那樣的方式來處理效率非常的低,這通常需要你自己去定義並實現很多非常基礎的爬蟲框架上的功能,或者需要組合很多Python第三方庫來做。不過不用擔心,Python中有很多非常優秀的爬蟲框架,比如我們接下來要學習到的Scrapy。Scrapy官方有很經典的入門文件說明,這一篇僅僅是通過一個簡單的例項來了解Scrapy這個庫是如何來進行網路內容提取的,更深入的學習請閱讀Scrapy官方文件。
建立目標
同樣在做任何事情之前都需要明確目標,那這次我們的目標是爬取一些技術性的文章並儲存到資料庫中。這就需要有目標網址和資料庫結構,資料庫我們選擇使用MySql,目標網站我們找了一個叫指令碼之家的內容站。我們這裡首先準備好一張用於儲存文章的表結構:
1 2 3 4 5 6 7 8 9 10 11 12 |
CREATE TABLE `articles` ( `id` mediumint(8) AUTO_INCREMENT NOT NULL, `title` varchar(255) DEFAULT NULL, `content` longtext, `add_date` int(11) DEFAULT 0, `hits` int(11) DEFAULT '0', `origin` varchar(500) DEFAULT '', `tags` varchar(45) DEFAULT '', PRIMARY KEY (`id`), KEY `add_date` (`add_date`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci; |
分析目標結構
這裡我們首先需要爬取得入口是“網路程式設計”這個節點,主入口網址為(http://www.jb51.net/list/index_1.htm) 開啟這個網站我們通過Chrome或者其他瀏覽器的檢視元素來分析當前頁面的HTML語義結構,如下圖所示:
從圖中紅色框線的部分可以看出,這裡是我們需要在“網路程式設計”這個節點下需要提取的所有文章的主分類入口,通過這些入口可以進去到不同文章分類的列表中。所以根據初步結構分析,我們得出本次爬蟲的爬取路線為:
從主入口進去 -> 提取當前入口中的所有分類 -> 通過分類入口進入到分類列表 -> 通過列表進入到文章頁
分類入口確定了接下來看看我們的分類列表,隨意點開一個分類入口,開啟列表如下圖所示:
這裡我框出了兩個主要部分,第一個是文章的標題,第二個是分頁,文章對應的URL就是我們接下來需要爬取文章內容的入口,這裡需要注意的是分頁的處理,通過分頁的最後一頁我們可以知道當前這類列表共有多少頁文章。結合以上分析我們基本確定了本次爬蟲的各個路線入口,接下來我們就開始通過程式來實現本次的目標。
實現爬蟲
在實現爬蟲之前我們通過一張圖來對Scrapy有個基本的認識,為了保持本章內容的簡潔性,我們這裡暫時不會討論Item Pipeline部分,Scrapy架構圖如下所示(圖片來自網路):
從圖中可以很清晰的看到Scrapy所包含的幾大塊,下面我們通過程式碼來演示我們所用到的基礎功能部分。
主要依賴第三方庫:
web.py web框架,這裡只用到了database部分,將來會用來進行內容展示
scrapy 爬蟲框架,這裡只用到了最基本的內容提取
這裡還會用到一些xpath相關知識,請自行Google瞭解xpath語法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 |
# -*- coding:utf-8 -*- '''by sudo rm -rf http://imchenkun.com''' import scrapy from scrapy.http import Request import web import time db = web.database(dbn='mysql', host='127.0.0.1', db='imchenkun', user='root', pw='root') # 允許的站點域 allow_domain = "jb51.net" base_url = "http://www.jb51.net" # 列表頁 list_url = "http://www.jb51.net/list/list_%d_%d.htm" # 列表分頁 list_page = 1 # 文章頁 crawl_url = "http://www.jb51.net/article/%d.htm" class JB51Spider(scrapy.Spider): name = "jb51" start_urls = [ "http://www.jb51.net/list/index_1.htm" ] cate_list = [] def parse(self, response): cate_id = response.selector.xpath('//div[@class="index_bor clearfix"]/div[@class="index_con"]/span/a/@href').re('(\\\\d+)')[::2] for id in cate_id: cate_url = list_url % (int(id), 1) yield Request(cate_url, callback=self.parse_page) def parse_page(self, response): _params = response.selector.xpath('//div[@class="dxypage clearfix"]/a[last()]/@href').re('(\\\\d+)') cate_id = int(_params[0]) # 分類編號 count = int(_params[1]) # 總頁數 article_urls = response.selector.xpath('//div[@class="artlist clearfix"]/dl/dt/a/@href').extract() # 處理第一頁 for article_url in article_urls: yield Request(base_url + article_url, callback=self.parse_article) # 處理其他頁 for page in range(1, count): url = (list_url % (cate_id, page + 1)) yield Request(url, callback=self.parse_list) def parse_list(self, response): """解析文章列表""" article_urls = response.selector.xpath('//div[@class="artlist clearfix"]/dl/dt/a/@href').extract() for article_url in article_urls: yield Request(base_url + article_url, callback=self.parse_article) def parse_article(self, response): """解析文章內容""" title = response.selector.xpath('//div[@class="title"]/h1/text()').extract()[0] content = response.selector.xpath('//div[@id="content"]').extract()[0] tags = ','.join(response.selector.xpath('//div[@class="tags mt10"]/a/text()').extract()) results = db.query('select count(0) as total from articles where origin=$origin', vars = { 'origin': response.url }) if results[0].total <= 0: db.insert('articles', title=title, origin=response.url, content=content, add_date=int(time.time()), hits=0, tags=tags ) |
安裝Scrapy後以上程式碼通過以下命令執行:
scrapy runspider jb51_spider.py
本次執行後的效果在資料庫中可以見如下圖所示:
總結
本篇文章我們主要了解了基本的Scrapy Spider部分,而且通過對目標網站的結構分析使用xpath進行內容的提取,以及分頁的處理。這裡我們的目的是建立一種寫爬蟲的思路,而不在於怎麼使用工具來爬資料。首先確定目標,然後分析目標,再借助現有工具進行內容提取,提取內容的過程中會遇到各種問題,這個時候我們再來逐個解決這些問題,直到我們的爬蟲能夠無障礙的執行。接下來我會使用Scrapy更多的功能將繼續探索Item的定義,Pipeline的實現以及如何使用代理。
特別申明:本文所提到的指令碼之家網站只是拿來進行爬蟲的技術交流學習,讀者涉及到的所有侵權問題都與本人無關,也希望大家在學習實戰的過程中不要大量的爬取內容對伺服器造成負擔