這兩天摸索了下scrapy,剛看文檔的時候覺得有點生無可戀,scrapy框架個人還是覺得比較難懂的,需要學習的地方非常多,之前用beautifulsoup4爬過top250,比scrapy簡單更容易理解!!
Scrapy簡介
Scrapy,Python開發的一個快速、高層次的屏幕抓取和web抓取框架,用于抓取web站點并從頁面中提取結構化的數據。Scrapy用途廣泛,可以用于數據挖掘、監測和自動化測試。 下面對每個組件都做了簡單介紹,數據流如下所描述。
- Scrapy Engine
引擎負責控制數據流在系統中所有組件中流動,并在相應動作發生時觸發事件。 詳細內容查看下面的數據流(Data Flow)部分 - 調度器(Scheduler)
調度器從引擎接受request并將他們入隊,以便之后引擎請求他們時提供給引擎 - 下載器(Downloader)
下載器負責獲取頁面數據并提供給引擎,而后提供給spider - Spiders
Spider是Scrapy用戶編寫用于分析response并提取item(即獲取到的item)或額外跟進的URL的類。 每 個spider負責處理一個特定(或一些)網站 - Item Pipeline
Item Pipeline負責處理被spider提取出來的item。典型的處理有清理、 驗證及持久化(例如存取到數 據庫中) - 下載器中間件(Downloader middlewares)
下載器中間件是在引擎及下載器之間的特定鉤子(specific hook),處理Downloader傳遞給引擎的 response。 其提供了一個簡便的機制,通過插入自定義代碼來擴展Scrapy功能 - Spider中間件(Spider middlewares)
Spider中間件是在引擎及Spider之間的特定鉤子(specific hook),處理spider的輸入(response)和輸出 (items及requests)。 其提供了一個簡便的機制,通過插入自定義代碼來擴展Scrapy功能 - 數據流(Data flow)
Scrapy中的數據流由執行引擎控制,其過程如下:
引擎打開一個網站(open a domain),找到處理該網站的Spider并向該spider請求第一個要爬取的 URL(s)。
引擎從Spider中獲取到第一個要爬取的URL并在調度器(Scheduler)以Request調度。
引擎向調度器請求下一個要爬取的URL。
調度器返回下一個要爬取的URL給引擎,引擎將URL通過下載中間件(請求(request)方向)轉發給下載 器(Downloader)。
一旦頁面下載完畢,下載器生成一個該頁面的Response,并將其通過下載中間件(返回(response)方 向)發送給引擎。
引擎從下載器中接收到Response并通過Spider中間件(輸入方向)發送給Spider處理。
Spider處理Response并返回爬取到的Item及(跟進的)新的Request給引擎。
引擎將(Spider返回的)爬取到的Item給Item Pipeline,將(Spider返回的)Request給調度器。
(從第二步)重復直到調度器中沒有更多地request,引擎關閉該網站
scrapy的流程如圖,并且可歸納如下
- 首先下載器下載request回執的html等的response
- 然后下載器傳給爬蟲解析
- 接著爬蟲解析后交給調度器過濾,查重等等
- 最后交給管道,進行爬取數據的處理
建議大家參考下中文版的Scrapy文檔,看文檔還是比較枯燥的,Scrapy又比較難懂(大神忽略),務必要有耐心!!!!!!
實戰應用
首先下載Scrapy包
pip install scrapy
這樣安裝,windows平臺應該是會報錯的,我當時裝Scrapy時廢了很大勁才弄完。安裝過程中Pycharm或者官網上找不到的模塊可以上這個網址找Unofficial Windows Binaries for Python Extension Packages
Pywin32
接著,我們打開CMD,新建一個爬蟲文件
scrapy startproject douban
C:\Users\ssaw\douban>tree /f
C:.
│ scrapy.cfg
│
└─douban
│ items.py
│ middlewares.py
│ pipelines.py
│ settings.py
│ init.py
│
└─spiders
init.py
簡單介紹下這些文件
- scrapy.cfg: 項目的配置文件
- douban/: 該項目的python模塊。之后您將在此加入代碼
- douban/items.py: 項目中的item文件
- douban/pipelines.py: 項目中的pipelines文件
- douban/settings.py: 項目的設置文件
- douban/spiders/:放置spider代碼的目錄
編輯items.py文件
# -*- coding: utf-8 -*-
# Define here the models for your scraped items
#
# See documentation in:
# http://doc.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_name = scrapy.Field()
movie_star = scrapy.Field()
movie_quote = scrapy.Field()
- 首先,引入Scrapy
- 接著,創建一個類,繼承自scrapy.item,這個是用來儲存要爬下來的數據的存放容器,類似orm的寫法
- 我們要記錄的是:電影的名字、電影的評分、電影的引述(quote)
現在,我們在spiders文件夾下創建douban_spider.py
在我們編寫爬蟲之前,先了解一下scrapy的爬取機制,scrapy提取數據有自己的一套機制。它們被稱作選擇器(seletors),因為他們通過特定的 XPath 或者 CSS 表達式來“選擇” HTML文件中的某個部分。
之前我在博客上也總結過一篇使用Xpath模擬登陸GitHub有興趣可以看一下
附上Xpath學習教程Xpath
獲取網頁數據
打開Chrome(F12),查找元素
豆瓣電影TOP250
紅框圈出來的分別代表
movie_name = div[@class="hd"]/a/span/
movie_star = div[@class="bd"]/div[@class="star"]/span[@class="rating_num"]
movie_quote = div[@class="bd"]/p[@class="quote"]/span[@class="inq"]
# _*_ coding=utf-8 _*_
from scrapy.spiders import Spider
from scrapy.selector import Selector
class DouBanSpider(Spider):
name = 'db'
start_urls = ['https://movie.douban.com/top250']
def parse(self, response):
# print(response.body)
selector = Selector(response)
# print(selector)
movies = selector.xpath('//div[@class="info"]')
for movie in movies:
movie_name = movie.xpath('div[@class="hd"]/a/span/text()').extract()
movie_star = movie.xpath('div[@class="bd"]/div[@class="star"]/span[@class="rating_num"]/text()').extract()
movie_quote = movie.xpath('div[@class="bd"]/p[@class="quote"]/span[@class="inq"]/text()').extract()
print(movie_name)
print(movie_star)
print(movie_quote)
我們打開setting.py,加上U-A
USER_AGENT = 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.100 Safari/537.36'
在CMD中輸入scrapy crawl db,運行如下:
我們還可以在douban文件根目錄創建一個main.py,這樣就可以在Pycharm中運行了
from scrapy import cmdline
cmdline.execute("scrapy crawl db".split())
使用Item
Item對象是自定義的python字典。 您可以使用標準的字典語法來獲取到其每個字段的值。(字段即是我們之前用Field賦值的屬性),Spider將會將爬取到的數據以 Item 對象返回。
item = DoubanItem()
item['movie_name'] = movie_name
item['movie_star'] = movie_star
item['movie_quote'] = movie_quote
好了,現在我們先試著爬取單頁面,查看下結果后,再去爬取多頁面
from scrapy.spiders import Spider
from scrapy.selector import Selector
from douban.items import DoubanItem
class DouBanSpider(Spider):
name = 'db'
start_urls = ['https://movie.douban.com/top250']
def parse(self, response):
# print(response.body)
selector = Selector(response)
# print(selector)
movies = selector.xpath('//div[@class="info"]')
for movie in movies:
movie_name = movie.xpath('div[@class="hd"]/a/span/text()').extract()
movie_star = movie.xpath('div[@class="bd"]/div[@class="star"]/span[@class="rating_num"]/text()').extract()
movie_quote = movie.xpath('div[@class="bd"]/p[@class="quote"]/span[@class="inq"]/text()').extract()
#print(movie_name)
#print(movie_star)
#print(movie_quote)
item = DoubanItem()
item['movie_name'] = movie_name
item['movie_star'] = movie_star
item['movie_quote'] = movie_quote
yield item
print(movie_name)
print(movie_star)
print(movie_quote)
- 首先,我們先從scrapy中獲得所需要的通用的 spider和 selector
- 接著,我們使用Item將爬取的數據返回
- 創建了一個DouBanSpider,繼承了 scrapy.Spider 類, 且定義以下三個屬性:
- name: 用于區別Spider。 該名字必須是唯一的,您不可以為不同的Spider設定相同的名字
- start_urls: 包含了Spider在啟動時進行爬取的url列表。 因此,第一個被獲取到的頁面將是其中之一, 后續的URL則從初始的URL獲取到的數據中提取。
- parse() 是spider的一個方法。 被調用時,每個初始URL完成下載后生成的 Response 對象將會作為唯一的參數傳遞給該函數。 該方法負責解析返回的數據(response data),提取數據(生成item)以及生成需要進一步處理的URL的 Request 對象
- seletor的方法返回后一定要用它的 extract()方法,來返回一個列表 ;extract()文檔的定義:串行化并將匹配到的節點返回一個unicode字符串列表。 結尾是編碼內容的百分比
- 接著,我們把得到的數據保存在Item中
- 最后,我們使用Feed exports來保存數據
- 這里使用了yield生成器函數,生成器函數和迭代器有密切關系,也并不是很容易理解,這一點需要多多學習
#看一個yield函數的示例
#函數在每次循環時都會產生一個值,之后將其返回給它的調用者
#函數不斷的生成數字的平方
def gensquares(N):
for i in range(N):
yield i ** 2
for i in gensquares(5):
print(i, end=' ')
0 1 4 9 16
好了,spider暫時寫完了,我們試著運行下
scrapy crawl db -o douban.json -t json
-o 后面是導出文件名,-t 后面是導出類型。
然后來看一下導出的結果,Pycharm打開json文件即可
打印出來的內容需要編碼
我們換種方式,把文件格式保存為CSV,使用EXCEL打開
scrapy crawl db -o douban.csv -t csv
用excel打開后假如是一堆亂碼,就使用記事本打開,把它“另存為”時,編碼選擇ANSI
好了,現在我們添加多頁面鏈接,完整地把TOP250爬取下來
我們從Elements中找到翻頁lianjie
next_page =response.selector.xpath('//span[@class="next"]/link/@href').extract()
if next_page:
next_page = next_page[0]
print(next_page)
yield Request(self.url + next_page, callback=self.parse)
CMD輸入scrapy crawl db -o douban.csv -t csv ,開始運行
學習Scrapy需要反復查看文檔、資料,這是個簡單的學習總結,這兩天準備再去學習MongoDB數據庫,大家一起加油!!