python 爬虫与数据可视化
1.引言
Web已经成为日新月异迅速发展的网络信息技术中的信息载体,如何有效地提取和利用搜索引擎获得互联网最有用的、可以免费公开访问的数据集,查找用户所需的价值数据或者相近的价值信息。网络爬虫具有诸多优势,可根据用户的实际需求,对网页数据信息进行爬取,获取整个网页,且具备很强的自定义性特点。本文通过利用python进行数据爬取与分析,python是近几年比较热门的语言,python入门简单,应用让范围广,与当下众多热门软件兼容,其对应的数据包和框架也逐渐成熟。
2.需求分析
2.1网站分析
爬取豆瓣读书Top250的基本信息,如下图(2-1)第一本书籍,红楼梦,书籍名称、作者、图片、评分、评价人数等数据。利用python向浏览器发送请求的时候,返回的是html代码,然后对html解析,解析的工具有很多。比如:正则表达式、Beautifulsoup、Xpath等,这里采用xpath方法。
图2-1
借助Chrome开发者工具(F12)来分析网页,在Element下找到需要数据的位置如下图(2-2)所示:
图2-2
2.2爬取基本流程
URL分析
通过浏览器查看分析目目标网页。
获取数据
通过HTTP库向目标站点发起请求,请求可以包含额外的header等信息,如果服务器能正常响应,会得到一个Respone,便是所要获取的页面内容。
解析内容
得到的内容可能是HTML、json等格式,可以用页面解析库、正则表达式等进行解析。
存储数据
保存形式多样,可以存为文本,也可以保存到数据库,或者保存特定格式的文件
流程如下图(2-3)所示:
图2-3
2.3数据可视化
使用Flask框架将爬取的数据进行可视化分析,Flask是一个轻量级的可定制框架,使用Python语言编写,较其他同类型框架更为灵活、轻便、安全且容易上手。本实验用于Flask框架将数据显示到网页,以及生成书籍评分柱状图(使用Echarts模块)和利用书籍概况生成词云(使用WordCloud模块)。
2.3.1引入Flask框架
Flask是一个使用 Python 编写的轻量级 Web 应用框架。其WSGI工具箱采用 Werkzeug ,模板引擎则使用 Jinja2 。
Flask程序运行过程:每个Flask程序必须有一个程序实例。Flask调用视图函数后,会将视图函数的返回值作为响应的内容,返回给客户端。一般情况下,响应内容主要是字符串和状态码。调用视图函数,获取响应数据后,把数据传入HTML模板文件中,模板引擎负责渲染响应数据,然后由Flask返回响应数据给浏览器,最后浏览器处理返回的结果显示给客户端。
创建Flask
图2-4
在运行的环境配置中,勾选Flask Debug
图2-5
使用Echarts
商业级数据图表,它是一个纯JavaScript的图标库,兼容绝大部分的浏览器,底层依赖轻量级的canvas类库ZRender,提供直观,生动,可交互,可高度个性化定制的数据可视化图表。创新的拖拽重计算、数据视图、值域漫游等特性大大增强了用户体验,赋予了用户对数据进行挖掘、整合的能力。
支持的图表:
折线图(区域图)、柱状图(条状图)、散点图(气泡图)、K线图、饼图(环形图)
雷达图(填充雷达图)、和弦图、力导向布局图、地图、仪表盘、漏斗图、事件河流图等12类图表
官方中文网址:https://www.echartsjs.com/zh/index.html
使用流程:
图2-6
使用WordCloud
WordCloud是python的一个三方库,称为词云也叫做文字云,是根据文本中的词频,对内容进行可视化的汇总.原理是首先将爬取的文本数据通过分隔单词,然后统计单词出现次数并过滤,接着根据统计配置字号,最后将生成的字号布局到给定的环境中。
2.4引入模块
模块(module):用来从逻辑上组织Python代码(变量、函数、类),本质就是py文件,提高代码的可维护性。Python使用import来导入模块。如本次实验用到的模块有:
3.实现代码
3.1爬取网页
3.1.1URL分析
页面URL:https://book.douban.com/top250?start=
页面包括250条书籍数据,分10页,每页25条,每页的URL的不同之处:最后的数值=(页数-1)*25
图3-1
3.1.2获取数据
通过HTTP库向目标站点发起请求,请求可以包含额外的header等信息,如果服务器能正常响应,会得到一个Response,便是所要获取的页面内容。具体操作如下:
对每一个页面,调用gainURL函数,传入一个url参数;urllib.request.urlopen发送请求获取响应;read()获取页面内容
def gainURL(url):
head = { #模拟浏览器头部信息,向豆瓣服务器发送消息
"User-Agent": "Mozilla / 5.0(Windows NT 10.0; Win64; x64) AppleWebKit / 537.36(KHTML, like Gecko) Chrome / 80.0.3987.122 Safari / 537.36"
}
request = urllib.request.Request(url,headers=head)
response = urllib.request.urlopen(request)
html = response.read().decode("utf-8")
return html
3.1.3解析内容
得到的内容可能是HTML、JSON等格式,可以用bs4、正则表达式、xpath等进行解析。
使用正则表达式找到具体的内容
findLink = re.compile(r'<a class="nbg" href="(.*?)" οnclick=') # 读书详情链接
findimgSrc = re.compile(r'<img src="(.*?)"')# 书籍图片链接
findTitle = re.compile(r'title="(.*?)"')# 书籍名称
findAuthor = re.compile(r'<p class="pl">(.*?)</p>')# 书籍作者
findRating = re.compile(r'<span class="rating_nums">(.*?)</span>')#书籍评分
findInq = re.compile(r'<span class="inq">(.*)</span>')# 书籍概况
BeautifulSoup定位特定的标签位置与正则表达式结合爬取内容
#解析数据
soup=BeautifulSoup(html,"html.parser") #bs4定位特定的标签位置
for item in soup.find_all('table'):
data = [] # 保存一部电影的所有信息
item = str(item)
# 书籍详情链接
findLink = re.compile(r'<a class="nbg" href="(.*?)" οnclick=')
link = re.findall(findLink, item)[0]
data.append(link)
# 书籍图片链接
findimgSrc = re.compile(r'<img src="(.*?)"')
imgSrc = re.findall(findimgSrc, item)[0]
data.append(imgSrc)
# 书籍名称
findTitle = re.compile(r'title="(.*?)"')
title = re.findall(findTitle, item)[0]
data.append(title)
# 书籍作者
findAuthor = re.compile(r'<p class="pl">(.*?)</p>')
author = re.findall(findAuthor, item)[0]
data.append(author)
# 书籍评分
findRating = re.compile(r'<span class="rating_nums">(.*?)</span>')
rating = re.findall(findRating , item)[0]
data.append(rating)
# 书籍概况
findInq = re.compile(r'<span class="inq">(.*)</span>')
Inq = re.findall(findInq , item)
data.append(Inq)
datalist.append(data) # 把处理好的信息放入datalist
3.1.4存储数据
保存形式多样,可以存为文本,也可以保存到数据库,或者保存特定格式的文件
利用python库xlwt将抽取的数据datalist写入Excel表格
def saveData(datalist,savepath):
bookwork = xlwt.Workbook(encoding="UTF-8",style_compression=0)
sheet = bookwork.add_sheet('豆瓣书籍TOP250',cell_overwrite_ok=True)
col = ("书籍详情链接", "图片链接", "书名", "作者", "评分", "概况")
for i in range(0, 6):
sheet.write(0, i, col[i]) # 列名
for i in range(0, 250):
print("第%d条已爬取" % (i + 1))
data = datalist[i]
for j in range(0, 6):
sheet.write(i + 1, j, data[j]) # 数据
bookwork.save(savepath) # 保存
利用python库sqlite3将抽取的数据datalist写入db文件
init_db()函数创建数据库表格
def init_db(savepath):
sql = '''
create table book250
(
id integer primary key autoincrement,
info_link text,
pic_link text,
name varchar,
author varchar,
score numeric ,
instroduction text
)
''' # 创建数据表
conn = sqlite3.connect(savepath)
cursor = conn.cursor()
cursor.execute(sql)
conn.commit()
conn.close()
saveDataDB()函数存储数据
def saveDataDB(datalist,savepath):
init_db(savepath)
conn = sqlite3.connect(savepath)
cur = conn.cursor()
for data in datalist:
for index in range(len(data)):
data[index] = '"'+data[index]+'"'
sql = '''
insert into book250 (
info_link,pic_link,name,author,score,instroduction)
values(%s)'''%",".join(data)
cur.execute(sql)
conn.commit()
cur.close()
conn.close()
3.2数据可视化
3.2.1 Flask
导入Flask类,接收一个__name__参数用于与web页面进行数据交互,route作用是将路由映射到视图函数def index(),应用程序实例的run方法启动WEB服务器
form flask import Flask
app = Flask(__name__) @app.route('/')
def index():
return render_template("index.html")
if __name__ == '__main__':
app.run()
引入import sqlite3模块,从.db文件中提取数据,
def book():
datalist = []
con = sqlite3.connect("book.db") #访问数据库
cur = con.cursor() #游标
sql = "select * from book250"
data = cur.execute(sql)
for item in data:
datalist.append(item)
cur.close()
con.close()
return render_template("book.html",books = datalist)
页面部署,从渲染模板时使用的数据中获取;Jinja2除了能识别基本类型的变量,还能识别{};
{% for book in books %}
<tr>
<td>{{book[0]}}</td>
<td>
<a href="{{ book[1] }}" target="_blank">{{ book[3] }}</a>
</td>
<td><img src="{{book[2]}}" width="70px"> </td>
<td>{{book[4]}}</td>
<td>{{book[5]}}</td>
<td>{{book[6]}}</td>
</tr>
{% endfor %}
3.2.2 Echarts
页面引入echarts文件
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<!-- 引入 ECharts 文件 -->
<script src="echarts.min.js"></script>
</head>
</html>
数据库提取出柱形图横坐标纵坐标值
def score():
score = [] #评分
num = [] #每个评分所统计出的书籍数量
con = sqlite3.connect("book.db")
cur = con.cursor()
sql = "select score,count(score) from book250 group by score"
data = cur.execute(sql)
for item in data:
score.append(str(item[0]))
num.append(item[1])
cur.close()
con.close()
return render_template("score.html",score= score,num=num)
页面渲染
<script type="text/javascript">
var dom = document.getElementById("main");
var myChart = echarts.init(dom);
var app = {};
option = null;
option = {
color:['#3398DB'],
tooltip: {
trigger: 'axis',
axisPointer: {
type: 'shadow'
}
},
grid: {
left: '3%',
right:'4%',
bottom:'3%',
containLabel:true
},
xAxis: {
type: 'category',
data: {{ score|tojson }}
},
yAxis: {
type: 'value'
},
series: [{
data: {{ num }},
barWidth:'60%',
type:'bar'
}]
};
;
if (option && typeof option === "object") {
myChart.setOption(option, true);
}
</script>
3.2.3 WordCloud
准备词云(使用爬取的book.db文件的instroduction字段进行分析)
#准备词云所需的文字(词)
con = sqlite3.connect('book.db')
cur = con.cursor()
sql = 'select instroduction from book250'
data = cur.execute(sql)
text = ""
for item in data:
text = text + item[0]
cur.close()
con.close()
分词
cut = jieba.cut(text)
string = ' '.join(cut)
print(len(string))
生成图片
img = Image.open(r'.\static\assets\img\tree.jpg') #打开遮罩图片
img_array = np.array(img) #将图片转换为数组
wc = WordCloud(
background_color='white',
mask=img_array,
font_path="msyh.ttc" # 生成字体
)
wc.generate_from_text(string)
#绘制图片
fig = plt.figure(1)
plt.imshow(wc)
plt.axis('off') #是否显示坐标轴
plt.show() #显示生成的词云图片
显示到页面
<img src="static/assets/img/bookword.jpg" class="img-fluid" alt="">
4.实验
4.1爬取结果
book_excel.py文件爬取结果
图4-1
book_sql.py文件爬取结果
图4-2
生成词云图片
图4-3
4.2分析结果
首页展示
图4-4
Top250书籍展示
图4-5
评分分布展示
图4-6
词云展示
图4-7
5.总结和展望
本实验通过爬取豆瓣排行前250的书籍,了解了python爬虫涉及包含的知识不限于 HTML 知识、HTTP/HTTPS 协议的基本知识、正则表达式,还需要了解数据库知识,爬虫框架的使用等。