近日,有朋友向我求助一件小事兒,他在一個(gè)短視頻app上看到一個(gè)好玩兒的段子,想下載下來,可死活找不到下載的方法。這忙我得幫,少不得就抓包分析了一下這個(gè)app,找到了視頻的下載鏈接,幫他解決了這個(gè)小問題。
因?yàn)檫@個(gè)事兒,勾起了我另一個(gè)念頭,這不最近一直想把python爬蟲方面的知識(shí)梳理梳理嗎,干脆借機(jī)行事,正湊著短視頻火熱的勢(shì)頭,做一個(gè)短視頻的爬蟲好了,中間用到什么知識(shí)就理一理。
我喜歡把事情說得很直白,如果恰好有初入門的朋友想了解爬蟲的技術(shù),可以將就看看,或許對(duì)你的認(rèn)識(shí)會(huì)有提升。如果有高手路過,最好能指點(diǎn)一二,本人不勝感激。
一、撕開爬蟲的面紗——爬蟲是什么,它能做什么
爬蟲是什么
爬蟲就是一段能夠從互聯(lián)網(wǎng)上高效獲取數(shù)據(jù)的程序。
我們每天都在從互聯(lián)網(wǎng)上獲取數(shù)據(jù)。當(dāng)打開瀏覽器訪問百度的時(shí)候,我們就從百度的服務(wù)器獲取數(shù)據(jù),當(dāng)拿起手機(jī)在線聽歌的時(shí)候,我們就從某個(gè)app的服務(wù)器上獲取數(shù)據(jù)。簡單的歸納,這些過程都可以描述為:我們提交一個(gè)Request請(qǐng)求,服務(wù)器會(huì)返回一個(gè)Response數(shù)據(jù),應(yīng)用根據(jù)Response來渲染頁面,給我們展示數(shù)據(jù)結(jié)果。
爬蟲最核心的也是這個(gè)過程,提交Requests——〉接受Response。就這樣,很簡單,當(dāng)我們?cè)跒g覽器里打開一個(gè)頁面,看到頁面內(nèi)容的時(shí)候,我們就可以說這個(gè)頁面被我們采集到了。
只不過當(dāng)我們真正進(jìn)行數(shù)據(jù)爬取時(shí),一般會(huì)需要采集大量的頁面,這就需要提交許多的Requests,需要接受許多的Response。數(shù)量大了之后,就會(huì)涉及到一些比較復(fù)雜的處理,比如并發(fā)的,比如請(qǐng)求序列,比如去重,比如鏈接跟蹤,比如數(shù)據(jù)存儲(chǔ),等等。于是,隨著問題的延伸和擴(kuò)展,爬蟲就成為了一個(gè)相對(duì)獨(dú)立的技術(shù)門類。
但它的本質(zhì)就是對(duì)一系列網(wǎng)絡(luò)請(qǐng)求和網(wǎng)絡(luò)響應(yīng)的處理。
爬蟲能做什么
爬蟲的作用和目的只有一個(gè),獲取網(wǎng)絡(luò)數(shù)據(jù)。我們知道,互聯(lián)網(wǎng)是個(gè)數(shù)據(jù)的海洋,大量的信息漂浮在其中,想把這些資源收歸己用,爬蟲是最常用的方式。特別是最近幾年大樹據(jù)挖掘技術(shù)和機(jī)器學(xué)習(xí)以及知識(shí)圖譜等技術(shù)的興盛,更是對(duì)數(shù)據(jù)提出了更大的需求。另外也有很多互聯(lián)網(wǎng)創(chuàng)業(yè)公司,在起步初期自身積累數(shù)據(jù)較少的時(shí)候,也會(huì)通過爬蟲快速獲取數(shù)據(jù)起步。
二、python爬蟲框架scrapy——爬蟲開發(fā)的利器
如果你剛剛接觸爬蟲的概念,我建議你暫時(shí)不要使用scrapy框架。或者更寬泛的說,如果你剛剛接觸某一個(gè)技術(shù)門類,我都不建議你直接使用框架,因?yàn)榭蚣苁菍?duì)許多基礎(chǔ)技術(shù)細(xì)節(jié)的高級(jí)抽象,如果你不了解底層實(shí)現(xiàn)原理就直接用框架多半會(huì)讓你云里霧里迷迷糊糊。
在入門爬蟲之初,看scrapy的文檔,你會(huì)覺得“太復(fù)雜了”。當(dāng)你使用urllib或者Requests開發(fā)一個(gè)python的爬蟲腳本,并逐個(gè)去解決了請(qǐng)求頭封裝、訪問并發(fā)、隊(duì)列去重、數(shù)據(jù)清洗等等問題之后,再回過頭來學(xué)習(xí)scrapy,你會(huì)覺得它如此簡潔優(yōu)美,它能節(jié)省你大量的時(shí)間,它會(huì)為一些常見的問題提供成熟的解決方案。
scrapy數(shù)據(jù)流程圖
這張圖是對(duì)scrapy框架的經(jīng)典描述,一時(shí)看不懂沒有關(guān)系,用一段時(shí)間再回來看。或者把本文讀完再回來看。

在一些書上會(huì)把爬蟲的基本抓取流程概括為UR 2 IM,意思是數(shù)據(jù)爬取的過程是圍繞URL、Request(請(qǐng)求)、Response(響應(yīng))、Item(數(shù)據(jù)項(xiàng))、MoreUrl(更多的Url)展開的。上圖的 綠色箭頭 體現(xiàn)的正是這幾個(gè)要素的流轉(zhuǎn)過程。圖中涉及的四個(gè)模塊正是用于處理這幾類對(duì)象的:
各個(gè)模塊和scrapy引擎之間可以添加一層或多層中間件,負(fù)責(zé)對(duì)出入該模塊的UR 2 IM對(duì)象進(jìn)行處理。
scrapy的安裝
參考官方文檔,不再贅述。官方文檔:https://scrapy-chs.readthedocs.io/zh_CN/0.24/intro/install.html
三、scrapy實(shí)戰(zhàn):50行代碼爬取全站短視頻
python的優(yōu)雅之處在于能夠讓開發(fā)者專注于業(yè)務(wù)邏輯,花更少的時(shí)間在枯燥的代碼編寫調(diào)試上。scrapy無疑完美詮釋了這一精神。
開發(fā)爬蟲的一般步驟是:
那么,我們一步一步來。
既然是使用scrapy框架,我們先創(chuàng)建項(xiàng)目:
scrapy startproject DFVideo
緊接著,我們創(chuàng)建一個(gè)爬蟲:
scrapy genspider -t crawl DfVideoSpider eastday.com
這是我們發(fā)現(xiàn)在當(dāng)前目錄下已經(jīng)自動(dòng)生成了一個(gè)目錄:DFVideo
目錄下包括如圖文件:

spiders文件夾下,自動(dòng)生成了名為DfVideoSpider.py的文件。

爬蟲項(xiàng)目創(chuàng)建之后,我們來確定需要爬取的數(shù)據(jù)。在items.py中編輯:
import scrapyclass DfvideoItem(scrapy.Item): # define the fields for your item here like: # name = scrapy.Field() video_url = scrapy.Field()#視頻源url video_title = scrapy.Field()#視頻標(biāo)題 video_local_path = scrapy.Field()#視頻本地存儲(chǔ)路徑
接下來,我們需要確定視頻源的url,這是很關(guān)鍵的一步。
現(xiàn)在許多的視頻播放頁面是把視頻鏈接隱藏起來的,這就使得大家無法通過右鍵另存為,防止了視頻別隨意下載。
但是只要視頻在頁面上播放了,那么必然是要和視頻源產(chǎn)生數(shù)據(jù)交互的,所以只要稍微抓下包就能夠發(fā)現(xiàn)玄機(jī)。
這里我們使用fiddler抓包分析。
發(fā)現(xiàn)其視頻播放頁的鏈接類似于:video.eastday.com/a/180926221513827264568.html?index3lbt
視頻源的數(shù)據(jù)鏈接類似于:mvpc.eastday.com/vyule/20180415/20180415213714776507147_1_06400360.mp4
有了這兩個(gè)鏈接,工作就完成了大半:
在DfVideoSpider.py中編輯
# -*- coding: utf-8 -*-import scrapyfrom scrapy.loader import ItemLoaderfrom scrapy.loader.processors import MapCompose,Joinfrom DFVideo.items import DfvideoItemfrom scrapy.linkextractors import LinkExtractorfrom scrapy.spiders import CrawlSpider, Ruleimport timefrom os import pathimport osclass DfvideospiderSpider(CrawlSpider): name = 'DfVideoSpider' allowed_domains = ['eastday.com'] start_urls = ['http://video.eastday.com/'] rules = ( Rule(LinkExtractor(allow=r'video.eastday.com/a//d+.html'), callback='parse_item', follow=True), ) def parse_item(self, response): item = DfvideoItem() try: item["video_url"] = response.xpath('//input[@id="mp4Source"]/@value').extract()[0] item["video_title"] = response.xpath('//meta[@name="description"]/@content').extract()[0] #print(item) item["video_url"] = 'http:' + item['video_url'] yield scrapy.Request(url=item['video_url'], meta=item, callback=self.parse_video) except: pass def parse_video(self, response): i = response.meta file_name = Join()([i['video_title'], '.mp4']) base_dir = path.join(path.curdir, 'VideoDownload') video_local_path = path.join(base_dir, file_name.replace('?', '')) i['video_local_path'] = video_local_path if not os.path.exists(base_dir): os.mkdir(base_dir) with open(video_local_path, "wb") as f: f.write(response.body) yield i至此,一個(gè)簡單但強(qiáng)大的爬蟲便完成了。
如果你希望將視頻的附加數(shù)據(jù)保存在數(shù)據(jù)庫,可以在pipeline.py中進(jìn)行相應(yīng)的操作,比如存入mongodb中:
from scrapy import logimport pymongoclass DfvideoPipeline(object): def __init__(self): self.mongodb = pymongo.MongoClient(host='127.0.0.1', port=27017) self.db = self.mongodb["DongFang"] self.feed_set = self.db["video"] # self.comment_set=self.db[comment_set] self.feed_set.create_index("video_title", unique=1) # self.comment_set.create_index(comment_index,unique=1) def process_item(self, item, spider): try: self.feed_set.update({"video_title": item["video_title"]}, item, upsert=True) except: log.msg(message="dup key: {}".format(item["video_title"]), level=log.INFO) return item def on_close(self): self.mongodb.close()當(dāng)然,你需要在setting.py中將pipelines打開:
ITEM_PIPELINES = { 'TouTiaoVideo.pipelines.ToutiaovideoPipeline': 300,}四、執(zhí)行結(jié)果展示
視頻文件:

五、最后
以上所述是小編給大家介紹的Python 利用scrapy爬蟲通過短短50行代碼下載整站短視頻,希望對(duì)大家有所幫助,如果大家有任何疑問請(qǐng)給我留言,小編會(huì)及時(shí)回復(fù)大家的。在此也非常感謝大家對(duì)VEVB武林網(wǎng)網(wǎng)站的支持!
新聞熱點(diǎn)
疑難解答
圖片精選