用Scrapy爬取王者皮肤海报~
文章目錄
- 咳咳,這里可以直接下載皮膚
- 這篇博客的由來
- 先看一下成品。
- 一、口水話說說,ImagePipeline
- 0、一般來說,簡單使用ImagesPipeline。
- 1.ImagePipeline可以做這樣的事情
- 2.進一步配置setting.py
- 3.我這樣寫爬蟲spider.py
- 4.上代碼(我的item.py/skin.py(我寫的爬蟲類))
- 5.寫ItemPipeline,(Customize ItemPipeline)
- 二、真正要學習的就是這三個函數(shù)了
- 6.1 file_path(self, request, response=None, info=None, *, item=None)
- 6.2 get_media_requests(item, info)
- 6.3item_completed(results, item, info)
咳咳,這里可以直接下載皮膚
我把爬到的照片上傳到我的資源了。感興趣的可以下載來看看噢。
——免費傳送門
這篇博客的由來
當然是因為我學習之余,喜歡打打王者上上分 (下面是我王者個人主頁,啊還沒上過榮耀…)
以及因為,我要學習 Scrapy 的ImagesPipeline,爬圖片
先看一下成品。
爬蟲結(jié)束后的日志,只爬到了93個items(93個英雄的皮膚,當然皮膚不只93)
以下內(nèi)容,有一些是翻譯的,我會附上文檔的英文原文。
一、口水話說說,ImagePipeline
想要邊學習scrapy 框架,邊學習英文?
想同時提高scrapy框架的掌握程度,和英文閱讀水平?
那就有空多看scrapy權(quán)威文檔(authoritative document)
At first
提到ImagesPipeline 就要先提它的 “本體” ——FilesPipeline。
因為 ImagesPipeline 是 FilesPipeline的一個擴展(extension),
The ImagesPipeline is an extension of the FilesPipeline
嗯,就提這么多。
0、一般來說,簡單使用ImagesPipeline。
(當然先創(chuàng)建scrapy 項目。)
只需要:
1.啟用媒體管道(Enabling your Media Pipeline):
在setting.py中的ITEM_PIPELINES添加
'scrapy.pipelines.images.ImagesPipeline': 1
2.配置存儲目標地址(configure the target storage)
要寫一個 有效的 地址,否則即便完成了第一步也不能啟用pipeline
在setting.py中設(shè)置 IMAGES_STORE setting:
IMAGESS_STORE = '/path/to/valid/dir'
我存到了scrapy project根目錄。就是與scrapy.cfg相同的文件夾
3.items.py類的配置
很簡單,添兩個字段。
image_urls ,一個list,存放圖片url (http://…jpg/png等)
images,一個RESULT,一個2元素元組的列表
每個元組將包含 (success, file_info_or_error)。
·
下面是results參數(shù)的一個典型值:
4.寫爬蟲(spider.py),返回item(圖片url列表)
簡單使用的時候,存儲的圖片。
存在一個full目錄下,
圖片文件名是根據(jù)原始url計算SHA1 hash值后進行存儲;
大概長這樣:
這顯然滿足不了妹子的需求,人家只想看中文字的圖片名
所以要進一步配置setting.py
1.ImagePipeline可以做這樣的事情
1.如生成縮略圖
generating thumbnails
2.根據(jù)大小過濾圖像。
filtering the images based on their size.
3.允許重定向 (其實皮膚海報的url是重定向的,但有一個小規(guī)律,可以不用重定向)
Allowing redirections
默認情況下(By default),
媒體管道會忽略重定向( ignore redirects,)
例如,一個指向媒體文件URL請求的HTTP重定向?qū)⒁馕吨襟w下載失敗。
4.當然還可以自己指定文件名、文件夾名
5.避免下載最近下載的文件
指定延遲天數(shù)
# 120 days of delay for files expiration FILES_EXPIRES = 120# 30 days of delay for images expiration IMAGES_EXPIRES = 302.進一步配置setting.py
我創(chuàng)建的scrapy項目:叫做KingshonorskinPipeline
在setting.py中:
ROBOTSTXT_OBEY = False #首先,一般都不遵循Robot協(xié)議DEFAULT_REQUEST_HEADERS = {'Accept': 'application/json, text/javascript, */*; q=0.01','Accept-Language': 'en','User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.182 Safari/537.36' } # 默認請求頭ITEM_PIPELINES = {'kingshonerSkin.pipelines.KingshonerskinPipeline': 300,# 'scrapy.pipelines.images.ImagesPipeline': 1 } # 注釋了默認的ImagePipeline, # 同時啟用,我自己customize(自己寫的)KingshonerskinPipelineIMAGES_STORE = './王者榮耀皮膚' #我設(shè)置的文件存儲目錄 IMAGES_URLS_FIELD = 'skin_urls' # 我給默認的image_urls 改成了 skin_urls IMAGES_RESULT_FIELD = 'skin_results' # 我給默認的image 改成了 skin_results我的setting.py的部分截圖
3.我這樣寫爬蟲spider.py
從這里開始爬:
英雄資料列表頁-英雄介紹-王者榮耀官方網(wǎng)站-騰訊游戲https://pvp.qq.com/web201605/herolist.shtml
先大概分析。
進入每個英雄的頁面后,
我一般在pycharm console 先來交互式的編程
導(dǎo)入requests,Beautiful 來一步一步“進入網(wǎng)頁”,爬取信息。
代碼有效就復(fù)制到spider.py里面
免得一次性寫好爬蟲文件(spider.py)再來debug,
導(dǎo)入庫
直接requests.get(url)
沒有加headers或者其他參數(shù),直接在右邊看到,Resposne 200了
這網(wǎng)站,沒什么反扒
分析:我用select方法定位標簽
接著我
結(jié)果print一些亂碼出來:我發(fā)現(xiàn)是response.encoding的問題。
改一下encoding,就正常顯示中文字。
到了這里說明沒有頁面渲染,每個英雄的url都能拿到
·
接著進入單個英雄,就拿瑤瑤分析吧
https://pvp.qq.com/web201605/herodetail/505.shtml
用select抓一下標簽
結(jié)果抓了個寂寞,
要么我寫錯了select,要么網(wǎng)頁動態(tài)渲染了。
但我向來不會犯這樣寫錯小錯誤,結(jié)果還真是渲染了。
我Refresh了網(wǎng)頁,這個url真正html代碼:
經(jīng)過一番對比
發(fā)現(xiàn)background_url(網(wǎng)頁背景皮膚海報的url)是一樣的,下面pic-pf標簽不一樣
·
但真正需要的就是background_url,
·
因為相同英雄的皮膚海報url,就后面的數(shù)字在遞增
所以到現(xiàn)在,spider.py真正要解決的是
1.每個hero對應(yīng)的id
2.皮膚的數(shù)量和名字
4.上代碼(我的item.py/skin.py(我寫的爬蟲類))
# items.py import scrapyclass KingshonerskinItem(scrapy.Item):skin_urls = scrapy.Field() # 必須要有的字段,list,存放皮膚urlskins_name = scrapy.Field() # list,存放皮膚nameskin_results = scrapy.Field() # 必須要有的字段,result 存放...hero_name = scrapy.Field() # str, 英雄中文名 # spider.py import scrapy from bs4 import BeautifulSoup from scrapy import Request import re from kingshonerSkin.items import KingshonerskinItemclass SkinSpider(scrapy.Spider):name = 'skin'start_urls = ['https://pvp.qq.com/web201605/herolist.shtml']def parse(self, response): # 進入每個英雄的皮膚所在頁面soup = BeautifulSoup(response.text,'html.parser')for i in soup.select('.herolist-content > ul > li > a'):url_id = re.findall(r'/\d+.shtml',i.get('href'))[0] # 拿到每個英雄對應(yīng)的idyield Request(url='https://pvp.qq.com/web201605/herodetail'+url_id, callback=self.parse_skin)# 按照id,組成每個英雄的url,去yield Requestdef parse_skin(self, response):item = KingshonerskinItem()soup = BeautifulSoup(response.text, 'html.parser')skin_id = 'https:' + re.findall(r'//.*.jpg',soup.select_one('.wrapper > div').get('style'))[0].replace('1.jpg','{}.jpg')# 將background_url 變成通用的skins_name = soup.select_one('.pic-pf > ul').get('data-imgname').split('|') # 皮膚名字列表hero_name = soup.select_one('h2.cover-name').texturls = []for i in range(len(skins_name)):skins_name[i] = skins_name[i].split('&')[0] # 清理多余的符號“&3”urls.append(skin_id.format(i+1))item['hero_name'] = hero_nameitem['skin_urls'] = urlsitem['skins_name'] = skins_namereturn item5.寫ItemPipeline,(Customize ItemPipeline)
如果簡單使用ImagesPipeline
就無需寫這個類,
只用:啟用’scrapy.pipelines.images.ImagesPipeline’: 1,
甚至不禁用自己寫的pipeline.py也可以
當然,我們要處理英雄和皮膚的對應(yīng)關(guān)系。
自己寫ItemPipeline.
我先上我的itempipeline.py代碼
from scrapy import Request from scrapy.pipelines.images import ImagesPipelineclass KingshonerskinPipeline(ImagesPipeline):def file_path(self, request, response=None, info=None, *, item):skin_num = int(request.url[-5]) - 1 # 海報url和海報名字對應(yīng)上。return f'{item["hero_name"]}/{item["skins_name"][skin_num]}.jpg'def get_media_requests(self, item, info):# for i in item['skins_name']:# yield Request(i)return [Request(i) for i in item['skin_urls']]二、真正要學習的就是這三個函數(shù)了
6.1 file_path(self, request, response=None, info=None, *, item=None)
This method is called once per downloaded item.
It returns the download path of the file originating from the specified
·
這個方法對每個下載的item調(diào)用一次。
返回來自指定的文件的下載路徑
override this method to customize the download path of each file
覆蓋/重寫這個函數(shù)就可以自定義存儲文件(圖片)的路徑
對于這個函數(shù)的幾個參數(shù),
1.在我寫的pipeline中,item=None的None去掉了。
于是就可以使用我放在item里面的字段(hero_name 、skins_name)
在指定英雄和皮膚的對應(yīng)關(guān)系
2.我嘗試用response.meta去傳遞(hero_name 、skins_name)
但是失敗了。不知道原因出自哪里。
·
3.不知道這個info怎么用
哪天發(fā)現(xiàn)了,再加到這里
·
4.request,就相當于request
文檔里面給了一用request.url的后綴作為圖片名的例子
6.2 get_media_requests(item, info)
As seen on the workflow,
the pipeline will get the URLs of the images to download from the item.
return a Request for each file URL:
·
這個函數(shù)很簡單,就是作為一個 生成器 ,
不斷地 return a Request for each file URL:
代碼中,注釋部分和下面的return是等價的。
Those requests will be processed by the pipeline and,
when they have finished downloading,
the results will be sent to the item_completed() method, as a list of 2-element tuples.
Each tuple will contain (success, file_info_or_error)
·
這些請求將由管道處理,
當它們完成下載后,
結(jié)果(方法:item_completed()的 result參數(shù) )將作為一個包含2個元素的元組列表發(fā)送到
item_completed()方法。
每個元組將包含(success, file_info_or_error)
我就不翻譯了。
6.3item_completed(results, item, info)
The ImagesPipeline.item_completed() method is called
when all image requests for a single item have completed
(either finished downloading, or failed for some reason).
·
當單個item的所有圖像請求都完成
(或者下載完成,或者由于某些原因失敗)時,
將調(diào)用ImagesPipeline.item_completed()方法。
we store the downloaded file paths (passed in results) in the file_paths item field,
and we drop the item if it doesn’t contain any files:
·
我們將下載的文件路徑(傳到result),存儲在file_paths 的item字段中,
如果item不包含任何文件,我們就刪除它:
下面附一下 文檔給的,實現(xiàn)這個方法的an example
from itemadapter import ItemAdapter from scrapy.exceptions import DropItemdef item_completed(self, results, item, info):file_paths = [x['path'] for ok, x in results if ok]if not file_paths:raise DropItem("Item contains no files")adapter = ItemAdapter(item)adapter['file_paths'] = file_paths return itemresult 是一個包含兩個元素的元組列表 (a list of 2-element tuples.)
# a typical value of the results argument: [(True,{'checksum': '2b00042f7481c7b056c4b410d28f33cf','path': 'full/0a79c461a4062ac383dc4fade7bc09f1384a3910.jpg','url': 'http://www.example.com/files/product1.pdf','status': 'downloaded'}),(False,Failure(...))]我沒有覆蓋這個item_completed函數(shù),
我在file_paths,寫英雄名字和皮膚的對應(yīng)關(guān)系了。
這個函數(shù)就是,可以進一步處理 已經(jīng)下載好的 每個item
顯然我們不用進一步處理item
運行
scrapy crawl skin注意:如果沒有圖片產(chǎn)生,看看也沒有下面的報錯。
WARNING: Disabled KingshonerskinPipeline: ImagesPipeline requires installing Pillow 4.0.0 or later
有的話,說明缺少必要的第三發(fā)庫pillow, 就:
然后重新
scrapy crawl skin就這些了,祝大家上分愉快~
總結(jié)
以上是生活随笔為你收集整理的用Scrapy爬取王者皮肤海报~的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 首款超小体积、免插卡、蓝牙配置的新款4G
- 下一篇: android查看屏幕大小,androi