(1)Scrapy模塊安裝
scrapy支持Python2.7和python3.4以上版本。
python包可以用全局安裝(也稱爲系統範圍),也可以安裝在用戶空間中。
Windows
一.直接安裝
1.在https://www.lfd.uci.edu/~gohlke/pythonlibs/ 下載對應的Twisted的版本文件
2. 在命令行進入到Twisted的目錄 執行pip install 加Twisted文件名
3.執行pip install scrapy
二.annaconda 下安裝 (官方推薦)
1.安裝conda
conda舊版本 https://docs.anaconda.com/anaconda/packages/oldpkglists/
安裝方法 https://blog.csdn.net/ychgyyn/article/details/82119201
2. 安裝scrapy conda install scrapy
(2)Scrapy框架簡介
Scrapy是純Python開發的一個高效,結構化的網頁抓取框架。
Scrapy是個啥?
Scrapy是一個爲了爬取網站數據,提取結構性數據而編寫的應用框架。 其最初是爲了頁面抓取 (更確切來說, 網絡抓取 )所設計的,也可以應用在獲取API所返回的數據(例如 Amazon Associates Web Services ) 或者通用的網絡爬蟲。 Scrapy用途廣泛,可以用於數據挖掘、監測和自動化測試 Scrapy使用了Twisted 異步網絡庫來處理網絡通訊。
我們爲啥要用這玩意呢?
1.爲了更利於我們將精力集中在請求與解析上。
2.企業級的要求。
(3)運行流程
(只要提到框架,就要重視它的運行流程/邏輯順序)
引入:
舉個粟子:
大一新生小明開學,他先到新生接待處等待,老學長學姐(管理人員)看到了就會上前詢問你需要幫忙嘛?小明正愁不知道該幹啥,就說我是來報道的大一新生,管理人員聽了就會將你的信息進行排隊,等排隊到了小明之後,就會將這個號給到管理人員。
然後,管理人員將這個號給到報到處,報到處安排小明的在校信息,比如:班級,宿舍…並將這些信息返還給管理人員。管理人員得到之後會再將這些信息給小明這個大一新生,讓小明覈對下這些是不是自己所需的,經小明認真核對之後發現都是自己想要的,小明跟管理人員說:我已經確認過了就這樣哦!
最後,管理人員就會將這些信息交到信息管理處進行存儲。
注意:圖中的弧線的意義:
如果,在小明拿到信息覈對之後發現這些不是自己所需的,那麼,小明就會告訴管理人員,這些不是我所要的,我要重新請求一下別的東西,然後管理人員就就會將小明進行重新排隊!!!
1.進入正題:
(
spiders網頁爬蟲
items項目
engine引擎
scheduler調度器
downloader下載器
item pipelines項目管道
middleware中間設備,中間件
)
數據流:
上圖顯示了Scrapy框架的體系結構及其組件,以及系統內部發生的數據流(由紅色的箭頭顯示。)
Scrapy中的數據流由執行引擎控制,流程如下:
首先從網頁爬蟲獲取初始的請求
將請求放入調度模塊,然後獲取下一個需要爬取的請求
調度模塊返回下一個需要爬取的請求給引擎
引擎將請求發送給下載器,依次穿過所有的下載中間件
一旦頁面下載完成,下載器會返回一個響應包含了頁面數據,然後再依次穿過所有的下載中間件。
引擎從下載器接收到響應,然後發送給爬蟲進行解析,依次穿過所有的爬蟲中間件
爬蟲處理接收到的響應,然後解析出item和生成新的請求,併發送給引擎
引擎將已經處理好的item發送給管道組件,將生成好的新的請求發送給調度模塊,並請求下一個請求
該過程重複,直到調度程序不再有請求爲止。
中間件介紹:
(1)下載中間件
下載中間件是位於引擎和下載器之間的特定的鉤子,它們處理從引擎傳遞到下載器的請求,以及下載器傳遞到引擎的響應。
如果你要執行以下操作之一,請使用Downloader中間件:
在請求發送到下載程序之前處理請求(即在scrapy將請求發送到網站之前)
在響應發送給爬蟲之前
直接發送新的請求,而不是將收到的響應傳遞給蜘蛛
將響應傳遞給爬行器而不獲取web頁面;
默默的放棄一些請求
(2)爬蟲中間件
爬蟲中間件是位於引擎和爬蟲之間的特定的鉤子,能夠處理傳入的響應和傳遞出去的item和請求。
如果你需要以下操作請使用爬蟲中間件:
處理爬蟲回調之後的請求或item
處理start_requests
處理爬蟲異常
根據響應內容調用errback而不是回調請求
2.各個組件介紹:
Scrapy Engine(引擎)
引擎負責控制系統所有組件之間的數據流,並在發生某些操作時觸發事件。
scheduler(調度器)
調度程序接收來自引擎的請求,將它們排入隊列,以便稍後引擎請求它們。
Downloader(下載器)
下載程序負責獲取web頁面並將它們提供給引擎,引擎再將它們提供給spider。
spider(爬蟲)
爬蟲是由用戶編寫的自定義的類,用於解析響應,從中提取數據,或其他要抓取的請求。
Item pipeline(管道)
管道負責在數據被爬蟲提取後進行後續處理。典型的任務包括清理,驗證和持久性(如將數據存儲在數據庫中)
(3)簡單使用
1.基操(簡單的項目命令)!
(1)創建項目:
(
小知識點:<>爲必填項;[]爲選填項!
小技巧1:pycharm終端輸入scrapy可以查看一些幫助,有助於我們寫那些難記的命令!
小技巧2:scrapy+命令關鍵字,可以查看有關於此命令的詳細用法!
)
1.首先:
cd+要放scrapy項目的文件夾路徑
2.第二步:
通過scrapy命令可以很方便的新建scrapy項目。
語法格式:scrapy startproject <project_name> [project_dir]
該命令會在project_dir文件加下創建一個名爲project_name的Scrapy新項目。如果project_dir沒有指定,project_dir與project_name相同。
執行命令:
scrapy startproject baidu
之後會在指定文件夾創建如下文件:
(2)創建爬蟲文件
{
創建一個bdSpider的類,它必須繼承scrapy.Spider類,需要定義以下三個屬性:
name: spider的名字,必須且唯一
start_urls: 初始的url列表
parse(self, response) 方法:每個初始url完成之後被調用。這個函數要完成一下兩個功能:
解析響應,封裝成item對象並返回這個對象
提取新的需要下載的url,創建新的request,並返回它
我們也可以通過命令創建爬蟲
語法格式:scrapy genspider [-t template]
運行命令:scrapy genspider bd www.baidu.com
會在spiders文件下生成bd.py文件
}
1.首先:
cd 到項目下
2.第二步:
scrapy genspider [options]
scrapy genspider bd www.baidu.com
會創建在項目/spider下 ;其中bd 是爬蟲文件名, www.baidu.com 是 url(域名)
執行命令:
scrapy genspider bd www.baidu.com
之後再項目/spider下創建的文件爲:
# -*- coding: utf-8 -*-
import scrapy
class BdSpider(scrapy.Spider): #繼承了scrapy.Spider類
name = 'bd' #名字是唯一的(不重複) 因爲我們在啓動項目的時候,是根據這個名字來找爬蟲文件的
allowed_domains = ['www.baidu.com'] #允許的域名 (限制) 可以沒有這個限制!
start_urls = ['http://www.baidu.com/'] #首個請求(必須要有) 不然開始都開始不了,怎麼讓整個框架運行下去呢!
def parse(self, response): #必須是parse函數 不可以亂改名 接收下載器下載的數據
print("*******") #用於更直觀的觀察框架能否正常運行!
print("*******")
print("*******")
print("*******")
print("*******")
print("*******")
print(response) #response對象
#獲取數據 兩種方法:
print(response.body.decode()) #獲取到的是字節碼形式
# print(response.text)
注意:最後引擎給spider模塊的數據就給到了函數parse裏的形參response:
(3)運行爬蟲文件
一步即可:
scrapy crawl [options]
其中spider是爬蟲文件名
執行命令:
scrapy crawl bd
但是!我們運行爬蟲文件之後,發現用於測試的print函數沒有顯示,經過檢查終端輸出的數據可知Scrapy框架是默認遵循robots協議的,所以咱們肯定獲取不到數據了!!!
如何解決這個問題呢?
打開設置文件settings.py,將其中的以下代碼更改爲False即可!
# Obey robots.txt rules
ROBOTSTXT_OBEY = True
(2)實操(豆瓣電影top250首頁電影信息的獲取!)
1.創建項目:
scrapy startproject douban
2.創建爬蟲文件:
scrapy genspider db www.summer.com
(注意:這個域名是可以隨便寫的【但是必須要寫哦!】,等爬蟲文件生成之後再進相應的爬蟲文件改爲我們所需的即可!)
# -*- coding: utf-8 -*-
import scrapy
class DbSpider(scrapy.Spider):
name = 'db'
allowed_domains = ['movie.douban.com']
start_urls = ['https://movie.douban.com/top250']
def parse(self, response):
print("*********")
print("*********")
print("*********")
print("*********")
print("*********")
print(response.text)
3.運行爬蟲文件:
scrapy crawl db
但是,我們運行之後發現又沒有獲取到數據哎!
造成這樣的原因是:回想爬蟲的基礎,我們如果直接這樣向網頁發送請求進行爬取,那服務端一眼就看到咱是scrapy了,它還會理咱嘛?所以我們要設置請求頭!
4.設置請求頭:
在配置文件settings.py中找到如下代碼取消註釋並加入爬取網頁請求頭的User-Agent即可!
5.獲取到電影名字:
{
到現在,我們運行爬蟲文件,Scrapy框架已經可以獲取到網頁的首頁數據。那麼,我們如何篩選出我們想要的電影的名字呢?
考慮到我們如果利用xpath匹配,可能要多次嘗試才能正確匹配到,那就需要我們一次又一次的運行咱的項目,多麻煩啊!咱都這樣想了,人家大牛也這樣想啊,所以,在這裏有個賊帥賊帥的牛皮的方法:
使用shell交互式平臺:(注意1:它是遵循settings設置的;注意2:一定要到咱的項目文件夾下運行;)
首先:cd到我們項目的文件路徑下。
然後:輸入命令scrapy shell url (start_url) 即可!
這樣:它其實就請求到了此url的數據(跟上面運行爬蟲文件得到的數據一模一樣)!!!
}
首先:打開我們的shell交互式平臺。
再此項目中:輸入命令scrapy shell https://movie.douban.com/top250
第二步:在shell交互式平臺中匹配我們所需的電影數據。
輸入:response.xpath(’//div[@class=“info”]/div/a/span[1]/text()’)
(
會發現:這得到的是一個selector對象!
而我們得到的數據就是用的response對象自帶的xpath匹配到的(生成了response之後就會自動生成selector對象)!
與我們正常用的xpath不同,它獲取到的數據在selector對象裏,如上圖:
)
第三步:從selector對象中提取電影名字
使用selector對象的方法.extract()。這個方法可以提取到selector對象中data對應的數據。
response.xpath(’//div[@class=“info”]/div/a/span[1]/text()’).extract()
6.將獲取到的電影的信息存儲到text文本中
{
注意:如果想要存儲數據,就要用到管道。
這就涉及到了items.py文件(定義結構化數據字段)和pipelines.py文件(管道文件)。
}
首先:操作items.py文件
因爲我們只需要存儲一個信息,所以定義一個字段名即可!
{
定義公共輸出數據格式,Scrapy提供了Item類。Item對象是用於收集剪貼數據的簡單容器。它們提供了一個類似詞典的API,提供了一種方便的語法來聲明它們的可用字段。 scray.Item對象是用於收集抓取數據的簡單容器,使用方法和python的字典類似。編輯項目目錄下items.py文件。
然後我們只需要在爬蟲中導入我們定義的Item類,實例化後用它進行數據結構化。
}
# -*- coding: utf-8 -*-
# Define here the models for your scraped items
#
# See documentation in:
# https://docs.scrapy.org/en/latest/topics/items.html
import scrapy
class DoubanItem(scrapy.Item):
# define the fields for your item here like:
# name = scrapy.Field()
#需要定義字段名 就像數據庫那樣,有字段名,才能插入數據(即存儲數據)
films_name=scrapy.Field() #定義字段名
第二步:在爬蟲文件中操作數據,使其與管道建立橋樑
{
到目前爲止,我們通過scrapy寫出的爬蟲還看不出優越性在哪裏,並且上面的爬蟲還有個很嚴重的問題,就是對文件的操作。每次調用parse方法會打開文件關閉文件,這極大的浪費了資源。parse函數在解析出我們需要的信息之後,可以將這些信息打包成一個字典對象或scray.Item對象(一般都是item對象),然後返回。這個對象會被髮送到item管道,該管道會通過順序執行幾個組件處理它。每個item管道組件是一個實現簡單方法的Python類。他們收到一個item並對其執行操作,同時決定該item是否應該繼續通過管道或者被丟棄並且不再處理。
item管道的典型用途是:
清理HTML數據
驗證已刪除的數據(檢查項目是否包含某些字段)
檢查重複項(並刪除它們)
將已爬取的item進行數據持久化
}
# -*- coding: utf-8 -*-
import scrapy
from ..items import DoubanItem #因爲我們要使用包含定義字段名的類,所以需要導入
class DbSpider(scrapy.Spider):
name = 'db'
allowed_domains = ['movie.douban.com']
start_urls = ['https://movie.douban.com/top250']
def parse(self, response):
# 獲取電影信息數據
films1_name=response.xpath('//div[@class="info"]/div/a/span[1]/text()').extract()
# 交給管道存儲
# 使用DoubanItem
item=DoubanItem() #創建對象
item["films_name"]=films1_name #值是個列表,因爲xpath匹配到的數據都扔到列表裏了!
# item可以理解爲一個安全的字典 用法與字典相同
print("item裏面是:",dict(item)) #可以轉換爲字典
return item #交給引擎 引擎要交給管道,需要打開管道
第三步:我們要將數據提交給管道,所以需要打開管道
要激活這個管道組件,必須將其添加到ITEM_PIPELINES設置中,在settings.py文件中:
(在此設置中爲類分配的整數值決定了它們運行的順序:按照從較低值到較高值的順序進行。
注意:這個管道的目的只是介紹如何編寫項目管道,如果要將所有爬取的item存儲到json文件中,則應使用Feed導出,在運行爬蟲是加上如下參數:
scrapy crawl bd -o films.json)
第四步:現在數據已經可以交給管道,那麼管道就要對數據進行處理
就是操作pipelines.py文件
# -*- coding: utf-8 -*-
# Define your item pipelines here
#
# Don't forget to add your pipeline to the ITEM_PIPELINES setting
# See: https://docs.scrapy.org/en/latest/topics/item-pipeline.html
import json
class DoubanPipeline(object):
def process_item(self, item, spider):
#爲了能寫進text json.dumps將dic數據轉換爲str
json_str=json.dumps(dict(item),ensure_ascii=False)
with open("films.text","w",encoding="utf-8") as f:
f.write(json_str)
return item