如何用 Python + Scrapy 爬取視頻?
本文轉載自微信公眾號「快學Python」,作者快快。轉載本文請聯系快學Python公眾號。
人生苦短,快學Python!
今天將帶大家簡單了解Scrapy爬蟲框架,并用一個真實案例來演示代碼的編寫和爬取過程。
一、scrapy簡介
1. 什么是Scrapy
Scrapy是一個為了爬取網站數據,提取結構性數據而編寫的應用框架,我們只需要實現少量的代碼,就能夠快速的抓取
Scrapy使用了Twisted異步網絡框架,可以加快我們的下載速度
http://scrapy-chs.readthedocs.io/zh_CN/1.0/intro/overview.html
異步和非阻塞的區別
異步:調用在發出之后,這個調用就直接返回,不管有無結果
非阻塞:關注的是程序在等待調用結果時的狀態,指在不能立刻得到結果之前,該調用不會阻塞當前線程
2. Scrapy工作流程
另一種爬蟲方式
Scrapy工作流程
Scrapy engine(引擎) | 總指揮:負責數據和信號的在不同模塊間的傳遞 | scrapy已經實現 |
---|---|---|
Scheduler(調度器) | 一個隊列,存放引擎發過來的request請求 | scrapy已經實現 |
Downloader(下載器) | 下載把引擎發過來的requests請求,并返回給引擎 | scrapy已經實現 |
Spider(爬蟲) | 處理引擎發來的response,提取數據,提取url,并交給引擎 | 需要手寫 |
Item Pipline(管道) | 處理引擎傳過來的數據,比如存儲 | 需要手寫 |
Downloader Middlewares(下載中間件) | 可以自定義的下載擴展,比如設置代理 | 一般不用手寫 |
Spider Middlewares(中間件) | 可以自定義requests請求和進行response過濾 | 一般不用手寫 |
3. Scrapy入門
- #1 創建一個scrapy項目
- scrapy startproject mySpider
- #2 生成一個爬蟲
- scrapy genspider demo "demo.cn"
- #3 提取數據
- 完善spider 使用xpath等
- #4 保存數據
- pipeline中保存數據
在命令中運行爬蟲
- scrapy crawl qb # qb爬蟲的名字
在pycharm中運行爬蟲
- from scrapy import cmdline
- cmdline.execute("scrapy crawl qb".split())
4. pipline使用
從pipeline的字典形可以看出來,pipeline可以有多個,而且確實pipeline能夠定義多個
為什么需要多個pipeline:
1 可能會有多個spider,不同的pipeline處理不同的item的內容
2 一個spider的內容可以要做不同的操作,比如存入不同的數據庫中
注意:
1 pipeline的權重越小優先級越高
2 pipeline中process_item方法名不能修改為其他的名稱
5. 文件目錄結構
文件配置:
setting:
- SPIDER_MODULES = ['st.spiders']
- NEWSPIDER_MODULE = 'st.spiders'
- LOG_LEVEL = 'WARNING' # 這樣設置可以在運行的時候不打印日志文件
- ...
- # Obey robots.txt rules
- ROBOTSTXT_OBEY = False # 調整為false,
- ...
- # Override the default request headers: # 頭部信息,反爬
- DEFAULT_REQUEST_HEADERS = {
- 'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.96 Safari/537.36',
- 'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
- 'Accept-Language': 'en',
- }
- ...
- ITEM_PIPELINES = { # 打開管道
- 'st.pipelines.StPipeline': 300,
- }
為了運行文件方便:新建start.py(和settings在同一目錄下),
- from scrapy import cmdline
- cmdline.execute('scrapy crawl stsp'.split()) # 這里爬蟲項目名為stsp
目前是這樣,后面提取數據的時候修改對應文件 .
二、頁面分析
第一頁url:https://699pic.com/video-sousuo-0-18-0-0-0-1-4-popular-0-0-0-0-0-0.html
url規律:
- url = 'https://699pic.com/video-sousuo-0-18-0-0-0-{}-4-popular-0-0-0-0-0-0.html'.format(i)
通過分析頁面知道視頻數據在li里面,如圖所示.現在問題就簡單了。
三、解析數據
- def parse(self, response):
- # global count
- # count += 1
- # print(response)
- liList = response.xpath('//li') # 獲取所有的li,后面提取有用的
- print(len(liList)) # 76(然后分析可知,第11個到第70個是我們需要的數據)
- newfolderName = 'page{}'.format(count) # 文件夾的名字page1,page2,....
- # 步驟二 創建一個新的文件夾 保存每頁的視頻
- if not os.path.exists(newfolderName):
- os.mkdir(newfolderName)
- for li in liList[10:-6]:
- video_link = li.xpath("./a/div/video/@data-original").extract_first()
- videoLink = 'https:' + video_link # url拼接
- title = li.xpath("./a[2]/h3/text()").extract_first()
- # 下載數據:
- res = requests.get(videoLink,headers=headers)
- data = res.content
- try:
- with open(newfolderName + '/' + title + '.mp4','wb') as f:
- f.write(data)
- print('%s下載成功'%title)
- except:
- break
四、文件配置
items:
- import scrapy
- class StItem(scrapy.Item):
- # define the fields for your item here like:
- # 和兩個對應前面的數據
- videoLink = scrapy.Field()
- title = scrapy.Field()
- # pass
設置好items文件后需要在爬蟲文件(stsp.py)頭部添加如下代碼:
- from st.items import StItem # 這個要設置根目錄文件即st
然后調整stsp文件:
- item = StItem(videoLink=videoLink,title=title)yield item # 這里必須使用yield,如果使用return最后在管道中只能得到一個文件
piplines:
- # 前面的注釋代碼
- from itemadapter import ItemAdapter
- import csv
- class StPipeline:
- def __init__(self):
- # 打開文件,指定方式為寫,利用第3個參數把csv寫數據時產生的空行消除
- self.f = open('Sp.csv','w',encoding='utf-8',newline='')
- # 設置文件第一行的字段名,注意要跟spider傳過來的字典key名稱相同
- self.file_name = ['title', 'videoLink']
- # 指定文件的寫入方式為csv字典寫入,參數1為指定具體文件,參數2為指定字段名
- self.writer = csv.DictWriter(self.f, fieldnames=self.file_name)
- # 寫入第一行字段名,因為只要寫入一次,所以文件放在__init__里面
- self.writer.writeheader()
- def process_item(self, item, spider):
- # 寫入spider傳過來的具體數值
- self.writer.writerow(dict(item)) # 這里的item是上面創建出來的實例對象,需要轉換成dict
- # 寫入完返回
- return item
- def close_spider(self,spider):
- self.f.close()
五、批量爬取
- next_url = 'https://699pic.com/video-sousuo-0-18-0-0-0-{}-4-popular-0-0-0-0-0-0.html'.format(count) # 這里的count是初始化的全局變量count,每次執行數據解析,就讓他+1
- request = scrapy.Request(next_url)
- yield request
最后運行程序:
csv文件:
page2.mp4文件: