Python时空大数据大数据,机器学习,人工智能呆鸟的Python数据分析

简书之旅

2020-07-18  本文已影响0人  皮皮大

这是自己爬取自己的文章,然后进行数据分析的!哈哈哈

声明:本文中获取的数据仅供学习使用,未用作任何商业用途;如有转载,请注明作者和原文出处

周末美食

这是本周的美食,很赞👍制作特点总结一下:

  1. 蒜多点

  2. 放点红椒或者胡萝卜丁,颜色更好些

  3. 最后焖的时候,水少些😃

image

简书APP之旅

最近爬取简书上面的数据,进行了数据分析和可视化处理,同时也制作了最终的词云图,主要是想知道最近2年都干了什么

这次爬取和以往很大的不同的是:网页是ajax动态加载的,对网页构造的分析和花费了很长的时间,还去B站上看了崔庆才大佬的视频,所以整体上还是加大了难度。

爬虫真的不简单呀😄东西越学越多,也越难咯!哈哈哈😃

image

爬取内容

以简书上面的一篇文章为例来进行解释。本来也想把砖石数爬取下来进行分析,但不是每篇都有文章都有砖石数,所以没有获取这个数据Masonry

image

数据

总共有530篇文章,但是不知道为什么爬出来总是只有527=58*9+5篇。在最后一页的爬取中总是只有5

因为网页的代码结构是一样的,爬不出来,很是无解😭暂且就这样子咯

image

实际爬到的数据只有527条:

image

网页结构

ajax网页

这是第一次爬取ajax动态加载的网页数据,知乎上看到一篇关于ajax的讲解:

AJAX 是一种在无需重新加载整个网页的情况下,能够更新部分网页的技术。

举一个例子,打开这个页面,先不要动,观察右边滚动条的长度,然后当你把滚动条下拉到底之后,滚动条就变短了,即页面变长了,也就是说有一部分数据是这个时候才加载出来的。这个过程就是动态加载,基于ajax技术。我们可以看到在拉动滚动条的时候,页面上的数据变多了,但是URL始终没有变化,它不是像翻页那样将数据存到了另一个网页。

https://zhuanlan.zhihu.com/p/35682031

网页更新

比如在这个网页的源码中,当右侧栏中的滚动条静止不动的时候,只有9篇文章即9个<li></li>标签对

image

现在当滚动条向下滑动的时候,li标签会自动更新

image

网页规律

针对ajax加载的网页,在右键—检查—Networks—XHR中查看:

image

通过headers获取一条URL地址:

image

这样我们就找到了整个爬取的URL地址,可以实现全网数据的爬取

爬取数据

导入库

import re
import requests
import pandas as pd
import csv
import jieba
import numpy as np
import matplotlib.pyplot as plt

# 绘图
import random

import plotly as py
import plotly_express as px
import plotly.graph_objects as go
import dash
import dash_core_components as dcc
import dash_html_components as html

# 显示所有列
# pd.set_option('display.max_columns', None)

# 显示所有行
# pd.set_option('display.max_rows', None)

# 设置value的显示长度为100,默认为50
# pd.set_option('max_colwidth',100)

获取网页内容

使用requests库获取网页内容

url = "https://www.js.com/u/635acc145?order_by=shared_at&page=1"
headers = {"User-Agent": "实际请求头"}

response = requests.get(url=url,headers=headers)   # 得到响应
res = response.content.decode('utf-8', 'ignore')  # 获取源码
result.append(res)
image

爬取单个字段

name为例:

image

其他字段的正则表达式为:

abstract = re.findall('<p class="abstract">\s*(.*?)\n\s*</p>', result, re.S)
watch = re.findall('class="iconfont ic-list-read"></i>(.*?)\s</a>',result, re.S)  # \s匹配空白字符;\S匹配任意非空白字符
comment = re.findall('class="iconfont ic-list-comments"></i>(.*?)\s</a>',result, re.S) 
like = re.findall('class="iconfont ic-list-like"></i>(.*?)</span>',result, re.S)
time = re.findall('lass="time" data-shared-at=(.*?)></span>',result, re.S)

最好是检查每个字段每页的个数是否为9个:

image

时间的爬取到的只是具体的时间,不要年月日

image

全网爬取

URL地址和请求头需要进行更换

# from multiprocessing import Pool

import re
import requests
import pandas as pd
import csv
import jieba
import numpy as np
import matplotlib.pyplot as plt

# !!!注意with语句的位置,放在开头:防止属性字段的重复写入到数据中

# 写入文件
with open("jianshu.csv", "a", encoding="utf-8") as f:  # 将写入的模式改成"a":表示追加模式
    writer =csv.DictWriter(f,fieldnames=["name","abstract","read","comment","like","time"])
    writer.writeheader()
        
    # url地址和请求头需要更换成实际内容
    for i in range(1,60):   # 爬取59页数据
        url = "https://www.js.com/u/6?shared_at&page={}".format(i)
        headers = {"User-Agent": "实际请求头"}

        response = requests.get(url=url,headers=headers)   # 得到响应
        res = response.content.decode('utf-8', 'ignore')

        name_list = re.findall('class="title" target="_blank".*?>(.*?)</a>',res, re.S)
        # \n:换行符;\s*:任意次数的空白;\.\.\.:匹配3个...
        abstract_list = re.findall('<p class="abstract">\s*(.*?)\n\s*</p>', res, re.S)
        # 单独写出匹配数字:{1}表示匹配1次;{1,}表示至少匹配1次
    #     masonry_list = re.findall(r'class="iconfont ic-paid1"></i>\s(\d{1,}.\d{1,}).*?</span>',res, re.S)
        read_list = re.findall('class="iconfont ic-list-read"></i>(.*?)\s</a>',res, re.S)  # \s匹配空白字符;\S匹配任意非空白字符
        comment_list = re.findall('class="iconfont ic-list-comments"></i>(.*?)\s</a>',res, re.S)
        like_list = re.findall('class="iconfont ic-list-like"></i>(.*?)</span>',res, re.S)
        time_list = re.findall('lass="time" data-shared-at=".*?T(.*?)\+.*?></span>',res, re.S)  

        result_list = []
        for j in range(len(name_list)):
            result = {
                "name": name_list[j],
                "abstract": abstract_list[j],
    #             "masonry": masonry_list[j],
                "read": read_list[j],
                "comment": comment_list[j],
                "like": like_list[j],
                "time": time_list[j]
            }

            result_list.append(result)
        writer.writerows(result_list)

数据处理

全网数据

通过上面的代码得到了全网的数据:

image

字段信息

image

time字段

排序

首先根据time字段进行排序

df_sort = df.sort_values("time")
print(df_sort.dtypes)
image
属性改变

解决的是将time字段的object数据类型改成和时间相关的。

后面发现:不用处理好像也可以正常处理time字段😭

image
散点图

横坐标是文章的名称name,纵坐标是发表的时间time,颜色是点赞次数like

fig = px.scatter(df_sort,x="name",y="time",color="like",height=900,width=1350)

app = dash.Dash()
app.layout = html.Div([
    dcc.Graph(figure=fig)
])

app.run_server()
image

time标记处理

处理规则

人为地将发表文章的时间分为4个阶段,并且用不同的数值表示:

image
增加flag字段

增加一个新的字段flag来标记上述信息:

for i in range(len(df_sort)):
    if "00:00:00" <= df_sort.loc[i,"time"] < "08:00:00":
        df_sort.loc[i,"flag"] = 1
    elif "08:00:00" <= df_sort.loc[i,"time"] < "14:00:00":
        df_sort.loc[i,"flag"]= 2
    elif "14:00:00" <= df_sort.loc[i,"time"] < "20:00:00":
        df_sort.loc[i,"flag"] = 3
    else:
        df_sort.loc[i,"flag"] = 4
image
fig = px.scatter(df_sort,x="flag",y="time",color="flag",height=800,width=1350)

app = dash.Dash()
app.layout = html.Div([
    dcc.Graph(figure=fig)
])

app.run_server()
绘图
image image
结论

通过上述图形可以看出来,在第4个阶段里面发表文章的概率是比较大的,说明大部分文章是晚上发表的:和实际情况也是符合的😃

read字段

数据信息
image
绘图
# 绘图

# 颜色的随机生成:#123456  # 加上6位数字构成
def random_color_generator(number_of_colors):
    color = ["#"+''.join([random.choice('0123456789ABCDEF') for j in range(6)])
                 for i in range(number_of_colors)]
    return color

text = read.values

trace = go.Bar(
    x = read.index,
    y = read.values,
    text = text,
    marker = dict(
        color = random_color_generator(232),
        line = dict(color='rgb(8, 48, 107)',   # 柱子的外围线条颜色和宽度
                    width = 1.5)
    ),
    opacity = 0.5   # 透明度设置
)

# 数据部分:一定是列表的形式
data = [trace]

# 布局设置
layout = go.Layout(
    title = 'Information of read',   # 整个图的标题
    margin = dict(
        l = 100   # 左边距离
    ),
    xaxis = dict(
        title = 'Number of reading'   # 2个轴的标题
    ),
    yaxis = dict(
        title = 'Count of the number of reading'
    ),
    width = 70000,  # figure的宽高
    height = 800
)

fig = go.Figure(data=data, layout=layout)

fig.update_traces(textposition="outside")   # 将每个占比显示出来,也就是y轴的值

fig.show()
image

comment字段

绘图

主要是对每篇文章的评论数量进行统计分析和制图

image image
结论

从上面的饼图看出来:评论数为0的文章占据了绝大多数,接近90%;评论数为2的文章其次

还是很少人评论呀😭😭

like字段

数据
image
绘图
# 绘图

# 颜色的随机生成:#123456  # 加上6位数字构成
def random_color_generator(number_of_colors):
    color = ["#"+''.join([random.choice('0123456789ABCDEF') for j in range(6)])
                 for i in range(number_of_colors)]
    return color

trace = go.Bar(
    x = like_number.index,
    y = like_number.values,
    text = text,
    marker = dict(
        color = random_color_generator(100),
        line = dict(color='rgb(8, 48, 107)',   # 柱子的外围线条颜色和宽度
                    width = 1.5)
    ),
    opacity = 0.7   # 透明度设置
)

# 数据部分:一定是列表的形式
data = [trace]

# 布局设置
layout = go.Layout(
    title = 'Information of like',   # 整个图的标题
    margin = dict(
        l = 100   # 左边距离
    ),
    xaxis = dict(
        title = 'Number of like'   # 2个轴的标题
    ),
    yaxis = dict(
        title = 'Count of like'
    ),
    width = 900,  # figure的宽高
    height = 500
)

fig = go.Figure(data=data, layout=layout)

fig.update_traces(textposition="outside")   # 将每个占比显示出来,也就是y轴的值

fig.show()
image
结论

词性分析与词云图

Jieba词性分析

生成列表
image
实现分词
# 2-实现分词
    
for i in range(len(name_list)):
    seg_list = jieba.cut(name_list[i].strip(), cut_all=False)  # seg_list只是一个generator生成器:<class 'generator'>
    print(("Default Mode: " + "/ ".join(seg_list)))  #  用list方法展开
image
分词结果放入列表
# 3-将分词的结果全部放入一个列表中,方便后续处理

jieba_name = []

for i in range(len(name_list)):
    seg_list = jieba.cut(name_list[i].strip(), cut_all=False)  # seg_list只是一个generator生成器:<class 'generator'>
    for str in list(seg_list):   # 对list(seg_list)中的每个元素进行追加
        jieba_name.append(str)
        
jieba_name
image
  1. 将待处理的句子放入列表中

  2. 对列表中的每个句子分词

  3. 将上面步骤中的分词结果放入到另一个列表中,方便后续处理

jieba使用总结

  1. 将待处理的句子放入列表中

  2. 对列表中的每个句子分词

  3. 将上面步骤中的分词结果放入到另一个列表中,方便后续处理

Wordcloud词云图

绘图
from wordcloud import WordCloud
import matplotlib.pyplot as plt

text = " ".join(i for i in jieba_name)   # 待处理的字符串

# 先下载SimHei.ttf字体,放置到自己的某个目录下,然后将font换成自己的路径即可
font = r'/Users/piqianchao/Desktop/spider/SimHei.ttf' 

wc = WordCloud(collocations=False, font_path=font, # 路径
               max_words=2000,width=4000, 
               height=4000, margin=2).generate(text.lower())

plt.imshow(wc)
plt.axis("off")
plt.show()

wc.to_file('jianshu.png')  # 把词云保存下来
初步结果
image

图中的札记实在是扎眼呀😃

这是因为自己Python札记写了很多的原因;另外3个比较突出的词语:利用、进行、数据分析是因为自己看了《利用Python进行数据分析》这本书

进一步处理

删除几个无价值的信息之后再进行绘图,选择了一个背景图:

noUse = ["札记","利用","进行","打卡","笔记","学习"]

for col in noUse:
    while col in jieba_name:
        jieba_name.remove(col)
from os import path
from PIL import Image
import numpy as np
import matplotlib.pyplot as plt

from wordcloud import WordCloud, STOPWORDS, ImageColorGenerator

d = path.dirname('.')   # 在ide中使用这段代码
# d = path.dirname(__file__)

# 待处理的文件(去掉无效信息之后的)
text = " ".join(i for i in jieba_name)   

# read the mask / color image taken from
# http://jirkavinse.deviantart.com/art/quot-Real-Life-quot-Alice-282261010
alice_coloring = np.array(Image.open(path.join(d, "wordcloud.png")))

# 设置停用词
stopwords = set(STOPWORDS)
stopwords.add("said")

# 路径改成自己的
font = r'/Users/piqianchao/Desktop/spider/SimHei.ttf'    

# 你可以通过 mask 参数 来设置词云形状
wc = WordCloud(background_color="white", font_path=font,
               max_words=2000, mask=alice_coloring,
               height=6000,width=6000,
               stopwords=stopwords, max_font_size=40, random_state=42)

# generate word cloud
wc.generate(text)

# create coloring from image
image_colors = ImageColorGenerator(alice_coloring)

# show
# 在只设置mask的情况下,你将会得到一个拥有图片形状的词云
plt.imshow(wc, interpolation="bilinear")
plt.axis("off")
plt.show()
wc.to_file('jianshu_one.png')  # 把词云保存下来

# recolor wordcloud and show
# we could also give color_func=image_colors directly in the constructor
# 直接在构造函数中直接给颜色:通过这种方式词云将会按照给定的图片颜色布局生成字体颜色策略
plt.imshow(wc.recolor(color_func=image_colors), interpolation="bilinear")
plt.axis("off")
plt.show()
wc.to_file('jianshu_two.png')  # 把词云保存下来
image

结论

从上面优化后的图形中可以看出来:

  1. Python是最突出的。的确如此,写的文章很多是关于Python

  2. 数据分析是一个亮点:因为《利用Python进行数据分析》这本书,还有就是很多pandas的文章

  3. MySQL也是另一个亮点:学习了很多数据库的知识,包含:MySQL、SQL、Sqlzoo、数据库等

  4. 机器一词是出自于机器学习中的,吴恩达老师带我入门的,学了很多的入门知识:吴恩达老师的视频、算法、数据结构等

  5. 深圳二字主要是因为到了深圳之后写了很多关于深圳的文章

数据还是非常准确的,很有参考价值👍数据不会说谎

上一篇下一篇

猜你喜欢

热点阅读