scrapy爬取豆瓣電影資料
1.建立專案
執行如下命令建立scrapy爬蟲專案
scrapy startproject spider_douban
命令執行完成後,建立了spider_douban資料夾,目錄結構如下:
.
├── scrapy.cfg
└── spider_douban
├── __init__.py
├── items.py
├── middlewares.py
├── pipelines.py
├── settings.py
└── spiders
├── douban_spider.py
└── __init__.py
2.建立爬蟲資料模型
開啟 ./spider_douban/items.py 檔案,編輯內容如下:
import scrapy class DoubanMovieItem(scrapy.Item): # 排名 ranking = scrapy.Field() # 電影名稱 movie_name = scrapy.Field() # 評分 score = scrapy.Field() # 評論人數 score_num = scrapy.Field()
3.新建爬蟲檔案
新建 ./spiders/douban_spider.py 檔案,編輯內容如下:
from scrapy import Request from scrapy.spiders import Spider from spider_douban.items import DoubanMovieItem class DoubanMovieTop250Spider(Spider): name = 'douban_movie_top250' start_urls = { '' } ''' 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 = '' yield Request(url, headers=self.headers) ''' def parse(self, response): item = DoubanMovieItem() movies = response.xpath('//ol[@class="grid_view"]/li') print(movies) print('=============================================') 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(r'(d+)人評價')[0] yield item next_url = response.xpath('//span[@class="next"]/a/@href').extract() if next_url: next_url = '' + next_url[0] yield Request(next_url)
爬蟲檔案各部分功能記錄
douban_spider.py檔案主要有幾部分構成。
匯入模組
from scrapy import Request from scrapy.spiders import Spider from spider_douban.items import DoubanMovieItem
Request 類用於請求要爬取的頁面資料
Spider 類是爬蟲的基類
DoubanMovieItem 是我們第一步建立的爬取資料模型
初始設定
基於spider類定義的爬蟲類DoubanMovieTop250Spider中,首先定義爬蟲的基本資訊:
name:在專案中爬蟲的名稱,可以在專案目錄中執行scrapy list獲取已經定義的爬蟲列表
start_urls:是爬取的第一個頁面地址
headers:是向web伺服器傳送頁面請求的時候附加的user-agent訊息,告訴web伺服器是什麼型別的瀏覽器或裝置在請求頁面,對於不具備簡單反爬機制的網站,headers部分可以省略。
為了迷惑web伺服器,一般會在爬蟲傳送web請求的時候定義user-agent資訊,這裡有兩種寫法。
header的第一種定義:
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 = '' yield Request(url, headers=self.headers)
可以看到,這種寫法中,start_urls定義沒有了,轉而定義了start_requests函式,開始的url寫到了函式里。同時,定義了headers字典,在傳送Request請求的時候,將headers字典一併傳送。這種寫法簡單直觀,缺點是在一個爬蟲專案執行期間,所有請求都是一個User-Agent屬性。
header的第二種定義:
start_urls = { '' }
簡單、直接的定義start_urls屬性,而Request中的header屬性透過其他方法另外定義,容後再說。
parse處理函式
逐句分解說明
1.基於我們定義的DoubanMovieItem類建立item例項
item = DoubanMovieItem()
2.解析頁面 - 獲取內容框架
透過分析頁面原始碼,我們能夠看到,頁面中的電影資訊是儲存在了<ol>標籤中,這個<ol>標籤有一個獨特的樣式表grid_view,而每一個單獨的電影資訊儲存在了<li>標籤中,下面程式碼獲取class屬性為grid_view的<ol>標籤下的所有<li>標籤內容。
movies = response.xpath('//ol[@class="grid_view"]/li')
3.解析頁面 - 獲取分項
在每一個<li>標籤中,還有內部結構,透過xpath()解析,將每一項內容解析出來,賦值給item例項中的各個欄位。透過檢視movie.douban.com/top250頁面的原始碼可以很容易找到這個標籤定義的內容。如果我們透過type()函式檢視movies的變數型別,可以發現他的型別是<class 'scrapy.selector.unified.SelectorList'>。<ol>標籤中的每一個<li>標籤都是這個列表中的一項,那麼就可以對movies做迭代。
首先看看<li>標籤中的頁面結構:
可以看到要提取資料的各部分所在標籤位置:
排名:class屬性為pic的<div>標籤下,,<em>標籤中...
電影名:class屬性為hd的<div>標籤下,<a>標籤中的第一個<span>標籤...
評分:class屬性為star的<div>標籤下,class屬性為rating_num的<span>標籤中...
評論人數:class屬性為star的<div>標籤下,<span>標籤中。由於使用了re正規表示式,所以沒有特別指定是哪一個<span>標籤。
回到程式碼部分,對之前定義的movies做迭代,逐項獲取要抓取的資料。
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(r '(d+)人評價')[0] yield item
4.Url跳轉(翻頁)
如果到此為止,我們可以將頁面中的第一頁內容爬取到,但只有25項記錄,要爬取全部的250條記錄,就要執行下面程式碼:
next_url = response.xpath('//span[@class="next"]/a/@href').extract() if next_url: next_url = '' + next_url[0] yield Request(next_url)
首先透過xpath解析了頁面中後頁的連結,並賦值給next_url變數,如果我們當前在第一頁,那麼解析後頁的連結就是?start=25&filter=。將解析的後頁連結與完整url連線形成完整的地址,再次執行Request(),就實現了對全部250條記錄的爬取。注意:透過xpath解析出的結果是列表,所以在引用的時候寫成next_url[0]。
4.處理隨機Head屬性(隨機User-Agent)
實現隨機的head屬性傳送。主要改兩個檔案:
settings.py
USER_AGENT_LIST = [ 'zspider/0.9-dev ', 'Xaldon_WebSpider/2.0.b1', 'Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US) Speedy Spider ()', 'Mozilla/5.0 (compatible; Speedy Spider; )', 'Speedy Spider (Entireweb; Beta/1.3; )', 'Speedy Spider (Entireweb; Beta/1.2; )', 'Speedy Spider (Entireweb; Beta/1.1; )', 'Speedy Spider (Entireweb; Beta/1.0; )', 'Speedy Spider (Beta/1.0; )', 'Speedy Spider ()', 'Speedy Spider ()', 'Speedy Spider (http://)', 'Sosospider+(+)', 'sogou spider', 'Nusearch Spider ()', 'nuSearch Spider (compatible; MSIE 4.01; Windows NT)', 'lmspider (lmspider@scansoft.com)', 'lmspider lmspider@scansoft.com', 'ldspider ()', 'iaskspider/2.0(+)', 'iaskspider', 'hl_ftien_spider_v1.1', 'hl_ftien_spider', 'FyberSpider (+)', 'FyberSpider', 'everyfeed-spider/2.0 ()', 'envolk[ITS]spider/1.6 (+)', 'envolk[ITS]spider/1.6 ( )', 'Baiduspider+(+)', 'Baiduspider+(+)', 'BaiDuSpider', 'Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.0) AddSugarSpiderBot ', ] DOWNLOADER_MIDDLEWARES = { 'spider_douban.middlewares.RandomUserAgentMiddleware': 400, 'scrapy.contrib.downloadermiddleware.useragent.UserAgentMiddleware': None, }
USER_AGENT_LIST定義了一些瀏覽器user-agent屬性,網上有很多,可以找來直接加進去,需要注意的是有些user-agent資訊是移動裝置(手機或平板)的,如果不注意的話,可能請求到的資料與你看到的資料有較大差異;
DOWNLOADER_MIDDLEWARES定義了下載器中介軟體,它在傳送頁面請求資料的時候被呼叫。
middlewares.py
from spider_douban.settings import USER_AGENT_LIST import random class RandomUserAgentMiddleware(): def process_request(self, request, spider): ua = random.choice(USER_AGENT_LIST) if ua: request.headers.setdefault('User-Agent', ua)
在RandomUserAgentMiddleware()中,每次傳送請求資料,會在USER_AGENT_LIST中隨機選擇一條User-Agent記錄。
5.結果儲存
編輯pipelines.py檔案:
from scrapy import signals from scrapy.contrib.exporter import CsvItemExporter class SpiderDoubanPipeline(CsvItemExporter): def __init__(self): self.files = {} @classmethod def from_crawler(cls, crawler): print('==========pipeline==========from_crawler==========') pipeline = cls() crawler.signals.connect(pipeline.spider_opened, signals.spider_opened) crawler.signals.connect(pipeline.spider_closed, signals.spider_closed) return pipeline def spider_opened(self, spider): savefile = open('douban_top250_export.csv', 'wb+') self.files[spider] = savefile print('==========pipeline==========spider_opened==========') self.exporter = CsvItemExporter(savefile) self.exporter.start_exporting() def spider_closed(self, spider): print('==========pipeline==========spider_closed==========') self.exporter.finish_exporting() savefile = self.files.pop(spider) savefile.close() def process_item(self, item, spider): print('==========pipeline==========process_item==========') print(type(item)) self.exporter.export_item(item) return item
SpiderDoubanPipeline類是建立專案的時候自行建立的,為了儲存檔案,做了修改。
def from_crawler(cls, crawler):
如果存在,則呼叫此類方法從Crawler建立pipeline例項。它必須返回一個新的pipeline例項。抓取物件提供對所有Scrapy核心元件的訪問,如settings和signals; 這是pipeline訪問它們並將其功能掛接到Scrapy的一種方式。
在此方法中,定義了一個資料收集器(cls)的例項:‘pipeline’。
signals:Scrapy使用訊號來通知事情發生。您可以在您的Scrapy專案中捕捉一些訊號(使用 extension)來完成額外的工作或新增額外的功能,擴充套件Scrapy。雖然訊號提供了一些引數,不過處理函式不用接收所有的引數 - 訊號分發機制(singal dispatching mechanism)僅僅提供處理器(handler)接受的引數。您可以透過 訊號(Signals) API 來連線(或傳送您自己的)訊號。
connect:連結一個接收器函式(receiver function) 到一個訊號(signal)。signal可以是任何物件,雖然Scrapy提供了一些預先定義好的訊號。
def spider_opened(self, spider):
當spider開始爬取時傳送該訊號。該訊號一般用來分配spider的資源,不過其也能做任何事。該訊號支援返回deferreds。
此方法中,建立了一個檔案物件例項:savefile。
CsvItemExporter(savefile):輸出 csv 檔案格式. 如果新增 fields_to_export 屬性, 它會按順序定義CSV的列名.
def spider_closed(self, spider):
當某個spider被關閉時,該訊號被髮送。該訊號可以用來釋放每個spider在 spider_opened 時佔用的資源。該訊號支援返回deferreds。
def process_item(self, item, spider):
每個item pipeline元件都需要呼叫該方法,這個方法必須返回一個 Item (或任何繼承類)物件, 或是丟擲 DropItem 異常,被丟棄的item將不會被之後的pipeline元件所處理。
啟用pipeline
為了讓我們定義的pipeline生效,要在settings.py檔案中,開啟ITEM_PIPELINES註釋:
ITEM_PIPELINES = { 'spider_douban.pipelines.SpiderDoubanPipeline': 300, }
6.執行爬蟲
scrapy crawl douban_movie_top250
執行爬蟲能夠看到爬取到的資料。。。
如果之前pipeline部分程式碼沒有寫,也可以用下面的命令,在爬蟲執行的時候直接匯出資料:
scrapy crawl douban_movie_top250 -o douban.csv
增加-o引數,可以將爬取到的資料儲存到douban.csv檔案中。。
7.檔案編碼的問題
我在linux伺服器執行爬蟲,生成csv檔案後,在win7系統中用excel開啟變成亂碼。在網上找了一些文章,有的文章直接改變linux檔案預設編碼,但是感覺這麼做會對其他專案產生影響。最後選擇一個相對簡單的方式。按這幾步執行就可以:
不要直接用excel開啟csv檔案。先開啟excel,建立空白工作表。
選擇資料選項卡,開啟獲取外部資料中的自文字。
在匯入文字檔案對話方塊中選擇要匯入的csv檔案。
在文字匯入嚮導 - 第1步中,設定檔案原始格式為65001 : Unicode (UTF-8)
繼續下一步選擇逗號分隔,就可以匯入正常文字了。
更多python爬蟲相關文章請關注。
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/2331/viewspace-2833488/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- scrapy入門:豆瓣電影top250爬取
- Python爬蟲筆記(4):利用scrapy爬取豆瓣電影250Python爬蟲筆記
- python更換代理爬取豆瓣電影資料Python
- 爬取豆瓣電影Top250和資料分析
- python爬蟲 爬取豆瓣電影 1-10 ajax 資料Python爬蟲
- 爬蟲01:爬取豆瓣電影TOP 250基本資訊爬蟲
- Python爬取分析豆瓣電影Top250Python
- 使用python爬取豆瓣電影TOP250Python
- 爬蟲教程——用Scrapy爬取豆瓣TOP250爬蟲
- 【python爬蟲案例】利用python爬取豆瓣電影TOP250評分排行資料!Python爬蟲
- Python爬蟲教程-17-ajax爬取例項(豆瓣電影)Python爬蟲
- 豆瓣top250資料爬取
- Python爬取豆瓣電影的短評資料並進行詞雲分析處理Python
- 正規表示式_爬取豆瓣電影排行Top250
- Selenium + Scrapy爬取某商標資料
- 如何提升scrapy爬取資料的效率
- 爬蟲如何爬取貓眼電影TOP榜資料爬蟲
- Springboot+JPA下實現簡易爬蟲--爬取豆瓣電視劇資料Spring Boot爬蟲
- Python爬蟲框架:scrapy爬取高考派大學資料Python爬蟲框架
- java爬取豆瓣書籍資訊Java
- 手把手教你網路爬蟲(爬取豆瓣電影top250,附帶原始碼)爬蟲原始碼
- 教你用python登陸豆瓣並爬取影評Python
- 資料視覺化豆瓣電影 TOP250視覺化
- Python爬取電影天堂Python
- scrapy 爬取空值
- Puppeteer 爬取豆瓣小組公開資訊
- 擼個爬蟲,爬取電影種子爬蟲
- Python3爬取貓眼電影資訊Python
- python——豆瓣top250爬取Python
- 【Python】從0開始寫爬蟲——轉身扒豆瓣電影Python爬蟲
- Scrapy爬取二手房資訊+視覺化資料分析視覺化
- 豆瓣電影TOP250爬蟲及視覺化分析筆記爬蟲視覺化筆記
- Scrapy框架的使用之Scrapy爬取新浪微博框架
- 使用 Scrapy 爬取股票程式碼
- Scrapy框架爬取海量妹子圖框架
- 批量抓取豆瓣電影圖片
- Python 從底層結構聊 Beautiful Soup 4(內建豆瓣最新電影排行榜爬取案例)Python
- scrapy爬取鏈家二手房存到mongo資料庫Go資料庫