python爬虫入门之爬取英雄联盟官网的所有英雄数据

本文是Python学期实训时所写的爬虫项目,在这里分享给你,希望能对你有所帮助。
传送门—>安装Python环境及PyCharm编辑器并配置爬虫环境

文章目录


  找到网页中有价值的内容及其所处在源码中的位置

  编写爬虫代码,将信息爬取下来并保存到本地文件中。

  将爬取到的数据进行分析。

内容部分:

 一.找到网页中有价值的内容及其所处在源码中的位置

  英雄联盟官方网址: 英雄联盟全新官方网站-腾讯游戏
  英雄数据信息网址: 游戏资料-英雄联盟官方网站-腾讯游戏
  本小节操作的目的是:找出官网上对自己有价值的信息及其所在网页源代码中的位置。

 第一步:分析网页信息

  所有的英雄页:
  在英雄联盟—游戏资料中,展示了所有的英雄数据,包括有原皮肤,英雄名以及英雄信息信息的网址链接。通过按下 F12 键我们可以查看到网页的源代码,展示如下:

在这里插入图片描述

  为了方便我们快速获取网页中某一部分的源码信息,我们可以点击屏幕中间位置最左边的箭头图标,去网页中找到该部分对应信息的源代码。( 在这里小编以安妮为例 )

在这里插入图片描述
  在此我们可以分析得出,一个<li>标签下放置着一个英雄的部分信息,其中,英雄详细信息的地址链接放置在 a 标签的 href 属性中,英雄的姓名全称放置在 a 标签的 title 属性中,英雄原皮肤图片地址链接放置在 img 标签下的 src 属性中,英雄的简称姓名放置在 p 标签中。

  当我们点击进入英雄详细信息的展示页面时,通过同样的方法我们可以得到以下内容:

  单个英雄职业信息:
  英雄的职业信息是放置在 id 为 “DATA tags” 的 div 容器下的 span 标签中。

在这里插入图片描述
  单个英雄皮肤信息: 
  英雄的所有皮肤信息被放置在 id 为 “skinNAV” 的 ul 容器下的 li 标签中。在每一个 li 标签内的 a 标签内的 img 标签中的 alt 属性存放的是英雄皮肤的名字, src 属性存放的是英雄每个皮肤的图片网址,

在这里插入图片描述
  单个英雄背景故事: 
  英雄的背景故事信息被放置在 id 为 “DATAlore” 的 div 容器中,但是内容并不完整。通过点击 id 为 “Gmore”的 a 标签,可以将英雄的背景故事信息完整的添加在 id 为 “DATAlore” 的 div 容器中展示出来。
在这里插入图片描述
  单个英雄技能信息:
  英雄技能信息被放置在 class 名为 “skilltitle” 的 div 容器下,h5 标签中放置的是英雄的技能名,em 标签中放置的是技能触发方式。通过点击 id 为 “DATAspellsNAV” 的 ul 标签下的每个 li 标签,可以将 class 名为 “skilltitle” 的 div 容器中的信息修改成别的技能介绍。
在这里插入图片描述
  当你使用某一英雄时的使用技巧:
  当你使用某一英雄时的使用技巧介绍被放在 id 为 “DATAallytips” 的 dl 标签下的 dd 标签下的所有 p 标签中。
在这里插入图片描述

  当敌人使用某一英雄时的应对技巧:
  当敌人使用某一英雄时的应对技巧介绍被放在 id 为 “DATAenemytips” 的 dl 标签下的 dd 标签下的所有 p 标签中。
在这里插入图片描述
  综上所述,我们已经找到了对自己有用的信息,也找到了信息所在网页源码中的位置,接下来要做的就是使用爬虫代码,将信息爬取下来并保存到本地文件中。

 二.编写爬虫代码,将信息爬取下来并保存到本地文件中。


```python
# 导入必要的库文件
# 导入selenium抓取动态网页信息
from selenium import webdriver
# 导入时间控制器
import time
# 导入正则表达式
import re
from urllib.request import urlretrieve
import os
from xlutils import copy
import xlrd

# 定义全局变量
# 所有的英雄全名及其详细信息的网址
allHeroParticularlyMessageUrl = []
heroNameList = []
heroJobList = []
heroSkinNumberList = []
heroPassiveSkillsList = []
heroQSkillsList = []
heroWSkillsList = []
heroESkillsList = []
heroRSkillsList = []
heroMessageList = []

# 主程序
def main():
    # 定义一个计数器
    count = 1
    #定义存储的起始位置
    start = 1
    #定义结束位置
    end = ""
    #创建皮肤图片保存目录
    imageFilePath = 'C:/Users/24010/Desktop/skinImages'
    if not os.path.exists(imageFilePath):
        os.mkdir(imageFilePath)

    print("...开始爬取数据...")
    # 定义初始爬取网页的URL
    basciPageUrl = "https://lol.qq.com/data/info-heros.shtml"

    print("...爬取所有的英雄全名及其详细信息的网址执行中...")
    seleniumForGetAllHeroURL(basciPageUrl)


    excel_path = './heroBasicInformationExcel.xls'  # 文件路径
    rbook = xlrd.open_workbook(excel_path, formatting_info=True)  # 打开文件
    book = copy.copy(rbook)  # 复制文件并保留格式
    sheet = book.get_sheet(0)  # 索引sheet表

    # 获取每个英雄的详细详细信息
    for oneHeroUrl in allHeroParticularlyMessageUrl:
        #保存中断后,可修改start的值,继续修改
        if end == "":
            if start <= count:
                print("开始保存第" + str(count) + "个英雄的数据!")
                saveDate("开始保存第" + str(count) + "个英雄的数据!", "a")
                saveDate("", "a")
                seleniumForGetHeroAllMessage(oneHeroUrl[1], count)
                saveDateInExcel(count - 1, book, sheet)
            else:
                pass
        else:
            if start <= count <= end:
                print("开始保存第" + str(count) + "个英雄的数据!")
                saveDate("开始保存第" + str(count) + "个英雄的数据!", "a")
                saveDate("", "a")
                seleniumForGetHeroAllMessage(oneHeroUrl[1], count)
                saveDateInExcel(count - 1, book, sheet)
            else:
                pass
        count = count + 1


# 获取所有的英雄全名及其详细信息的网址
def seleniumForGetAllHeroURL(basciPageUrl):
    # 打开浏览器
    browser = webdriver.Chrome()
    # 访问网页
    browser.get(basciPageUrl)

    time.sleep(20)
    # 查找信息
    getli = browser.find_element_by_id('jSearchHeroDiv').find_elements_by_tag_name('li')
    for Everyone in getli:
        EveryoneUrl = Everyone.find_element_by_tag_name('a').get_attribute('href')
        EveryoneTitle = Everyone.find_element_by_tag_name('a').get_attribute('title')
        allHeroParticularlyMessageUrl.append([EveryoneTitle, EveryoneUrl])
    browser.close()
    print("...爬取所有的英雄全名及其详细信息的网址并存储完成...")


# 获取该英雄的详细信息
def seleniumForGetHeroAllMessage(heroMessageUrl, count):
    # 打开浏览器
    browser = webdriver.Chrome()

    while True:
        # 访问网页
        browser.get(heroMessageUrl)
        time.sleep(5)

        browser.execute_script('window.scrollTo(0, 0)')
        time.sleep(2)


        # 滑动页面
        browser.execute_script('window.scrollBy(0, document.body.scrollHeight*0.2)')
        time.sleep(1)
        browser.execute_script('window.scrollBy(0, document.body.scrollHeight*0.2)')
        time.sleep(1)
        browser.execute_script('window.scrollBy(0, document.body.scrollHeight*0.2)')
        time.sleep(1)
        browser.execute_script('window.scrollBy(0, document.body.scrollHeight*0.2)')
        time.sleep(1)


        # 获取到查看更多按钮
        button = browser.find_element_by_class_name('cgray')

        # 点击上步按钮
        button.click()

        # <---time.sleep()必须写,网速不佳的话,适当延长时间--->
        time.sleep(1)

        if len(browser.find_element_by_id('skinNAV').find_elements_by_tag_name("li")) > 1:
            break
        else:
            print("访问此页面时网络不佳-->" + heroMessageUrl)
            time.sleep(10)

    # 获取基本信息
    findMostmessage(browser, heroMessageUrl)

    # 获取完基本信息后再将页面到滚动条的五分之三处
    browser.execute_script('window.scrollTo(0, document.body.scrollHeight*0.6)')

    # <---time.sleep()必须写,网速不佳的话,适当延长时间--->
    time.sleep(1)

    # 获取英雄技能
    findHeroAllSkills(browser, count)


# ...查找...
def findMostmessage(browser, heroMessageUrl):
    # ----------------------------------------查找信息---------------------------------------------
    # 英雄名
    thisHeroName = browser.find_element_by_id('DATAname').text + browser.find_element_by_id('DATAtitle').text
    # 英雄职业
    thisHeroJob = browser.find_element_by_id('DATAtags').find_element_by_tag_name('span').text
    # 英雄背景故事
    thisHeroStory = browser.find_element_by_id('DATAlore').text
    # 自己使用该英雄时的技巧
    tipsForUsToUseThisHero = ""
    # 敌人使用该英雄时的技巧
    tipsForEnemyUseThisHero = ""
    # 皮肤名称及其图片链接
    heroSkinImgs = []
    # -----------------------------------------查找信息---------------------------------------------

    # 技巧对应的英雄名
    whileYouUseWhichHero = browser.find_element_by_id('DATAallytips').find_element_by_tag_name('dt').text
    whileEnemyUseWhichHero = browser.find_element_by_id('DATAenemytips').find_element_by_tag_name('dt').text

    # 自己使用时的技巧合集
    tipListForUsToUseThisHero = browser.find_element_by_id('DATAallytips').find_element_by_tag_name(
        'dd').find_elements_by_tag_name('p')
    # 别人使用时的技巧合集
    tipListForEnemyUseThisHero = browser.find_element_by_id('DATAenemytips').find_element_by_tag_name(
        'dd').find_elements_by_tag_name('p')
    # 自己使用时的技巧字符串
    for tip in tipListForUsToUseThisHero:
        tipsForUsToUseThisHero = tipsForUsToUseThisHero + tip.text[1:len(tip.text)]
    tipsForUsToUseThisHero = "4," + whileYouUseWhichHero + " : " + tipsForUsToUseThisHero
    # 敌人使用时的技巧字符串
    for tip in tipListForEnemyUseThisHero:
        tipsForEnemyUseThisHero = tipsForEnemyUseThisHero + tip.text[1:len(tip.text)]
    tipsForEnemyUseThisHero = "5," + whileEnemyUseWhichHero + " : " + tipsForEnemyUseThisHero

    # -------------------------------------查找图片-------------------------------------------
    heroSkinImg = browser.find_element_by_id('skinNAV').find_elements_by_tag_name('li')
    heroSkillImgsLi = browser.find_element_by_id('DATAspellsNAV').find_elements_by_tag_name('li')

    findHeroSkillSrcNumber = re.compile(r'act/img/skin/small(.*?).jpg')
    #创建目录
    path1 = "C:/Users/24010/Desktop/skinImages/" + thisHeroName
    if not os.path.exists(path1):
        os.mkdir(path1)

    #循环该英雄皮肤url
    for img in heroSkinImg:
        heroSkinName = img.find_element_by_tag_name('a').get_attribute('title')
        smalllImgsrc = img.find_element_by_tag_name('img').get_attribute('src')
        HeroSkillSrcNumber = re.findall(findHeroSkillSrcNumber, str(smalllImgsrc))[0]

        #重新拼接图片url
        heroSkinImgUrl = "https://game.gtimg.cn/images/lol/act/img/skin/big" + HeroSkillSrcNumber + ".jpg"

        #拼接图片保存地址
        if heroSkinImgUrl != "https://game.gtimg.cn/images/lol/act/img/skin/big235010.jpg":
            path2 = path1 + "/image" + HeroSkillSrcNumber + ".jpg"
            #保存图片为本地文件
            urlretrieve(heroSkinImgUrl, path2)

            heroSkinImgs.append([heroSkinName, heroSkinImgUrl])

    # 创建目录
    skillpath1 = "C:/Users/24010/Desktop/skinImages/" + thisHeroName + "/技能图片"
    if not os.path.exists(skillpath1):
        os.mkdir(skillpath1)

    jineng = ["被动技能", "Q技能", "W技能", "E技能", "R技能"]
    i = 0
    # 循环该英雄技能url
    for img in heroSkillImgsLi:
        heroSkillImgUrl = img.find_element_by_tag_name("img").get_attribute('src')

        # 拼接图片保存地址
        skillpath = skillpath1 + "/" + jineng[i] + ".png"

        # 保存图片为本地文件
        urlretrieve(heroSkillImgUrl, skillpath)

        i = i + 1



    # ----------------------------保存数据---------------------
    saveDate(thisHeroName + "  详细信息网址   " + heroMessageUrl, "a")
    heroMessageList.append(heroMessageUrl)
    saveDate("", "a")
    saveDate("1,英雄名:" + thisHeroName, "a")
    heroNameList.append(thisHeroName)
    saveDate("", "a")
    saveDate("2,英雄职业:" + thisHeroJob, "a")
    heroJobList.append(thisHeroJob)
    saveDate("", "a")
    saveDate("3,英雄背景故事:" + thisHeroStory, "a")
    saveDate("", "a")
    saveDate(tipsForUsToUseThisHero, "a")
    saveDate("", "a")
    saveDate(tipsForEnemyUseThisHero, "a")
    saveDate("", "a")

    #图片个数
    imgcount = 0
    for img in heroSkinImgs:
        imgcount = imgcount + 1
        date = "6." + str(imgcount) + img[0] + " : " + img[1]
        #保存皮肤名和图片链接到txt文件里面
        saveDate(date, "a")
    heroSkinNumberList.append(imgcount)
    saveDate("", "a")

# ...查找英雄技能及其介绍
def findHeroAllSkills(browser, count):
    # 获取技能点击列表
    button = browser.find_element_by_id('DATAspellsNAV').find_elements_by_tag_name('li')
    # 逐个点击技能按钮

    #定义计数器
    skillcount = 7
    for i in range(0, 5):
        # 点击第i个按钮
        button[i].click()
        # <---time.sleep()必须写,网速不佳的话,适当延长时间--->
        time.sleep(1)

        skillName = browser.find_element_by_class_name('skilltitle').find_element_by_tag_name('h5').text
        saveDate(str(skillcount) + ".1,技能名称:" + skillName, "a")

        skillTriggerMode = browser.find_element_by_class_name('skilltitle').find_element_by_tag_name('em').text
        saveDate(str(skillcount) + ".2,技能触发方式:" + skillTriggerMode, "a")

        skillInformation = browser.find_element_by_id('DATAspells').find_element_by_tag_name('p').text
        saveDate(str(skillcount) + ".3,技能内容介绍:" + skillInformation, "a")

        saveDate("", "a")
        skillcount = skillcount + 1

        #存技能名
        if i == 0:
            heroPassiveSkillsList.append(skillName)
        if i == 1:
            heroQSkillsList.append(skillName)
        if i == 2:
            heroWSkillsList.append(skillName)
        if i == 3:
            heroESkillsList.append(skillName)
        if i == 4:
            heroRSkillsList.append(skillName)

    saveDate("", "a")
    saveDate("", "a")
    # 关闭浏览器
    browser.close()

    print("第" + str(count) + "条英雄数据保存成功!")


# ------------------------------保存数据---------------------------------
def saveDate(date, mode):
    filename = 'allHeroMessages.txt'
    with open(filename, mode, encoding='utf-8') as f:
        f.write(date + "\n")

#------------------------------保存到Excel-----------------------------
def saveDateInExcel(j, book, sheet):
    col = ["英雄名称", "英雄职业", "英雄皮肤数量", "被动技能名称", "Q技能名称", "W技能名称", "E技能名称", "R技能名称", "英雄信息链接"]
    if j == 0:
        for i in range(0, 9):
            sheet.write(0, i, col[i])
    sheet.write(j+1, 0, heroNameList[0])
    sheet.write(j + 1, 1, heroJobList[0])
    sheet.write(j + 1, 2, heroSkinNumberList[0])
    sheet.write(j + 1, 3, heroPassiveSkillsList[0])
    sheet.write(j + 1, 4, heroQSkillsList[0])
    sheet.write(j + 1, 5, heroWSkillsList[0])
    sheet.write(j + 1, 6, heroESkillsList[0])
    sheet.write(j + 1, 7, heroRSkillsList[0])
    sheet.write(j + 1, 8, heroMessageList[0])

    heroNameList.clear()
    heroJobList.clear()
    heroSkinNumberList.clear()
    heroPassiveSkillsList.clear()
    heroQSkillsList.clear()
    heroWSkillsList.clear()
    heroESkillsList.clear()
    heroRSkillsList.clear()
    heroMessageList.clear()

    book.save('./heroBasicInformationExcel.xls')  # 保存文件
# 调用主程序,开始执行本程序
if __name__ == "__main__":
    main()
    print("...执行完成...")

《解释部分等我有时间再更新,如果你直接copy我的代码到你编辑器,大概率你是运行不出来的(需要配置浏览器插件),奸笑中~~》

 三.将爬取到的数据进行分析。

饼图(英雄联盟各职业英雄数量分布图)

import matplotlib.pyplot as plt

# 饼图
data = {
    '坦克': (19, 'red'),
    '战士': (42, 'yellow'),
    '法师': (34, 'blue'),
    '辅助': (15, 'green'),
    '射手': (25, 'orange'),
    '刺客': (17, 'gray'),
}
# 设置绘图对象的大小
fig = plt.figure(figsize=(8, 8))
heros = data.keys()
values = [x[0] for x in data.values()]
colors = [x[1] for x in data.values()]
ax1 = fig.add_subplot(111)
ax1.set_title('英雄联盟各职业英雄数量分布图')
labels = ['{}:{}'.format(skin, value) for skin, value in zip(heros, values)]

explode = [] # 设置饼图的凸出显示
ax1.pie(values, labels=labels, colors=colors, shadow=True) # 画饼状图, 并且指定标签和对应的颜色  指定阴影效果

# plt.savefig('pie.jpg') # 保存成图片
plt.rcParams['font.sans-serif']=['SimHei']  # 中文
plt.show()

结果:

在这里插入图片描述

柱状图(英雄皮肤数量分布图)

# encoding: utf-8
import matplotlib.pyplot as plt

index = ['1-3', '4-6', '7-9', '10-12', '13-15', '16-18']
values = [12, 31, 42, 49, 17, 1]
plt.bar(index, values)
plt.xlabel("英雄数量")
plt.ylabel("皮肤数量")
plt.rcParams['font.sans-serif']=['SimHei']
plt.show()

结果

在这里插入图片描述

尾语

如果觉得本文写的还不错的话,求赞、求收藏、求关注、求转发、最重要的是给小博主点个大大的订阅,你的鼓励就是我前进的最大动力,我们下期再见。

  • 17
    点赞
  • 60
    收藏
    觉得还不错? 一键收藏
  • 17
    评论
评论 17
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值