python 爬虫与数据可视化

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 协议的基本知识、正则表达式,还需要了解数据库知识,爬虫框架的使用等。


版权声明:本文为kair_原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。