zoukankan      html  css  js  c++  java
  • 【Python爬虫】爬取数码宝贝digimon数据库

    写在最前面,本文完全基于 【网络爬虫】爬取神奇宝贝Pokemon图鉴图片大全 编写

    前言

    最近在学习Vue.js和微信小程序,作为实践,决定用uni-app以vue.js的方式写微信小程序,加上最近在switch上玩“数码宝贝网络侦探骇客追忆”,发现还没有和口袋妖怪一样的图鉴小程序,决定做一个“数码宝贝图鉴”小程序,苦于没有数据也没有图片,决定现场学习python,自己去数码兽数据库爬数据。

    效果图

    详细数据
    数码兽数据
    数码兽图片

    准备工作

    1. 学习Python基本语法,学习地点 Python基础教程
    2. 了解爬虫方式、库,直接从【网络爬虫】爬取神奇宝贝Pokemon图鉴图片大全中的代码看着学习,结合 Python爬虫实战教程:批量爬取某网站图片的视频来综合改进
    3. 请教已有的图鉴类小程序的创作者,特别鸣谢微信小程序“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 = 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) + '
    ')
    
        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='
    ')
                    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+'
    ')
    
            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就可以了。

    步骤

    1. 解析主页,获取数码宝贝列表里各自单独的详细资料链接
    2. 分别解析数码宝贝图片地址,各种资料
    3. 下载图片并保存
    4. 保存资料和图片链接

    总结

    通过各种百度,玩玩自己想做的东西还挺开心的。

    代码原文件

    参考资料

    1. 【网络爬虫】爬取神奇宝贝Pokemon图鉴图片大全 by.Memory逆光
    2. 数码兽数据库(数据来源)
    3. Python基础教程
    4. Python爬虫实战教程:批量爬取某网站图片 UP-python学习者
  • 相关阅读:
    CentOS7.4部署Python3+Django+uWSGI+Nginx
    测试:ATM
    JDBC_增删改
    HTTP请求状态码
    Servlet2
    Java日期时间3
    Servlet1
    安装Tomcat
    Java日期时间2
    广度优先遍历
  • 原文地址:https://www.cnblogs.com/SoShun/p/13069822.html
Copyright © 2011-2022 走看看