寫在最前面,本文完全基于 【網絡爬蟲】爬取神奇寶貝Pokemon圖鑒圖檔大全 編寫
前言
最近在學習Vue.js和微信小程式,作為實踐,決定用uni-app以vue.js的方式寫微信小程式,加上最近在switch上玩“數位寶貝網絡偵探駭客追憶”,發現還沒有和口袋妖怪一樣的圖鑒小程式,決定做一個“數位寶貝圖鑒”小程式,苦于沒有資料也沒有圖檔,決定現場學習python,自己去數位獸資料庫爬資料。
效果圖
準備工作
- 學習Python基本文法,學習地點 Python基礎教程
- 了解爬蟲方式、庫,直接從【網絡爬蟲】爬取神奇寶貝Pokemon圖鑒圖檔大全中的代碼看着學習,結合 Python爬蟲實戰教程:批量爬取某網站圖檔的視訊來綜合改進
- 請教已有的圖鑒類小程式的創作者,特别鳴謝微信小程式“FGO素材規劃”作者,問了才知道資料都是自己去找的,沒有API
代碼
由于是第一次寫Python,第一次寫爬蟲,可能下載下傳慢,可能記憶體爆掉,見諒
# -*- coding:UTF-8 -*-
from bs4 import BeautifulSoup
from xlwt import Workbook
import requests
import os
class downloader(object):
def __init__(self):
self.target = r'http://www.digimons.net/digimon/chn.html' # 首頁
self.root = 'http://www.digimons.net/digimon/' # 數位獸們的根目錄
self.digimon = [] # 存放數位寶貝名和屬性
self.names = [] # 數位寶貝的名字
self.urls = [] # 數位寶貝的連結
self.level = [] # 數位寶貝的等級
self.divs = [] # 不同等級的class屬性
self.palces = ['幼年期Ⅰ', '幼年期Ⅱ', '成長期', '成熟期',
'完全體', '究極體', '裝甲體', '混合體', '不明', '無(-)']
self.levelClass = ['c_1','c_2','c_3','c_4','c_5','c_6','c_7','c_8','c_9','c_10']
self.image = [] # 數位寶貝的圖檔位址
self.down = [] # 圖檔位址及編号
self.datas = [] # 數位寶貝資料
self.tableName = 'digimons'
self.tableHeader = ['序号', '名字', '圖檔連結', '等級', '類型',
'屬性', '所屬', '适應領域', '首次登場', '名字來源', '必殺技1', '必殺技2']
def first_process(self):
r = requests.get(self.target)
r.encoding = r.apparent_encoding
html = r.text
div_bf = BeautifulSoup(html, features='html.parser')
for place in self.palces:
if place == self.palces[0]:
name = self.levelClass[0]
elif place == self.palces[1]:
name = self.levelClass[1]
elif place == self.palces[2]:
name = self.levelClass[2]
elif place == self.palces[3]:
name = self.levelClass[3]
elif place == self.palces[4]:
name = self.levelClass[4]
elif place == self.palces[5]:
name = self.levelClass[5]
elif place == self.palces[6]:
name = self.levelClass[6]
elif place == self.palces[7]:
name = self.levelClass[7]
elif place == self.palces[8]:
name = self.levelClass[8]
else:
name = self.levelClass[9]
self.divs.append(div_bf.find_all('li', class_=name))
print("等級共有:", len(self.divs))
self.get_Pokemon()
def get_digimon_data(self):
k = 0
for i, url in enumerate(self.urls):
try:
k = k+1
print('擷取圖檔位址中…… {}%'.format(k*100/len(self.urls)), end='\r')
r = requests.get(url[0])
r.encoding = r.apparent_encoding
html = r.text
div_bf = BeautifulSoup(html, features='html.parser')
# 擷取頁面資源完畢,擷取圖檔連結開始
imageDiv = div_bf.find('div', class_='digimon_img')
image = imageDiv.find('img')
if image == None:
print(url[1], "沒找到圖檔")
image_address = url[0][0:url[0].rfind(
'/')+1] + image.get('src')
self.image.append((image_address, url[1]))
self.down.append((image_address, k-1))
# 擷取圖檔連結完畢,擷取資料資源開始
datas = div_bf.find_all('tr')
tmp_datas = []
for i in range(len(datas)):
tmp_datas.append(datas[i].find('td').get_text())
self.datas.append(tmp_datas)
except Exception as e:
print(e)
with open('urls.txt', 'w') as f:
for item in self.down:
f.write(str(item) + '\n')
def get_Pokemon(self):
print("get_Pokemon")
for index, adiv in enumerate(self.divs):
l = []
k = 0
if(index == 0):
level = self.palces[0]
elif(index == 1):
level = self.palces[1]
elif(index == 2):
level = self.palces[2]
elif(index == 3):
level = self.palces[3]
elif(index == 4):
level = self.palces[4]
elif(index == 5):
level = self.palces[5]
elif(index == 6):
level = self.palces[6]
elif(index == 7):
level = self.palces[7]
elif(index == 8):
level = self.palces[8]
else:
level = '\"數位獸第六部\"'
print('擷取 '+level+' 數位寶貝資訊中')
for li in adiv:
# print('擷取'+level+'數位寶貝資訊中…… {} %'.format(k*100/len(adiv)), end='\r')
k = k+1
tmp = []
tmp_url = []
tmp_level = []
label = li('a')
tmp.append(label[0].get_text())
tmp_url.append(label[0].get('href'))
tmp_level.append(level)
l.append(tmp)
try:
if tmp[0] not in self.palces and tmp[0] != None:
self.urls.append((self.root + tmp_url[0], tmp[0]))
self.level.append(index)
self.names.append(tmp[0])
except Exception as e:
print(e)
self.digimon.extend(l)
print("數位寶貝總數:", len(self.digimon))
print("url數:", len(self.urls))
self.get_digimon_data()
with open('names.txt', 'w') as f:
for item in self.names:
f.write(item+'\n')
print(len(self.image))
def get_image(self):
print("擷取圖檔中")
imageRoot = './image'
k = 0
for index, url in enumerate(self.image):
k = k+1
address = url[0]
name = url[1]
levelPath = imageRoot + '/' + str(self.level[index])
picture = levelPath + '/' + name + '.jpg'
try:
if not os.path.exists(imageRoot):
os.mkdir(imageRoot)
if not os.path.exists(levelPath):
os.mkdir(levelPath)
if not os.path.exists(picture):
r = requests.get(address)
with open(picture, 'wb') as f:
f.write(r.content)
print('圖檔儲存成功,{}%'.format(k*100/len(self.image)))
else:
print('檔案已存在')
except Exception:
print('爬取失敗')
def save_as_xlsx(self):
# TODO 解決“必須目前沒有digimons.xls才可以儲存”的問題
print("儲存數位寶貝資料中")
file = Workbook(encoding='utf-8')
table = file.add_sheet(self.tableName)
for i, item in enumerate(self.tableHeader):
table.write(0, i, item)
for i, data in enumerate(self.datas):
table.write(i+1, 0, i+1)
table.write(i+1, 1, self.names[i])
table.write(i+1, 2, self.down[i][0])
for j, cell in enumerate(data):
table.write(i+1, j+3, cell)
file.save(self.tableName+'.xls')
if __name__ == "__main__":
target = downloader()
target.first_process()
target.get_image()
target.save_as_xlsx()
這裡使用了beautifulsoup來解析網頁
分析
我決定按照等級(成長期、完全體等)把數位寶貝分類,而不是按照網頁裡的首次登場年份分類
分析網頁
目标網頁
可以看到,所有數位寶貝都放在了一個 id="digimon_list"的ul裡,按照年份分成了一個個塊,每一個數位寶貝都在li标簽中,li标簽裡的class屬性儲存了數位獸的等級,a标簽裡儲存了這個數位獸的詳細連結和名字。
是以我們首先要得到id="digimon_list"的ul标簽,在其中找到所有的li标簽,在li标簽中找到數位獸的詳細連結、名字、等級。我們進入到數位獸詳細頁面
可以看到,數位獸圖檔連結放在了id="digimon_img"的div裡的img标簽裡,然後所有資訊都放在tr标簽裡,是以我們頁面裡的相應div和tr就可以了。
步驟
- 解析首頁,擷取數位寶貝清單裡各自單獨的詳細資料連結
- 分别解析數位寶貝圖檔位址,各種資料
- 下載下傳圖檔并儲存
- 儲存資料和圖檔連結
總結
通過各種百度,玩玩自己想做的東西還挺開心的。
代碼原檔案
參考資料
- 【網絡爬蟲】爬取神奇寶貝Pokemon圖鑒圖檔大全 by.Memory逆光
- 數位獸資料庫(資料來源)
- Python基礎教程
- Python爬蟲實戰教程:批量爬取某網站圖檔 UP-python學習者