暑假的一次爬虫任务,正好拿来练练手顺便治治自己平时不怎么写代码的懒癌。目前现在python爬虫的第三方库越来越多也比较强大,最主要还是python简洁易懂的语法和强大的第三方库使得python变成了最大众化的一个编程语言,原因就是易上手。
头图地址:流星-ナコモ
任务目标
- 爬取http://www.animeshow.tv/下的full anime list的动漫列表
- 获取动漫信息并存储(存储格式不限,可以txt,数据库,json格式等等)
- 必须要有的数据(动漫名称,动漫地址,类型,播出时间,状态,流派,摘要)
- 把存储后的数据调用显示在前端界面上,采用图表方式做可视化呈现
工程结构:
目标分析
进入网页后根据观察,动漫以分类方式排序,用开发者工具选择工具移动到动漫名字上,看到开发中工具中定位到了该标签的内容,是以一个a标签做的链接
点进去后则是该部动漫的具体介绍信息
我们根据要求,里面的type,Year等信息都是我们需要的需要将其过滤出来整理,python中可以用Beatifulsoup来进行标签定位获取,这边我自己是用了正则表达式过来获取
代码过程
爬虫py文件:
import re,requests,os #导入正则,requests,os库
from openpyxl import workbook #导入用于写入excel的库
from multiprocessing import Process #多进程的库
URL = "http://www.animeshow.tv/anime-list.html" #设置目标网页
html = requests.get(URL).text #获取目标网页内容并转为文本
links = re.compile('href="(.+?)"') #编译正则匹配所有href里的字符串内容
link = links.findall(html) #利用正则findall寻找编译的正则表达式
link_list = link[38:] #筛选出有用的番剧链接信息
#正则模块
Types = re.compile("Type: .*?<div>(.+?)</div>") #匹配类型内容
Summary_re = re.compile('<p>(.*?)</p>') #匹配介绍内容
Year_re = re.compile('Year:.*?<div>(.*?)</div>') #匹配日期内容
Status_re = re.compile('Status:.*?<div>(.*?)</div>') #匹配状态内容
Genres_re = re.compile('Genres:.*?<a href=".*?">(.*?)</a>') #匹配流派内容
title_re = re.compile('<title>(.*?) - AnimeShow.tv</title>') #匹配标题内容
list_month = ['Jan','Feb','Mar','Apr','May','Jun','Jul','Aug','Sep','Oct','Nov','Dec']#月份表
Jan = Feb = Mar = Apr = May = Jun = Jul = Aug = Sep = Oct = Nov = Dec = 0
month_data = [Jan, Feb, Mar, Apr, May, Jun, Jul, Aug, Sep, Oct, Nov, Dec]
#打引统计好的值用于填入可视化
def time_range():
for i in range(0,12):
if Year[0:3] == list_month[i] :
month_data[i] += 1
#爬取以及写入模块
def data_get():
global title, Type, Summary, Year, Status, Genres
x = 0
TV_Series = Movie = OVA = Special = 0
wb = workbook.Workbook() # 创建Excel对象
ws = wb.active # 获取当前正在操作的表对象
ws.append(["Status", "title", "Type", "Year", "Genres", "Summarys"]) # 往表中写入标题行,以列表形式写入
for i in link_list:
cartoon_html = requests.get(i).text #获取子网页html文本内容
# 这里利用正则匹配后的列表数据转化成字符串
Type = "".join(Types.findall(cartoon_html))
Summarys = Summary_re.findall(cartoon_html)
Summary = "".join(Summarys[1:len(Summarys)-2])
Year = "".join(Year_re.findall(cartoon_html))
Status = "".join(Status_re.findall(cartoon_html))
Genres = "".join(Genres_re.findall(cartoon_html))
title = "".join(title_re.findall(cartoon_html))
#输入内容到控制台
print(title,"\n",Type,"\n",Summary,"\n",Year,"\n",Status,"\n",Genres,"\n")
#向Execl写入以行形式写入数据
ws.append([Status,title,Type,Year,Genres,Summary])
time_range()
if Type[0:9] == "TV Series":
TV_Series += 1
elif Type[0:5] == "Movie":
Movie += 1
elif Type[0:3] == 'OVA':
OVA += 1
elif Type[0:7] == "Special":
Special += 1
print("爬取完成进度:{:.2%}".format(x / 1226)) #以进度表示完成度
print("TV Series:"+str(TV_Series),"Movie:" + str(Movie),'OVA:'+str(OVA),"Special:"+str(Special))
x += 1
-
print("[INFO]: 100%爬取结束")
print("一月:" + str(month_data[0]), "二月:" + str(month_data[1]),
"三月:" + str(month_data[2]), "四月:" + str(month_data[3]),
"五月:" + str(month_data[4]),"六月:" + str(month_data[5]),
"七月:" + str(month_data[6]), "八月:" + str(month_data[7]),
"九月:" + str(month_data[8]), "十月:" + str(month_data[9]),
"十一月:" + str(month_data[10]),"十二月:" + str(month_data[11]))
wb.save('anime.xlsx')#保存爬取数据并关闭
#编译成json格式写入json文件
dictionary = dict(zip(list_month, list_month2))
print(dictionary)
data = json.dumps(dictionary)
with open("data.json","wb") as file:
file.write(data.encode())
#进程化运行模块
def run_proc1(name):
print('Run child process %s (%s)...' % (name, os.getpid()))
print(data_get(),"\n")
#以进程形式运行
if __name__ == '__main__':
print('Parent process %s.' % os.getpid())
p1 = Process(target=run_proc1, args=('spider',)) #创建进程
print('Child process will start.')
p1.start() #进程启动
p1.join() #添加任务
print('Child process end.') #进程结束
Flask的py主文件:
from flask import Flask #导入Flask模块
from flask import render_template #导入渲染模板模块
import json
#读取json文件并分成列表,以便传值
with open("data.json","r") as f:
js = f.read()
js = json.loads(js)
month ,data = list(js.keys()),list(js.values())
app = Flask(__name__) #主入口
@app.route('/') #路由
def index():
return render_template('index.html',data=data,month=month)#渲染模板以及传参
if __name__ == '__main__':
app.run() #运行在本地环境,如需配置请设置host="xxxxx",port=xxxx
爬取结束写入文件后的效果
可能会看到在介绍那边会有一点标签<p>字符残留
再看看这个造成这个原因的html结构
这个原因是因为正则在匹配表达时候其中一个标签出现了空内容,正则表达式则会把最先前匹配到的给写入进去造成,也可以自己后面提取出来去掉再放到列表
可视化部分
因为这边数据不是经常变动而且比较固定,所以部分选择了统计数量后填写静态数据展示
可视化工具使用了百度的Echarts,具体的实例Echarts即可找到配置方法,这里就不再讲述直接看效果
利用Flask的框架进行搭建web,通过jinja2模板进行传值
运行flask后即可访问地址观看效果
最后我将他放在了云机上展示,展示地址为 Anime可视化展示
END
说实在自己代码水平真的很不行,平时也练的很少从上面代码看下来都是一些很死脑筋写出来的,但还是学习到了一些知识,最重要的还是正则吧,会写正则真的方便太多了。再则跟身边同龄人比差距还是太大了,代码这样的东西还是多写才会好。
也就当暑假里完成的一个小任务
正则大法吼,贪婪模式一把梭|´・ω・)ノ
一梭子下去我死了