實(shí)踐Python的爬蟲(chóng)框架Scrapy來(lái)抓取豆瓣電影TOP250
安裝部署Scrapy
在安裝Scrapy前首先需要確定的是已經(jīng)安裝好了Python(目前Scrapy支持Python2.5,Python2.6和Python2.7)。官方文檔中介紹了三種方法進(jìn)行安裝,我采用的是使用 easy_install 進(jìn)行安裝,首先是下載Windows版本的setuptools(下載地址:http://pypi.python.org/pypi/setuptools),下載完后一路NEXT就可以了。
安裝完setuptool以后。執(zhí)行CMD,然后運(yùn)行一下命令:
easy_install -U Scrapy
同樣的你可以選擇使用pip安裝,pip的地址:http://pypi.python.org/pypi/pip
使用pip安裝Scrapy的命令為
pip install Scrapy
如果你的電腦先前裝過(guò)visual studio 2008 或 visual studio 2010那么一起順利,Scrapy已經(jīng)安裝完成。如果出現(xiàn)下列報(bào)錯(cuò):Unable to find vcvarsall.bat 那么你需要折騰下。你可以安裝visual studio 后進(jìn)行安裝或采用下面的方式進(jìn)行解決:
首先安裝MinGW(MinGW下載地址:http://sourceforge.net/projects/mingw/files/),在MinGW的安裝目錄下找到bin的文件夾,找到mingw32-make.exe,復(fù)制一份更名為make.exe;
把MinGW的路徑添加到環(huán)境變量path中,比如我把MinGW安裝到D:\MinGW\中,就把D:\MinGW\bin添加到path中;
打開(kāi)命令行窗口,在命令行窗口中進(jìn)入到要安裝代碼的目錄下;
輸入如下命令 setup.py install build –compiler=mingw32 就可以安裝了。
如果出現(xiàn)“xslt-config' 不是內(nèi)部或外部命令,也不是可運(yùn)行的程序或批處理文件?!卞e(cuò)誤,原因主要是lxml安裝不成功,只要上http://pypi.python.org/simple/lxml/下載個(gè)exe文件進(jìn)行安裝就可以了。
下面就可以進(jìn)入正題了。
新建工程
讓我們來(lái)用爬蟲(chóng)獲取豆瓣電影Top 250的電影信息吧。開(kāi)始之前,我們新建一個(gè)Scrapy工程。因?yàn)槲矣玫腤in7,所以在CMD中進(jìn)入一個(gè)我希望保存代碼的目錄,然后執(zhí)行:
D:\WEB\Python>scrapy startproject doubanmoive
這個(gè)命令會(huì)在當(dāng)前目錄下創(chuàng)建一個(gè)新的目錄doubanmoive,目錄結(jié)構(gòu)如下:
D:\WEB\Python\doubanmoive>tree /f Folder PATH listing for volume Data Volume serial number is 00000200 34EC:9CB9 D:. │ scrapy.cfg │ └─doubanmoive │ items.py │ pipelines.py │ settings.py │ __init__.py │ └─spiders __init__.py
這些文件主要為:
- doubanmoive/items.py: 定義需要獲取的內(nèi)容字段,類(lèi)似于實(shí)體類(lèi)。
- doubanmoive/pipelines.py: 項(xiàng)目管道文件,用來(lái)處理Spider抓取的數(shù)據(jù)。
- doubanmoive/settings.py: 項(xiàng)目配置文件
- doubanmoive/spiders: 放置spider的目錄
定義項(xiàng)目(Item)
Item是用來(lái)裝載抓取數(shù)據(jù)的容器,和Java里的實(shí)體類(lèi)(Entity)比較像,打開(kāi)doubanmoive/items.py可以看到默認(rèn)創(chuàng)建了以下代碼。
from scrapy.item import Item, Field class DoubanmoiveItem(Item): pass
我們只需要在 Doubanmoive 類(lèi)中增加需要抓取的字段即可,如 name=Field() ,最后根據(jù)我們的需求完成代碼如下。
from scrapy.item import Item, Field class DoubanmoiveItem(Item): name=Field()#電影名 year=Field()#上映年份 score=Field()#豆瓣分?jǐn)?shù) director=Field()#導(dǎo)演 classification=Field()#分類(lèi) actor=Field()#演員
編寫(xiě)爬蟲(chóng)(Spider)
Spider是整個(gè)項(xiàng)目中最核心的類(lèi),在這個(gè)類(lèi)里我們會(huì)定義抓取對(duì)象(域名、URL)以及抓取規(guī)則。Scrapy官方文檔中的教程是基于 BaseSpider 的,但 BaseSpider 只能爬取給定的URL列表,無(wú)法根據(jù)一個(gè)初始的URL向外拓展。不過(guò)除了 BaseSpider ,還有很多可以直接繼承 Spider 的類(lèi),比如 scrapy.contrib.spiders.CrawlSpider 。
在 doubanmoive/spiders 目錄下新建moive_spider.py文件,并填寫(xiě)代碼。
# -*- coding: utf-8 -*- from scrapy.selector import Selector from scrapy.contrib.spiders import CrawlSpider,Rule from scrapy.contrib.linkextractors.sgml import SgmlLinkExtractor from doubanmoive.items import DoubanmoiveItem class MoiveSpider(CrawlSpider): name="doubanmoive" allowed_domains=["movie.douban.com"] start_urls=["http://movie.douban.com/top250"] rules=[ Rule(SgmlLinkExtractor(allow=(r'http://movie.douban.com/top250\?start=\d+.*'))), Rule(SgmlLinkExtractor(allow=(r'http://movie.douban.com/subject/\d+')),callback="parse_item"), ] def parse_item(self,response): sel=Selector(response) item=DoubanmoiveItem() item['name']=sel.xpath('//*[@id="content"]/h1/span[1]/text()').extract() item['year']=sel.xpath('//*[@id="content"]/h1/span[2]/text()').re(r'\((\d+)\)') item['score']=sel.xpath('//*[@id="interest_sectl"]/div/p[1]/strong/text()').extract() item['director']=sel.xpath('//*[@id="info"]/span[1]/a/text()').extract() item['classification']= sel.xpath('//span[@property="v:genre"]/text()').extract() item['actor']= sel.xpath('//*[@id="info"]/span[3]/a[1]/text()').extract() return item
代碼說(shuō)明: MoiveSpider 繼承Scrapy中的 CrawlSpider , name , allow_domains , start_url 看名字就知道什么含義,其中rules稍微復(fù)雜一些,定義了URL的抓取規(guī)則,符合 allow 正則表達(dá)式的鏈接都會(huì)加入到Scheduler(調(diào)度程序)。通過(guò)分析豆瓣電影Top250的分頁(yè)URL http://movie.douban.com/top250?start=25&filter=&type= 可以得到以下規(guī)則
Rule(SgmlLinkExtractor(allow=(r'http://movie.douban.com/top250\?start=\d+.*'))),
而我們真正要抓取的頁(yè)面是每一個(gè)電影的詳細(xì)介紹,如肖申克的救贖的鏈接為 http://movie.douban.com/subject/1292052/ ,那只有 subject 后面的數(shù)字是變化的,根據(jù)正則表達(dá)式得到如下代碼。我們需要抓取這種類(lèi)型鏈接中的內(nèi)容,于是加入callback屬性,將Response交給parse_item函數(shù)來(lái)處理。
Rule(SgmlLinkExtractor(allow=(r'http://movie.douban.com/subject/\d+')),callback="parse_item"),
在 parse_item 函數(shù)中的處理邏輯非常簡(jiǎn)單,獲取符合條件鏈接的代碼,然后根據(jù)一定的規(guī)則抓取內(nèi)容賦給item并返回 Item Pipeline 。獲取大部分標(biāo)簽的內(nèi)容不需要編寫(xiě)復(fù)雜的正則表達(dá)式,我們可以使用 XPath 。 XPath 是一門(mén)在 XML 文檔中查找信息的語(yǔ)言,但它也可以用在HTML中。下表列出了常用表達(dá)式。
表達(dá)式 | 描述 |
---|---|
nodename | 選取此節(jié)點(diǎn)的所有子節(jié)點(diǎn)。 |
/ | 從根節(jié)點(diǎn)選取。 |
// | 從匹配選擇的當(dāng)前節(jié)點(diǎn)選擇文檔中的節(jié)點(diǎn),而不考慮它們的位置。 |
. | 選取當(dāng)前節(jié)點(diǎn)。 |
.. | 選取當(dāng)前節(jié)點(diǎn)的父節(jié)點(diǎn)。 |
@ | 選取屬性。 |
如 //*[@id="content"]/h1/span[1]/text() 獲取的結(jié)果是在id為content的任意元素下h1元素下的span列表中第一個(gè)元素的文本內(nèi)容。我們可以通過(guò)Chrome開(kāi)發(fā)者工具(F12)來(lái)獲取某內(nèi)容的XPath表達(dá)式,具體操作為在需要抓取的內(nèi)容上點(diǎn)擊審查元素,下方就會(huì)出現(xiàn)開(kāi)發(fā)者工具,并定位到該元素,在內(nèi)容上點(diǎn)擊右鍵,選擇復(fù)制XPath。
存儲(chǔ)數(shù)據(jù)
爬蟲(chóng)獲取到數(shù)據(jù)以后我們需要將其存儲(chǔ)到數(shù)據(jù)庫(kù)中,之前我們提到該操作需要靠項(xiàng)目管道(pipeline)來(lái)處理,其通常執(zhí)行的操作為:
- 清洗HTML數(shù)據(jù)
- 驗(yàn)證解析到的數(shù)據(jù)(檢查項(xiàng)目是否包含必要的字段)
- 檢查是否是重復(fù)數(shù)據(jù)(如果重復(fù)就刪除)
- 將解析到的數(shù)據(jù)存儲(chǔ)到數(shù)據(jù)庫(kù)中
由于我們獲取的數(shù)據(jù)格式多種多樣,有一些存儲(chǔ)在關(guān)系型數(shù)據(jù)庫(kù)中并不方便,所以我在寫(xiě)完MySQL版本的Pipeline之后又寫(xiě)了一個(gè)MongoDB的。
MySQL版本:
# -*- coding: utf-8 -*- from scrapy import log from twisted.enterprise import adbapi from scrapy.http import Request import MySQLdb import MySQLdb.cursors class DoubanmoivePipeline(object): def __init__(self): self.dbpool = adbapi.ConnectionPool('MySQLdb', db = 'python', user = 'root', passwd = 'root', cursorclass = MySQLdb.cursors.DictCursor, charset = 'utf8', use_unicode = False ) def process_item(self, item, spider): query = self.dbpool.runInteraction(self._conditional_insert, item) query.addErrback(self.handle_error) return item def _conditional_insert(self,tx,item): tx.execute("select * from doubanmoive where m_name= %s",(item['name'][0],)) result=tx.fetchone() log.msg(result,level=log.DEBUG) print result if result: log.msg("Item already stored in db:%s" % item,level=log.DEBUG) else: classification=actor='' lenClassification=len(item['classification']) lenActor=len(item['actor']) for n in xrange(lenClassification): classification+=item['classification'][n] if n<lenClassification-1: classification+='/' for n in xrange(lenActor): actor+=item['actor'][n] if n<lenActor-1: actor+='/' tx.execute(\ "insert into doubanmoive (m_name,m_year,m_score,m_director,m_classification,m_actor) values (%s,%s,%s,%s,%s,%s)",\ (item['name'][0],item['year'][0],item['score'][0],item['director'][0],classification,actor)) log.msg("Item stored in db: %s" % item, level=log.DEBUG) def handle_error(self, e): log.err(e)
MongoDB版本:
# -*- coding: utf-8 -*- import pymongo from scrapy.exceptions import DropItem from scrapy.conf import settings from scrapy import log class MongoDBPipeline(object): #Connect to the MongoDB database def __init__(self): connection = pymongo.Connection(settings['MONGODB_SERVER'], settings['MONGODB_PORT']) db = connection[settings['MONGODB_DB']] self.collection = db[settings['MONGODB_COLLECTION']] def process_item(self, item, spider): #Remove invalid data valid = True for data in item: if not data: valid = False raise DropItem("Missing %s of blogpost from %s" %(data, item['url'])) if valid: #Insert data into database new_moive=[{ "name":item['name'][0], "year":item['year'][0], "score":item['score'][0], "director":item['director'], "classification":item['classification'], "actor":item['actor'] }] self.collection.insert(new_moive) log.msg("Item wrote to MongoDB database %s/%s" % (settings['MONGODB_DB'], settings['MONGODB_COLLECTION']), level=log.DEBUG, spider=spider) return item
可以看到其基本的處理流程是一樣,但是MySQL不太方便的一點(diǎn)就是需要將數(shù)組類(lèi)型的數(shù)據(jù)通過(guò)分隔符轉(zhuǎn)換。而MongoDB支持存入List、Dict等多種類(lèi)型的數(shù)據(jù)。
配置文件
在運(yùn)行爬蟲(chóng)之前還需要將在 settings.py 中增加一些配置信息。
BOT_NAME = 'doubanmoive' SPIDER_MODULES = ['doubanmoive.spiders'] NEWSPIDER_MODULE = 'doubanmoive.spiders' ITEM_PIPELINES={ 'doubanmoive.mongo_pipelines.MongoDBPipeline':300, 'doubanmoive.pipelines.DoubanmoivePipeline':400, } LOG_LEVEL='DEBUG' DOWNLOAD_DELAY = 2 RANDOMIZE_DOWNLOAD_DELAY = True USER_AGENT = 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_8_3) AppleWebKit/536.5 (KHTML, like Gecko) Chrome/19.0.1084.54 Safari/536.5' COOKIES_ENABLED = True MONGODB_SERVER = 'localhost' MONGODB_PORT = 27017 MONGODB_DB = 'python' MONGODB_COLLECTION = 'test'
ITEM_PIPELINES 中定義了MySQL和MongoDB兩個(gè)Pipeline文件,后面的數(shù)字代表執(zhí)行的優(yōu)先級(jí)順序,范圍為0~1000。 而中間的 DOWNLOAD_DELAY 等信息是為了防止爬蟲(chóng)被豆瓣Ban掉,增加了一些隨機(jī)延遲,瀏覽器代理等。最后的就是MongoDB的配置信息,MySQL也可以參考這種方式來(lái)寫(xiě)。
至此為止,抓取豆瓣電影的爬蟲(chóng)就已經(jīng)完成了。在命令行中執(zhí)行 Scrapy crawl doubanmoive 讓蜘蛛開(kāi)始爬行吧!
- Python爬蟲(chóng)框架Scrapy安裝使用步驟
- 零基礎(chǔ)寫(xiě)python爬蟲(chóng)之使用Scrapy框架編寫(xiě)爬蟲(chóng)
- 使用scrapy實(shí)現(xiàn)爬網(wǎng)站例子和實(shí)現(xiàn)網(wǎng)絡(luò)爬蟲(chóng)(蜘蛛)的步驟
- scrapy爬蟲(chóng)完整實(shí)例
- 深入剖析Python的爬蟲(chóng)框架Scrapy的結(jié)構(gòu)與運(yùn)作流程
- 講解Python的Scrapy爬蟲(chóng)框架使用代理進(jìn)行采集的方法
- Python使用Scrapy爬蟲(chóng)框架全站爬取圖片并保存本地的實(shí)現(xiàn)代碼
- Python的Scrapy爬蟲(chóng)框架簡(jiǎn)單學(xué)習(xí)筆記
- 使用Python的Scrapy框架編寫(xiě)web爬蟲(chóng)的簡(jiǎn)單示例
- python爬蟲(chóng)框架scrapy實(shí)戰(zhàn)之爬取京東商城進(jìn)階篇
- 淺析python實(shí)現(xiàn)scrapy定時(shí)執(zhí)行爬蟲(chóng)
- Scrapy爬蟲(chóng)多線(xiàn)程導(dǎo)致抓取錯(cuò)亂的問(wèn)題解決
相關(guān)文章
PyTorch中的參數(shù)類(lèi)torch.nn.Parameter()詳解
這篇文章主要給大家介紹了關(guān)于PyTorch中torch.nn.Parameter()的相關(guān)資料,要內(nèi)容包括基礎(chǔ)應(yīng)用、實(shí)用技巧、原理機(jī)制等方面,文章通過(guò)實(shí)例介紹的非常詳細(xì),需要的朋友可以參考下2022-02-02Python制作運(yùn)行進(jìn)度條的實(shí)現(xiàn)效果(代碼運(yùn)行不無(wú)聊)
這篇文章主要介紹了Python制作運(yùn)行進(jìn)度條的實(shí)現(xiàn)效果(代碼運(yùn)行不無(wú)聊),本文通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2021-02-02python代數(shù)式括號(hào)有效性檢驗(yàn)示例代碼
這篇文章主要給大家介紹了關(guān)于python代數(shù)式括號(hào)有效性檢驗(yàn)的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2020-10-10利用Python多線(xiàn)程實(shí)現(xiàn)圖片下載器
這篇文章主要介紹了利用Python多線(xiàn)程制作的圖片下載器的相關(guān)代碼,文中展示的示例代碼講解詳細(xì),對(duì)我們學(xué)習(xí)Python有一定幫助,需要的可以參考一下2022-03-03Python機(jī)器學(xué)習(xí)入門(mén)(一)序章
這篇文章主要介紹了Python機(jī)器學(xué)習(xí)入門(mén)知識(shí),本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2021-08-08