一、簡介
Scrapy 是一款簡單、易用,適用范圍很廣的網(wǎng)絡(luò)爬蟲框架,主要用戶數(shù)據(jù)挖掘、檢測、自動化測試等領(lǐng)域,其整體結(jié)構(gòu)如下:
Scrapy主要包括了以下組件:
引擎(Scrapy) : 用來處理整個系統(tǒng)的數(shù)據(jù)流處理, 觸發(fā)事務(wù)(框架核心)
調(diào)度器(Scheduler) : 用來接受引擎發(fā)過來的請求, 壓入隊列中, 并在引擎再次請求的時候返回. 可以想像成一個URL(抓取網(wǎng)頁的網(wǎng)址或者說是鏈接)的優(yōu)先隊列, 由它來決定下一個要抓取的網(wǎng)址是什么, 同時去除重復(fù)的網(wǎng)址
下載器(Downloader) : 用于下載網(wǎng)頁內(nèi)容, 并將網(wǎng)頁內(nèi)容返回給蜘蛛(Scrapy下載器是建立在twisted這個高效的異步模型上的)
爬蟲(Spiders) : 爬蟲是主要干活的, 用于從特定的網(wǎng)頁中提取自己需要的信息, 即所謂的實(shí)體(Item)。用戶也可以從中提取出鏈接,讓Scrapy繼續(xù)抓取下一個頁面
項(xiàng)目管道(Pipeline) : 負(fù)責(zé)處理爬蟲從網(wǎng)頁中抽取的實(shí)體,主要的功能是持久化實(shí)體、驗(yàn)證實(shí)體的有效性、清除不需要的信息。當(dāng)頁面被爬蟲解析后,將被發(fā)送到項(xiàng)目管道,并經(jīng)過幾個特定的次序處理數(shù)據(jù)。
下載器中間件(Downloader Middlewares) : 位于Scrapy引擎和下載器之間的框架,主要是處理Scrapy引擎與下載器之間的請求及響應(yīng)。
爬蟲中間件(Spider Middlewares) : 介于Scrapy引擎和爬蟲之間的框架,主要工作是處理蜘蛛的響應(yīng)輸入和請求輸出。
調(diào)度中間件(Scheduler Middewares) : 介于Scrapy引擎和調(diào)度之間的中間件,從Scrapy引擎發(fā)送到調(diào)度的請求和響應(yīng)。
Scrapy運(yùn)行流程大概如下:
- 引擎從調(diào)度器中取出一個鏈接(URL)用于接下來的抓取
- 引擎把URL封裝成一個請求(Request)傳給下載器
- 下載器把資源下載下來,并封裝成應(yīng)答包(Response)
- 爬蟲解析Response
- 解析出實(shí)體(Item),則交給實(shí)體管道進(jìn)行進(jìn)一步的處理
- 解析出的是鏈接(URL),則把URL交給調(diào)度器等待抓取
二、安裝 & 創(chuàng)建工程
Linux 環(huán)境下直接執(zhí)行以下命令即可:
sudo apt install python-pip
pip install scrapy
創(chuàng)建工程,比如我們現(xiàn)在就創(chuàng)建一個example工程,就只需要直接輸入一下命令:
scrapy startproject example
執(zhí)行完這一步之后,系統(tǒng)會提示我們創(chuàng)建一個spider,直接安裝提示創(chuàng)建一個就可以了。
接下來看看我們剛剛創(chuàng)建的項(xiàng)目目錄,來了解一下都創(chuàng)建了哪些文件。
scrapy框架結(jié)構(gòu):
- scrapy.cfg: 項(xiàng)目的配置文件。
- example/: 該項(xiàng)目的python模塊。
- example/items.py: 項(xiàng)目中的item文件。
- example/pipelines.py: 項(xiàng)目中的pipelines文件。
- example/settings.py: 項(xiàng)目的設(shè)置文件。
- example/spiders/: 放置spider代碼的目錄。
三、實(shí)戰(zhàn)---爬取豆瓣排名250的電影信息
- 在item.py下面定義一個VideoItem類,作為我們爬取信息的實(shí)體類。
class VideoItem(scrapy.Item):
# define the fields for your item here like:
# name = scrapy.Field()
# 排名
ranking = scrapy.Field()
# 電影名稱
movie_name = scrapy.Field()
# 評分
score = scrapy.Field()
# 評論人數(shù)
score_num = scrapy.Field()
- 編寫網(wǎng)絡(luò)爬蟲請求以及解析返回結(jié)果
# -*- coding: utf-8 -*-
import scrapy
import re
from scrapy import Request
from scrapy.spiders import Spider
from video.items import VideoItem
class ExampleSpider(scrapy.Spider):
name = 'example'
allowed_domains = ['example.com']
start_urls = ['https://movie.douban.com/top250']
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.143 Safari/537.36',
}
def start_requests(self):
url = 'https://movie.douban.com/top250'
yield Request(url, headers=self.headers)
def parse(self, response):
item = VideoItem()
movies = response.xpath('//ol[@class="grid_view"]/li')
for movie in movies:
item['ranking'] = movie.xpath('.//div[@class="pic"]/em/text()').extract()[0]
item['movie_name'] = movie.xpath('.//div[@class="hd"]/a/span[1]/text()').extract()[0]
item['score'] = movie.xpath('.//div[@class="star"]/span[@class="rating_num"]/text()').extract()[0]
item['score_num'] = movie.xpath('.//div[@class="star"]/span/text()').re(ur'(\d+)人評價')[0]
yield item
next_url = response.xpath('//span[@class="next"]/a/@href').extract()
if next_url:
next_url = 'https://movie.douban.com/top250' + next_url[0]
yield Request(next_url, headers=self.headers, callback=self.parse)
- 設(shè)置系統(tǒng)屬性
# 爬取網(wǎng)站最大允許的深度(depth)值。如果為0,則沒有限制。
# DEPTH_LIMIT = 4
# 設(shè)置下載的等待時間,大規(guī)模集中的訪問對服務(wù)器的影響最大,相當(dāng)與短時間中增大服務(wù)器負(fù)載
DOWNLOAD_DELAY = 2
SPIDER_MIDDLEWARES = {
'scrapy.spidermiddlewares.offsite.OffsiteMiddleware': None,
}
- 運(yùn)行爬蟲程序
scrapy crawl example
-
運(yùn)行結(jié)果
屏幕快照 2018-09-08 22.37.00.png
四、實(shí)戰(zhàn)---爬取最新美劇
目標(biāo)地址:http://www.meijutt.com/new100.html
爬取項(xiàng)目:美劇名稱、狀態(tài)、電視臺、更新時間
# -*- coding: utf-8 -*-
import scrapy
from scrapy.spiders import Spider
from meiju.items import MeijuItem
class ExampleSpider(scrapy.Spider):
name = 'example'
allowed_domains = ['example.com']
start_urls = ['http://www.meijutt.com/new100.html']
def parse(self, response):
item = MeijuItem()
meijus = response.xpath('//ul[@class="top-list fn-clear"]/li')
for meiju in meijus:
item['name'] = meiju.xpath('./h5/a/text()').extract()
item['status'] = meiju.xpath('./span/font/text()').extract()
item['des'] = meiju.xpath('./span[@class="mjjq"]/text()').extract()
item['episode'] = meiju.xpath('./span[@class="mjtv"]/text()').extract()
item['update'] = meiju.xpath('./div/font/text()').extract()
yield item