爬蟲五大核心組件
組件的作用:
引擎(Scrapy)
用來處理整個系統的數據流處理, 觸發事務(框架核心)
調度器(Scheduler)
用來接受引擎發過來的請求, 壓入隊列中, 並在引擎再次請求的時候返回. 可以想像成一個URL(抓取網頁的網址或者說是鏈接)的優先隊列, 由它來決定下一個要抓取的網址是什么, 同時去除重復的網址
下載器(Downloader)
用於下載網頁內容, 並將網頁內容返回給蜘蛛(Scrapy下載器是建立在twisted這個高效的異步模型上的)
爬蟲(Spiders)
爬蟲是主要干活的, 用於從特定的網頁中提取自己需要的信息, 即所謂的實體(Item)。用戶也可以從中提取出鏈接,讓Scrapy繼續抓取下一個頁面
項目管道(Pipeline)
負責處理爬蟲從網頁中抽取的實體,主要的功能是持久化實體、驗證實體的有效性、清除不需要的信息。當頁面被爬蟲解析后,將被發送到項目管道,並經過幾個特定的次序處理數據。
請求傳參的實現深度爬取
請求傳參實現的深度爬取
- 深度爬取:爬取的數據沒有在同一張頁面中(首頁數據+詳情頁數據)
- 在scrapy中如果沒有請求傳參我們是無法持久化存儲數據
- 實現方式:
- scrapy.Request(url,callback,meta)
- meta是一個字典,可以將meta傳遞給callback
- callback取出meta:
- response.meta
代碼實現:
# -*- coding: utf-8 -*-
import scrapy
from movie.items import MovieItem
class MovieTestSpider(scrapy.Spider):
name = 'movie_test'
# allowed_domains = ['www.xxxxx.com']
start_urls = ['https://www.4567kan.com/index.php/vod/show/id/5.html']
url ="https://www.4567kan.com/index.php/vod/show/id/5/page/{}.html"
page = 2
def parse(self, response):
li_list = response.xpath("/html/body/div[1]/div/div/div/div[2]/ul/li")
for li in li_list:
titile = li.xpath("./div/a/@title").extract_first()
src = "https://www.4567kan.com"+li.xpath("./div/a/@href").extract_first()
item = MovieItem()
item["title"] = titile
yield scrapy.Request(url = src,callback=self.parse_movie,meta={"item":item})
if self.page<5:
new_url = self.url.format(self.page)
self.page+=1
yield scrapy.Request(url = new_url,callback=self.parse)
def parse_movie(self,response):
print(response)
item = response.meta["item"]
desc = response.xpath('/html/body/div[1]/div/div/div/div[2]/p[5]/span[2]/text()').extract_first()
item["desc"] = desc
yield item
中間件
-
作用:批量攔截請求和響應
-
爬蟲中間件(暫時未講)
-
下載中間件(推薦)
- 攔截請求:
- 篡改請求Url
- 偽裝請求頭信息
- UA
- cookie
- 設置請求代理(重點)
- 攔截響應
- 篡改響應數據
- 代理操作必須使用中間件才可以實現
- process_exception:
- request.meta["proxy"] = "http:// ip:port"
- process_exception:
- 攔截請求:
middlewares.py代碼
class MiddleproDownloaderMiddleware(object):
#攔截所有的請求(正常和異常的都算上)
def process_request(self,request,spider):
print("process_request()")
request.headers["User-Agent"] = "xxxx"
request.headers["Cookie"] = "xxxxx" #但是平常我們不會這么做,因為settings中有cookie配置,scrapy每次請求會帶這cook
return None #或者request
#攔截所有響應的對象
#參數:response攔截到的響應對象,request響應對象對應的請求對象
def process_exception(self,request,response,spider):
print("process_response()")
return response
#攔截異常的請求
#參數:request就是攔截到的發生異常的請求
#作用:想要將異常的請求進行修正,將其變成正常的請求,然后對其重新發送
def process_exception(self.request,exception,spider):
#請求的ip被禁掉,該請求就會變成一個異常的請求
#這里的meta跟請求傳參一樣。都是Request
request.meta["proxy"] = "http://ip:port" #設置代理
print("process_exception()")
return request #將異常的請求修正后將其重新發送
在settings中
打開這個配置,每次請求都會帶這cookie,不需要咱們去添加!
下載圖片的爬取
大文件下載:大文件數據是在管道中請求到的
-
下屬管道類是scrapy封裝好的我們直接用即可:
-
from scrapy.pipelines.images import ImagesPipeline #提供了數據下載功能
重寫該管道類的三個方法:
- get_media_requests
- 對圖片地址發起請求
- file_path
- 返回圖片名稱即可
- item_copleted
- 返回item,將其返回給下一個即將被執行的管道類
- 在配置文件中添加:
- IMAGES_STORE = 'dirName'
- get_media_requests
img.py
import scrapy
from imgPro.items import ImgproItem
class ImgSpider(scrapy.Spider):
name = 'img'
# allowed_domains = ['www.xxx.com']
start_urls = ['http://www.521609.com/daxuexiaohua/']
def parse(self, response):
#解析圖片地址和圖片名稱
li_list = response.xpath('//*[@id="content"]/div[2]/div[2]/ul/li')
for li in li_list:
img_src = 'http://www.521609.com'+li.xpath('./a[1]/img/@src').extract_first()
img_name = li.xpath('./a[1]/img/@alt').extract_first()+'.jpg'
item = ImgproItem()
item['name'] = img_name
item['src'] = img_src
yield item
items.py
import scrapy
class ImgproItem(scrapy.Item):
# define the fields for your item here like:
name = scrapy.Field()
src = scrapy.Field()
pipelines.py
#該默認管道無法幫助我們請求圖片數據,因此該管道我們就不用
# class ImgproPipeline(object):
# def process_item(self, item, spider):
# return item
#管道需要接受item中的圖片地址和名稱,然后再管道中請求到圖片的數據對其進行持久化存儲
from scrapy.pipelines.images import ImagesPipeline #提供了數據下載功能
from scrapy.pipelines.media import MediaPipeline
from scrapy.pipelines.files import FilesPipeline
import scrapy
class ImgsPipiLine(ImagesPipeline):
#根據圖片地址發起請求
def get_media_requests(self, item, info):
# print(item)
yield scrapy.Request(url=item['src'],meta={'item':item})
#返回圖片名稱即可
def file_path(self, request, response=None, info=None):
#通過request獲取meta
item = request.meta['item']
filePath = item['name']
return filePath #只需要返回圖片名稱
#將item傳遞給下一個即將被執行的管道類
def item_completed(self, results, item, info):
return item
settings.py
ITEM_PIPELINES = {
'imgPro.pipelines.ImgsPipiLine': 300,
}
IMAGES_STORE = './imgLibs'