本文是Python学期实训时所写的爬虫项目,在这里分享给你,希望能对你有所帮助。
文章目录
找到网页中有价值的内容及其所处在源码中的位置
编写爬虫代码,将信息爬取下来并保存到本地文件中。
将爬取到的数据进行分析。
内容部分:
英雄联盟官方网址: 英雄联盟全新官方网站-腾讯游戏 英雄数据信息网址: 游戏资料-英雄联盟官方网站-腾讯游戏 本小节操作的目的是:找出官网上对自己有价值的信息及其所在网页源代码中的位置。
所有的英雄页:
在英雄联盟—游戏资料中,展示了所有的英雄数据,包括有原皮肤,英雄名以及英雄信息信息的网址链接。通过按下 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()
结果
尾语
如果觉得本文写的还不错的话,求赞、求收藏、求关注、求转发、最重要的是给小博主点个大大的订阅,你的鼓励就是我前进的最大动力,我们下期再见。