爬蟲學(xué)習(xí)之基于Scrapy的網(wǎng)絡(luò)爬蟲

概述


在上一篇文章《爬蟲學(xué)習(xí)之一個(gè)簡單的網(wǎng)絡(luò)爬蟲》中我們對(duì)爬蟲的概念有了一個(gè)初步的認(rèn)識(shí)溃卡,并且通過Python的一些第三方庫很方便的提取了我們想要的內(nèi)容堕阔,但是通常面對(duì)工作當(dāng)作復(fù)雜的需求,如果都按照那樣的方式來處理效率非常的低鲜结,這通常需要你自己去定義并實(shí)現(xiàn)很多非常基礎(chǔ)的爬蟲框架上的功能,或者需要組合很多Python第三方庫來做崎苗。不過不用擔(dān)心,Python中有很多非常優(yōu)秀的爬蟲框架舀寓,比如我們接下來要學(xué)習(xí)到的Scrapy胆数。Scrapy官方有很經(jīng)典的入門文檔說明,這一篇僅僅是通過一個(gè)簡單的實(shí)例來了解Scrapy這個(gè)庫是如何來進(jìn)行網(wǎng)絡(luò)內(nèi)容提取的互墓,更深入的學(xué)習(xí)請(qǐng)閱讀Scrapy官方文檔必尼。

建立目標(biāo)


同樣在做任何事情之前都需要明確目標(biāo),那這次我們的目標(biāo)是爬取一些技術(shù)性的文章并存儲(chǔ)到數(shù)據(jù)庫中。這就需要有目標(biāo)網(wǎng)址和數(shù)據(jù)庫結(jié)構(gòu)判莉,數(shù)據(jù)庫我們選擇使用MySql豆挽,目標(biāo)網(wǎng)站我們找了一個(gè)叫腳本之家的內(nèi)容站。我們這里首先準(zhǔn)備好一張用于存儲(chǔ)文章的表結(jié)構(gòu):

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;

分析目標(biāo)結(jié)構(gòu)

這里我們首先需要爬取得入口是“網(wǎng)絡(luò)編程”這個(gè)節(jié)點(diǎn)券盅,主入口網(wǎng)址為(http://www.jb51.net/list/index_1.htm) 打開這個(gè)網(wǎng)站我們通過Chrome或者其他瀏覽器的查看元素來分析當(dāng)前頁面的HTML語義結(jié)構(gòu)帮哈,如下圖所示:

從圖中紅色框線的部分可以看出,這里是我們需要在“網(wǎng)絡(luò)編程”這個(gè)節(jié)點(diǎn)下需要提取的所有文章的主分類入口锰镀,通過這些入口可以進(jìn)去到不同文章分類的列表中娘侍。所以根據(jù)初步結(jié)構(gòu)分析,我們得出本次爬蟲的爬取路線為:

從主入口進(jìn)去 -> 提取當(dāng)前入口中的所有分類 -> 通過分類入口進(jìn)入到分類列表 -> 通過列表進(jìn)入到文章頁

分類入口確定了接下來看看我們的分類列表泳炉,隨意點(diǎn)開一個(gè)分類入口私蕾,打開列表如下圖所示:

這里我框出了兩個(gè)主要部分,第一個(gè)是文章的標(biāo)題胡桃,第二個(gè)是分頁踩叭,文章對(duì)應(yīng)的URL就是我們接下來需要爬取文章內(nèi)容的入口,這里需要注意的是分頁的處理翠胰,通過分頁的最后一頁我們可以知道當(dāng)前這類列表共有多少頁文章容贝。結(jié)合以上分析我們基本確定了本次爬蟲的各個(gè)路線入口,接下來我們就開始通過程序來實(shí)現(xiàn)本次的目標(biāo)之景。

實(shí)現(xiàn)爬蟲


在實(shí)現(xiàn)爬蟲之前我們通過一張圖來對(duì)Scrapy有個(gè)基本的認(rèn)識(shí)斤富,為了保持本章內(nèi)容的簡潔性,我們這里暫時(shí)不會(huì)討論Item Pipeline部分锻狗,Scrapy架構(gòu)圖如下所示(圖片來自網(wǎng)絡(luò)):

從圖中可以很清晰的看到Scrapy所包含的幾大塊衰伯,下面我們通過代碼來演示我們所用到的基礎(chǔ)功能部分吵瞻。
主要依賴第三方庫:

web.py web框架霞势,這里只用到了database部分催植,將來會(huì)用來進(jìn)行內(nèi)容展示
scrapy 爬蟲框架,這里只用到了最基本的內(nèi)容提取

這里還會(huì)用到一些xpath相關(guān)知識(shí)刻帚,請(qǐng)自行Google了解xpath語法

# -*- 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')

# 允許的站點(diǎn)域
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]) # 分類編號(hào)
        count = int(_params[1]) # 總頁數(shù)

        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):
        """解析文章內(nèi)容"""
        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后以上代碼通過以下命令執(zhí)行:

scrapy runspider jb51_spider.py

本次運(yùn)行后的效果在數(shù)據(jù)庫中可以見如下圖所示:

Github地址

總結(jié)


本篇文章我們主要了解了基本的Scrapy Spider部分潦嘶,而且通過對(duì)目標(biāo)網(wǎng)站的結(jié)構(gòu)分析使用xpath進(jìn)行內(nèi)容的提取,以及分頁的處理崇众。這里我們的目的是建立一種寫爬蟲的思路掂僵,而不在于怎么使用工具來爬數(shù)據(jù)。首先確定目標(biāo)顷歌,然后分析目標(biāo)锰蓬,再借助現(xiàn)有工具進(jìn)行內(nèi)容提取,提取內(nèi)容的過程中會(huì)遇到各種問題眯漩,這個(gè)時(shí)候我們?cè)賮碇饌€(gè)解決這些問題芹扭,直到我們的爬蟲能夠無障礙的運(yùn)行。接下來我會(huì)使用Scrapy更多的功能將繼續(xù)探索Item的定義,Pipeline的實(shí)現(xiàn)以及如何使用代理冯勉。

特別申明:本文所提到的腳本之家網(wǎng)站只是拿來進(jìn)行爬蟲的技術(shù)交流學(xué)習(xí),讀者涉及到的所有侵權(quán)問題都與本人無關(guān)摹芙,也希望大家在學(xué)習(xí)實(shí)戰(zhàn)的過程中不要大量的爬取內(nèi)容對(duì)服務(wù)器造成負(fù)擔(dān)

本文首發(fā)在sudo rm -rf 轉(zhuǎn)載請(qǐng)注明原作者

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末灼狰,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子浮禾,更是在濱河造成了極大的恐慌交胚,老刑警劉巖,帶你破解...
    沈念sama閱讀 219,270評(píng)論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件盈电,死亡現(xiàn)場離奇詭異蝴簇,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)匆帚,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,489評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門熬词,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人吸重,你說我怎么就攤上這事互拾。” “怎么了嚎幸?”我有些...
    開封第一講書人閱讀 165,630評(píng)論 0 356
  • 文/不壞的土叔 我叫張陵颜矿,是天一觀的道長。 經(jīng)常有香客問我嫉晶,道長骑疆,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,906評(píng)論 1 295
  • 正文 為了忘掉前任替废,我火速辦了婚禮箍铭,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘椎镣。我一直安慰自己坡疼,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,928評(píng)論 6 392
  • 文/花漫 我一把揭開白布衣陶。 她就那樣靜靜地躺著柄瑰,像睡著了一般。 火紅的嫁衣襯著肌膚如雪剪况。 梳的紋絲不亂的頭發(fā)上教沾,一...
    開封第一講書人閱讀 51,718評(píng)論 1 305
  • 那天,我揣著相機(jī)與錄音译断,去河邊找鬼授翻。 笑死,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的堪唐。 我是一名探鬼主播巡语,決...
    沈念sama閱讀 40,442評(píng)論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢(mèng)啊……” “哼淮菠!你這毒婦竟也來了男公?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,345評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤合陵,失蹤者是張志新(化名)和其女友劉穎枢赔,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體拥知,經(jīng)...
    沈念sama閱讀 45,802評(píng)論 1 317
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡踏拜,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,984評(píng)論 3 337
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了低剔。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片速梗。...
    茶點(diǎn)故事閱讀 40,117評(píng)論 1 351
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖襟齿,靈堂內(nèi)的尸體忽然破棺而出镀琉,到底是詐尸還是另有隱情,我是刑警寧澤蕊唐,帶...
    沈念sama閱讀 35,810評(píng)論 5 346
  • 正文 年R本政府宣布屋摔,位于F島的核電站,受9級(jí)特大地震影響替梨,放射性物質(zhì)發(fā)生泄漏钓试。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,462評(píng)論 3 331
  • 文/蒙蒙 一副瀑、第九天 我趴在偏房一處隱蔽的房頂上張望弓熏。 院中可真熱鬧,春花似錦糠睡、人聲如沸挽鞠。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,011評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽信认。三九已至,卻和暖如春均抽,著一層夾襖步出監(jiān)牢的瞬間嫁赏,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,139評(píng)論 1 272
  • 我被黑心中介騙來泰國打工油挥, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留潦蝇,地道東北人款熬。 一個(gè)月前我還...
    沈念sama閱讀 48,377評(píng)論 3 373
  • 正文 我出身青樓,卻偏偏與公主長得像攘乒,于是被迫代替她去往敵國和親贤牛。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,060評(píng)論 2 355

推薦閱讀更多精彩內(nèi)容