基于python框架Scrapy爬取自己的博客內(nèi)容過程詳解
前言
python中常用的寫爬蟲的庫常有urllib2、requests,對(duì)于大多數(shù)比較簡單的場景或者以學(xué)習(xí)為目的,可以用這兩個(gè)庫實(shí)現(xiàn)。這里有一篇我之前寫過的用urllib2+BeautifulSoup做的一個(gè)抓取百度音樂熱門歌曲的例子,有興趣可以看一下。
本文介紹用Scrapy抓取我在博客園的博客列表,只抓取博客名稱、發(fā)布日期、閱讀量和評(píng)論量這四個(gè)簡單的字段,以求用較簡單的示例說明Scrapy的最基本的用法。
環(huán)境配置說明
操作系統(tǒng):Ubuntu 14.04.2 LTS
Python:Python 2.7.6
Scrapy:Scrapy 1.0.3
注意:Scrapy1.0的版本和之前的版本有些區(qū)別,有些類的命名空間改變了。
創(chuàng)建項(xiàng)目
執(zhí)行如下命令創(chuàng)建一個(gè)Scrapy項(xiàng)目
scrapy startproject scrapy_cnblogs
創(chuàng)建之后查看項(xiàng)目的目錄結(jié)構(gòu)如下:
scrapy_cnblogs ├── botcnblogs │ ├── __init__.py │ ├── items.py #用于定義抓取內(nèi)容的實(shí)體 │ ├── pipelines.py #處理抓取的item的管道 │ ├── settings.py #爬蟲需要的配置參數(shù)在這里 │ └── spiders │ └── __init__.py └── scrapy.cfg #項(xiàng)目的配置文件,可以不去理會(huì),默認(rèn)即可
其中scrapy.cfg所在的目錄為項(xiàng)目的根目錄,此文件是項(xiàng)目的配置文件,項(xiàng)目建立后,此文件的內(nèi)容可以不用理會(huì)。其內(nèi)容如下:
[settings] default = botcnblogs.settings [deploy] #url = http://localhost:6800/ project = botcnblogs
在items.py文件里定義在抓取網(wǎng)頁內(nèi)容中抽象出來的數(shù)據(jù)結(jié)構(gòu)的定義,由于這里需要博客名稱、發(fā)布日期、閱讀量和評(píng)論量這四個(gè)字段,定義的Item結(jié)構(gòu)如下:
from scrapy import Item,Field #引入Item、Field class BotcnblogsItem(Item): # define the fields for your item here like: title = Field() #標(biāo)題 publishDate = Field() #發(fā)布日期 readCount = Field() #閱讀量 commentCount = Field() #評(píng)論數(shù)<br data-filtered="filtered"><br data-filtered="filtered">
在pipelines.py里對(duì)爬蟲抓取到的信息(這里的信息是已經(jīng)組織好的上面定義的Item對(duì)象)進(jìn)行處理,官方介紹的典型的應(yīng)用場景為:
- 清理HTML數(shù)據(jù)
- 驗(yàn)證爬取的數(shù)據(jù)(檢查item包含某些字段)
- 查重(并丟棄)
- 將爬取結(jié)果保存到數(shù)據(jù)庫中
它的定義也很簡單,只需要實(shí)現(xiàn)process_item方法即可,此方法有兩個(gè)參數(shù),一個(gè)是item,即要處理的Item對(duì)象,另一個(gè)參數(shù)是spider,即爬蟲。
另外還有open_spider和close_spider兩個(gè)方法,分別是在爬蟲啟動(dòng)和結(jié)束時(shí)的回調(diào)方法。
本例中處理很簡單,只是將接收的Item對(duì)象寫到一個(gè)json文件中,在__init__方法中以“w+”的方式打開或創(chuàng)建一個(gè)item.json的文件,然后把對(duì)象反序列化為字符串,寫入到item.json文件中。代碼如下:
# -*- coding: utf-8 -*-
import json
class BotcnblogsPipeline(object):
def __init__(self):
self.file = open("item.json", "w+")
def process_item(self, item, spider):
record = json.dumps(dict(item), ensure_ascii=False)+"\n" #此處如果有中文的話,要加上ensure_ascii=False參數(shù),否則可能出現(xiàn)亂碼
self.file.write(record)
return item
def open_spider(self, spider):
pass
def close_spider(self, spider):
self.file.close()
setting.py是爬蟲的配置文件,配置爬蟲的一些配置信息,這里用到的就是設(shè)置pipelines的ITEM_PIPELINES參數(shù),此參數(shù)配置項(xiàng)目中啟用的pipeline及其執(zhí)行順序,以字典的形式存在,{“pipeline”:執(zhí)行順序整數(shù)}
此例中的配置如下:
SPIDER_MODULES = ['botcnblogs.spiders']
NEWSPIDER_MODULE = 'botcnblogs.spiders'
ITEM_PIPELINES = {
'botcnblogs.pipelines.BotcnblogsPipeline': 1,
}
準(zhǔn)備工作都做好了,爬蟲呢,爬蟲在哪里實(shí)現(xiàn)呢,我們看到項(xiàng)目中有個(gè)spiders目錄,里面只有一個(gè)init.py文件,沒錯(cuò),爬蟲文件需要自己創(chuàng)建,就在這個(gè)目錄下,這里創(chuàng)建一個(gè)botspider.py的文件,對(duì)網(wǎng)頁進(jìn)行解析的工作就要在這里實(shí)現(xiàn)了,此例中定義的爬蟲類繼承自CrawlSpider類。
定義一個(gè)Spider需要如下幾個(gè)變量和方法實(shí)現(xiàn):
name:定義spider名字,這個(gè)名字應(yīng)該是唯一的,在執(zhí)行這個(gè)爬蟲程序的時(shí)候,需要用到這個(gè)名字。
allowed_domains:允許爬取的域名列表,例如現(xiàn)在要爬取博客園,這里要寫成cnblogs.com
start_urls:爬蟲最開始爬的入口地址列表。
rules:如果要爬取的頁面不是單獨(dú)一個(gè)或者幾個(gè)頁面,而是具有一定的規(guī)則可循的,例如爬取的博客有連續(xù)多頁,就可以在這里設(shè)置,如果定義了rules,則需要自己定義爬蟲規(guī)則(以正則表達(dá)式的方式),而且需要自定義回調(diào)函數(shù)。
代碼說話:
#-*- coding:utf-8 -*-
__author__ = 'linuxfengzheng'
from scrapy.spiders import Spider, Rule
from scrapy.selector import Selector
from botcnblogs.items import BotcnblogsItem
from scrapy.linkextractors import LinkExtractor
import re
from scrapy.spiders import CrawlSpider
class botspider(CrawlSpider):
name = "cnblogsSpider" #設(shè)置爬蟲名稱
allowed_domains = ["cnblogs.com"] #設(shè)置允許的域名
start_urls = [
"http://www.cnblogs.com/fengzheng/default.html?page=3", #設(shè)置開始爬取頁面
]
rules = (
Rule(LinkExtractor(allow=('fengzheng/default.html\?page\=([\d]+)', ),),callback='parse_item',follow=True),
) #制定規(guī)則
def parse_item(self, response):
sel = response.selector
posts = sel.xpath('//div[@id="mainContent"]/div/div[@class="day"]')
items = []
for p in posts:
#content = p.extract()
#self.file.write(content.encode("utf-8"))
item = BotcnblogsItem()
publishDate = p.xpath('div[@class="dayTitle"]/a/text()').extract_first()
item["publishDate"] = (publishDate is not None and [publishDate.encode("utf-8")] or [""])[0]
#self.file.write(title.encode("utf-8"))
title = p.xpath('div[@class="postTitle"]/a/text()').extract_first()
item["title"] = (title is not None and [title.encode("utf-8")] or [""])[0]
#re_first("posted @ 2015-11-03 10:32 風(fēng)的姿態(tài) 閱讀(\d+")
readcount = p.xpath('div[@class="postDesc"]/text()').re_first(u"閱讀\(\d+\)")
regReadCount = re.search(r"\d+", readcount)
if regReadCount is not None:
readcount = regReadCount.group()
item["readCount"] = (readcount is not None and [readcount.encode("utf-8")] or [0])[0]
commentcount = p.xpath('div[@class="postDesc"]/text()').re_first(u"評(píng)論\(\d+\)")
regCommentCount = re.search(r"\d+", commentcount)
if regCommentCount is not None:
commentcount = regCommentCount.group()
item["commentCount"] = (commentcount is not None and [commentcount.encode("utf-8")] or [0])[0]
items.append(item)
return items
#self.file.close()
因?yàn)?.0版和之前的版本在包上有所改變,這里列出此例中所涉及的不同版本的區(qū)別
| 類 | 所在包 | |
| 1.0版本 | 之前版本 | |
| spider | scrapy.spiders | scrapy.spider |
| crawlspider | scrapy.spiders | scrapy.contrib.spiders |
| linkextractor | scrapy.linkextractors | scrapy.contrib.linkextractors |
| rule | scrapy.spiders | scrapy.contrib.spiders |
爬蟲思路:
首先進(jìn)入到我的博客頁面http://www.cnblogs.com/fengzheng/,這是我的博客首頁,以列表形式顯示已經(jīng)發(fā)布的博文,這是第一頁,點(diǎn)擊頁面下面的下一頁按鈕,進(jìn)入第二頁,頁面地址為http://www.cnblogs.com/fengzheng/default.html?page=2,由此看出網(wǎng)站以page作為參數(shù)來表示頁數(shù),這樣看來爬蟲的規(guī)則就很簡單了, fengzheng/default.html\?page\=([\d]+),這個(gè)就是爬蟲的規(guī)則,爬取default.html頁面,page參數(shù)為數(shù)字的頁面,這樣無論有多少頁都可以遍歷到。
當(dāng)然,如果頁面數(shù)量很少可以在start_urls列表中,將要爬取的頁面都列出來,但是這樣當(dāng)博文數(shù)量增多就會(huì)出現(xiàn)問題,如下:
start_urls = [ "http://www.cnblogs.com/fengzheng/default.html?page=1", "http://www.cnblogs.com/fengzheng/default.html?page=2", "http://www.cnblogs.com/fengzheng/default.html?page=3", ]
當(dāng)爬取的網(wǎng)頁具有規(guī)則定義的情況下,要繼承CrawlSpider爬蟲類,使用Spider就不行了,在規(guī)則定義(rules)時(shí),如果要對(duì)爬取的網(wǎng)頁進(jìn)行處理,而不是簡單的需要Url,這時(shí),需要定義一個(gè)回調(diào)函數(shù),在爬取到符合條件的網(wǎng)頁時(shí)調(diào)用,并且設(shè)置follow=Ture,定義如下:
rules = (
Rule(LinkExtractor(allow=('fengzheng/default.html\?page\=([\d]+)', ),),callback='parse_item',follow=True),
)
回調(diào)函數(shù)名稱為parse_item,在parse_item方法中,就是真正要分析網(wǎng)頁html,獲取需要的內(nèi)容的時(shí)候了。觀察頁面,查看需要的信息在什么位置,如圖:

之后,分析網(wǎng)頁源碼,分析出xpath

用如下代碼找到所有的class為day的div,每一個(gè)就是一個(gè)博文區(qū)域:
posts = sel.xpath('//div[@id="mainContent"]/div/div[@class="day"]')
之后遍歷這個(gè)集合,獲取所需內(nèi)容,其中注意一下幾點(diǎn):
因?yàn)橛兄形膬?nèi)容,要對(duì)獲取的內(nèi)容進(jìn)行encode("utf-8")編碼
由于評(píng)論數(shù)和閱讀量混在一起,要對(duì)那個(gè)字符串再進(jìn)行正則表達(dá)式提取
至此,簡單的爬蟲已經(jīng)完成,接下來要運(yùn)行這個(gè)爬蟲,cd進(jìn)入到爬蟲項(xiàng)目所在的目錄,執(zhí)行以下命令:
scrapy crawl cnblogsSpider
會(huì)輸出爬取過程信息

之后會(huì)看到,根目錄中多了一個(gè)item.json文件,cat此文件內(nèi)容,可以看到信息已經(jīng)被提取出來:

點(diǎn)擊這里在github獲取源碼
以上就是本文的全部內(nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
Prometheus開發(fā)中間件Exporter過程詳解
這篇文章主要介紹了Prometheus開發(fā)中間件Exporter過程詳解,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-11-11
python中子類調(diào)用父類函數(shù)的方法示例
Python中類的初始化方法是__init__(),因此父類、子類的初始化方法都是這個(gè),下面這篇文章主要給大家介紹了關(guān)于python中子類調(diào)用父類函數(shù)的方法示例,文中通過示例代碼介紹的非常詳細(xì),需要的朋友可以參考下。2017-08-08
使用Python制作讀單詞視頻的實(shí)現(xiàn)代碼
我們經(jīng)常在B站或其他視頻網(wǎng)站上看到那種逐條讀單詞的視頻,但他們的視頻多多少少和我們的預(yù)期都不太一致,然而,網(wǎng)上很難找到和自己需求符合的視頻,所以本文給大家介紹了使用Python制作讀單詞視頻的實(shí)現(xiàn),需要的朋友可以參考下2024-04-04
python實(shí)現(xiàn)數(shù)據(jù)可視化超詳細(xì)講解
Python的數(shù)據(jù)可視化是將數(shù)據(jù)以圖形或圖表的形式呈現(xiàn),使復(fù)雜的信息更易于理解和分析,本文給大家詳細(xì)介紹了python數(shù)據(jù)可視化的實(shí)現(xiàn),文中通過圖文結(jié)合的方式介紹的非常詳細(xì),需要的朋友可以參考下2024-06-06
python類中super()和__init__()的區(qū)別
這篇文章主要介紹了python類中super()和__init__()的區(qū)別,本文給大家介紹的非常詳細(xì),具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2016-10-10

