Github項目地址:https://github.com/xylon666/Scrapy
Scrapy框架,簡單來說就是把爬蟲各功能模塊分割開來,分別負責相應的功能,讓我們通過簡單的學習和實踐來使用他
框架示意圖:
架構分析:
Scrapy Engine
:Scrapy引擎。負責控制數據流在系統中所有組件中流動,並在相應動作發生時觸發事件。Scheduler
:調度器。從Scrapy Engine接受請求(requests)並排序列入隊列,並在引擎再次請求時返回。用它來決定下一個抓取的網址是什麼,同時去除重複的網址。Downloader
:下載器。抓取網頁並將網頁內容返還給Spiders。建立在twisted異步模型。Spiders
:爬蟲。用戶自定義的類,主要用來解析網頁,提取Items,發送url跟進等新請求等。Item Pipelines
:管道。主要用來處理Spider解析出來的Items,進行按規則過濾,驗證,持久化存儲(如數據庫存儲)等Downloader Middlewares
:下載中間件。位於Scrapy Engine和Downloader之間,主要是處理Scrapy引擎與下載器之間的請求及響應。Spider Middlewares
:爬蟲中間件。位於Scrapy Engine和Spiders之間,主要工作是處理Spiders的響應輸入和請求輸出。Scheduler Middlewares
:調度中間件。位於Scrapy Engine和Scheduler之間。主要工作是處理從Scrapy Engine發送到Scheduler的請求和響應。
所需環境:
編譯器:Pycharm
第三方庫:scrapy
Scrapy相關依賴庫:
lxml
parsel
w3lib
twisted
cryptography
pyOpenSSL
均可通過pip install 安裝
實踐目標:
使用Scrapy框架爬取豆瓣電影排行版Top250
創建項目:
選擇創建項目的文件路徑,如在D盤創建一個文件夾"Douban_Scrapy"
然後運行cmd,cd到該目錄
d:
cd D:\Douban_Scrapy
創建項目:
scrpay startproject douban
運行後我們會發現在該目錄下多了幾個文件,在Pycharm中打開:
對比文章開頭的框架示意圖,簡單介紹下他們的功能
spiders目錄:編寫爬蟲代碼的主體
items:存放獲取數據的相關元素
middlewares:定義爬蟲過程中的操作
pipelines:定義存儲信息時的操作,例如將數據傳入ManggoDB或MySQL
setting:顧名思義,用來定義我們的各種配置,比如請求頭信息等
初始化爬蟲:
運行cmd,cd到爬蟲project的spiders目錄,執行:
scrapy genspider douban_spider movie.douban.com
這樣一個爬蟲模板就自動建好了
由於需要多次運行cmd來執行scrapy命令,我們可以通過Pycharm直接在編譯器內來實現這一過程
在spiders目錄新建main.py:
from scrapy import cmdline
cmdline.execute('scrapy genspider douban_spider movie.douban.com'.split())
運行後無需通過cmd就能執行命令了
再修改一下setting配置:
USER_AGENT = 'Mozilla/5.0 (Windows NT 10.0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.169 Safari/537.36'
#僞裝頭
ROBOTSTXT_OBEY = False
#忽略網頁的爬蟲規則
DOWNLOAD_DELAY = 0.5
#下載延時
再來看一下要爬的內容:
我們通過該頁面可以獲取到的信息有:排名,電影名,星級,評價人數,描述
根據爬取對象編輯items.py文件
# -*- 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()
# 排名
movie_num = scrapy.Field()
# 電影名稱
movie_name = scrapy.Field()
# 星級
star = scrapy.Field()
# 評價人數
value = scrapy.Field()
# 描述
describle = scrapy.Field()
編輯爬蟲代碼douban_spider.py:
# -*- coding: utf-8 -*-
import scrapy
class DoubanSpiderSpider(scrapy.Spider):
#爬蟲名稱
name = 'douban_spider'
#爬蟲允許抓取的域名
allowed_domains = ['movie.douban.com']
#獲取數據傳給調度器的地址
start_urls = ['http://movie.douban.com/top250']
def parse(self, response):
print(response.text)
執行命令:
在cmd中對應目錄下
scrapy crawl douban_spider
或在Pycharm中spiders目錄下新建main.py
from scrapy import cmdline
cmdline.execute('scrapy crawl douban_spider'.split())
執行結果,可以發現成功獲取到了豆瓣網頁源代碼
分析頁面:
網頁源代碼已獲取,再來看要爬取的內容:
電影信息都在div class='"article"//ol class="grid_view"下的<li>標籤內,通過xpath對其解析獲取:
# -*- coding: utf-8 -*-
import scrapy
class DoubanSpiderSpider(scrapy.Spider):
name = 'douban_spider'
allowed_domains = ['movie.douban.com']
start_urls = ['http://movie.douban.com/top250']
def parse(self, response):
movie_list = response.xpath("//div[@class='article']//ol[@class='grid_view']/li")
for item in movie_list:
print(item)
如果你不知道xpath,推薦閱讀:xpath語法
獲取該頁面所有電影信息後,從中提取出我們需要的部分
導入模型文件:
from ..items import DoubanItem
從我們剛剛獲得的電影信息中,根據節點信息獲取電影排名:
for item in movie_list:
douban_item = DoubanItem()
#模型初始化
douban_item['movie_num'] = item.xpath(".//div[@class='item']//em/text()").get()
#從當前標籤起始,訪問目標標籤獲取文本信息,將其寫入movie_num
以此類推,獲取後面的內容
for item in movie_list:
douban_item = DoubanItem()
douban_item['movie_num'] = item.xpath(".//div[@class='item']//em/text()").get()
douban_item['movie_name'] = item.xpath(".//div[@class='info']/div[@class='hd']/a/span[1]/text()").get()
douban_item['star'] = item.xpath(".//div[@class='bd']/div[@class='star']/span[2]/text()").get()
douban_item['value'] = item.xpath(".//div[@class='bd']/div[@class='star']/span[4]/text()").get()
douban_item['describle'] = item.xpath(".//div[@class='bd']/p[@class='quote']/span/text()").get()
print(douban_item)
yield douban_item
#將返回結果壓入item Pipline進行處理
運行結果(紅色信息是正常情況):
循環獲取當前頁面所有電影信息後,我們需要訪問下一頁繼續獲取數據,右鍵檢查“後頁”
根據標籤信息,拼接前綴獲取完整鏈接並訪問下一頁
next_link = response.xpath("//span[@class='next']/link/@href").get()
if next_link:
yield scrapy.Request('http://movie.douban.com/top250' + next_link, callback=self.parse)
通過輸出結果可以看到成功訪問到了最後一頁
完整代碼:
# -*- coding: utf-8 -*-
import scrapy
from ..items import DoubanItem
class DoubanSpiderSpider(scrapy.Spider):
#爬蟲名稱
name = 'douban_spider'
#爬蟲允許抓取的域名
allowed_domains = ['movie.douban.com']
#獲取數據傳給調度器的地址
start_urls = ['http://movie.douban.com/top250']
def parse(self, response):
movie_list = response.xpath("//div[@class='article']//ol[@class='grid_view']/li")
for item in movie_list:
douban_item = DoubanItem()
douban_item['movie_num'] = item.xpath(".//div[@class='item']//em/text()").get()
douban_item['movie_name'] = item.xpath(".//div[@class='info']/div[@class='hd']/a/span[1]/text()").get()
douban_item['star'] = item.xpath(".//div[@class='bd']/div[@class='star']/span[2]/text()").get()
douban_item['value'] = item.xpath(".//div[@class='bd']/div[@class='star']/span[4]/text()").get()
douban_item['describle'] = item.xpath(".//div[@class='bd']/p[@class='quote']/span/text()").get()
print(douban_item)
yield douban_item
#將返回結果壓入item Pipline進行處理
next_link = response.xpath("//span[@class='next']/link/@href").get()
if next_link:
yield scrapy.Request('http://movie.douban.com/top250' + next_link, callback=self.parse)
保存文件:
保存爲csv文件:
scrapy crawl douban_spider -o movielist.csv
保存爲json文件:
scrapy crawl douban_spider -o movielist.json
注意:使用excel打開csv文件時,常常會發生亂碼,這是由於csv數據用逗號分隔,而excel通過ANSI解碼導致的
解決方法:
在爬蟲文件中添加以下代碼,預先設置csv文件的編碼格式爲UTF8-BOM
import codecs
with codecs.open('movielist.csv','wb+') as f:
f.write(codecs.BOM_UTF8)
結果展示: