为何大学女生比男生看起来有钱得多

作者: 皮皮大 | 来源:发表于2020-07-13 19:59 被阅读0次

    本文中介绍的如何通过\color{red}{正则表达式}来爬取百度贴吧中的内容,并且通过Jieba分词和wordcloud来实现图云展示

    选取的话题是:为何大学女生比男生看起来有钱得多

    image

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

    项目成果

    • 如何获取网页源码
    • re模块中正则表达式的使用
    • 如何写入csv文件
    • jieba分词
    • wordcloud绘制图云

    爬取内容

    ()表示提取其中的内容,找到3个需要提取信息的源码特点,写出了如下的正则表达式

    • 名称:class="d_name".*?target="_blank">([\u4e00-\u9fa5+\w])
    • 内容:class="d_post_content j_d_post_content.?">(.?)<
    • 时间:class="tail-info">(20.*?)<

    所有的时间都以20开头

    image image image

    数据

    爬取的数据总共有15页,每页大概30条信息

    image

    单个网页

    导入库

    import re   # 正则表达式
    import requests  # 获取网页内容
    import csv  #  保存成csv文件
    import pandas as pd  # 数据处理
    
    # 显示所有列
    # 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://tieba.baidu.com/p/6792642821?pn=1"
    headers = {"User-Agent": "实际请求头"}
    
    response = requests.get(url=url,headers=headers)   # 得到响应
    res = response.content.decode('utf-8', 'ignore')  # 获取整个网页源码` </pre>
    

    正则使用

    username_list

    通过获取username_list为例,来讲解正则表达式的使用

    image

    效果如下:我们只需要username_list部分,保存到相应的列表中

    image
    content_list

    元素如果为空,表示回复的是图片,无法抓取到相应的内容

    image
    reply_time_list
    image

    源码

    # 爬取单个网页的内容到tieba1.csv中
    
    import re
    import requests
    import csv
    import pandas as pd
    
    url = "https://tieba.baidu.com/p/6792642821?pn=1"
    headers = {"User-Agent": "更换成实际请求头"}
    
    response = requests.get(url=url,headers=headers)   # 得到响应
    res = response.content.decode('utf-8', 'ignore')  # 获取源码
    
    username_all = re.findall('class="d_name".*?target="_blank">(.*?)</a>',res,re.S)
    username_list = []
    
    for name in username_all:
        user = re.sub("<img.*?/>","",name)  # 将username中的img标签去掉
        username_list.append(user)
    
    content_list = re.findall('"d_post_content j_d_post_content.*?">(.*?)<',res,re.S)
    reply_time_list = re.findall('class="tail-info">(20.*?)<',res,re.S)
    
    result_list = []
    for i in range(len(username_list)):
        result = {
            "username": username_list[i],
            "content":content_list[i],
            "reply_time":reply_time_list[i]
        }
        result_list.append(result)
    
    # 保存文件:csv模块使用
    with open("tieba1.csv", "a", encoding="utf-8") as f:
        writer =csv.DictWriter(f,fieldnames=["username","content","reply_time"])  # 构造实例化对象
        writer.writeheader()  # 写入表头
        writer.writerows(result_list)   # 将列表中的内容全部写入实例对象中` 
    

    全网爬取

    过程

    • format()方法实现URL地址的更新
    • requests库的使用
    • 正则表达式获取3项内容
    • csv模块使用,写入到文件中
    import re
    import requests
    import csv
    import pandas as pd
    
    # 总共有15页
    for i in range(1,16):  
        url = "https://tieba.baidu.com/p/6792642821?pn={}".format(i)  # 通过format函数实现
        headers = {"User-Agent": "实际请求头"}
    
        response = requests.get(url=url,headers=headers)   # 得到响应
        res = response.content.decode('utf-8', 'ignore')  # 获取源码
        # 先获取名称,有些名称是带有img标签的,需要去掉
        username_all = re.findall('class="d_name".*?target="_blank">(.*?)</a>',res,re.S)
    
        username_list = []
        for name in username_all:
            user = re.sub("<img.*?/>","",name)  # 将img标签替换成空格,得到完整的只含有中文和英文字母的标签
            username_list.append(user)   # 将全部的user放到username_list中
    
        content_list = re.findall('"d_post_content j_d_post_content.*?">(.*?)<',res,re.S)
        reply_time_list = re.findall('class="tail-info">(20.*?)<',res,re.S)
    
        result_list = []
        for j in range(len(username_list)):
            result = {
                "username": username_list[j],
                "content":content_list[j],
                "reply_time":reply_time_list[j]
            }
            result_list.append(result)
    
        with open("tieba.csv", "a", encoding="utf-8") as f:  # 将写入的模式改成"a":表示追加模式
            writer =csv.DictWriter(f,fieldnames=["username","content","reply_time"])
            writer.writeheader()
            writer.writerows(result_list)
    
    df = pd.read_csv("tieba.csv")  # 读取文件
    df
    

    全网数据

    通过爬取15个页面得到的数据如下的表格:

    • 3个属性字段
    • 464条记录

    我们进行的处理是content字段,分析哪些词语是高频词语

    image

    Jieba

    参考

    https://blog.csdn.net/FontThrone/article/details/72782971

    https://github.com/fxsjy/jieba

    安装jieba

    这是我第一次使用jieba来进行分词操作,所以需要先进行安装

    pip install -i https://pypi.douban.com/simple jieba` </pre>
    
    image

    分词

    • jieba.cut 方法接受4个输入参数:

      1. 需要分词的字符串
      2. cut_all 参数用来控制是否采用全模式
      3. HMM 参数用来控制是否使用 HMM 模型
      4. use_paddle 参数用来控制是否使用paddle模式下的分词模式,paddle模式采用延迟加载方式,通过enable_paddle接口安装paddlepaddle-tiny,并且import相关代码;
    • jieba.cut_for_search 方法接受2个参数:

      1. 需要分词的字符串;
      2. 是否使用 HMM 模型。该方法适合用于搜索引擎构建倒排索引的分词,粒度比较细

    注意点

    1. 待分词的字符串可以是 unicode 或 UTF-8 字符串、GBK 字符串。注意:不建议直接输入 GBK 字符串,可能无法预料地错误解码成 UTF-8

    2. jieba.cut以及jieba.cut_for_search返回的结构都是一个可迭代的generator,可以使用 for 循环来获得分词后得到的每一个词语(unicode),或者用

    3. jieba.lcut以及jieba.lcut_for_search直接返回 list

    4. jieba.Tokenizer(dictionary=DEFAULT_DICT)新建自定义分词器,可用于同时使用不同词典。jieba.dt` 为默认分词器,所有全局分词相关函数都是该分词器的映射。

    demo

    这个是jiebaGitHub上面给的一个入门案例,仅供参考学习

    # encoding=utf-8
    import jieba
    
    jieba.enable_paddle()# 启动paddle模式。 0.40版之后开始支持,早期版本不支持
    strs=["我来到北京清华大学","乒乓球拍卖完了","中国科学技术大学"]
    for str in strs:
        seg_list = jieba.cut(str,use_paddle=True) # 使用paddle模式
        print("Paddle Mode: " + '/'.join(list(seg_list)))
    
    seg_list = jieba.cut("我来到北京清华大学", cut_all=True)
    print("Full Mode: " + "/ ".join(seg_list))  # 全模式
    
    seg_list = jieba.cut("我来到北京清华大学", cut_all=False)
    print("Default Mode: " + "/ ".join(seg_list))  # 精确模式
    
    seg_list = jieba.cut("他来到了网易杭研大厦")  # 默认是精确模式
    print(", ".join(seg_list))
    
    seg_list = jieba.cut_for_search("小明硕士毕业于中国科学院计算所,后在日本京都大学深造")  # 搜索引擎模式
    print(", ".join(seg_list))
    
    image

    处理

    1. 我们需要处理的content字段。jieba处理的是列表类型的数据,所以现将全部的content字段中的信息放到一个列表中:
    image
    1. 将上述步骤中实现的列表strings中每个字符串进行分词
    # encoding=utf-8
    import jieba
    
    for i in range(len(strings)):
        seg_list = jieba.cut(strings[i].strip(), cut_all=False)  # seg_list只是一个generator生成器:<class 'generator'>
        print(("Default Mode: " + "/ ".join(seg_list)))  #  用list方法展开
    

    分词之后的效果如下:

    image
    1. 将分词的结果放入到另一个列表comment中,方便后续wordcloud的处理
    # encoding=utf-8
    import jieba
    
    comment = [] 
    for i in range(len(strings)):
       # 对每个元素分别进行分词操作
        seg_list = jieba.cut(strings[i].strip(), cut_all=False)  # seg_list只是一个generator生成器:<class 'generator'>  ;用list(seg_list))  #  用list方法展开
    
        for str in list(seg_list):   # 对lsit(seg_list)中的每个元素进行追加
            comment.append(str)
    
    comment
    
    image

    wordcloud

    参考

    👉wordcloud十五分钟快速入门与进阶

    👉GitHub-wordcloud

    👉wordcloud

    安装

    第一次使用,所以还是需要先进行安装

    pip install -i https://pypi.douban.com/simple wordcloud
    

    数据处理

    wordcloud处理的是一个字符串信息。因此,在进行绘制词云图之前,我们需要先将上面comment字典中的全部元素放置在一起,然后转成一个整体的字符串。

    text = " ".join(i for i in comment)
    text
    

    效果如下:

    image

    生成词云

    初步处理

    wordcloud生成词云图是依赖Matplotlib包,所以需要先安装Matplotlib(如果没有)

    # -*- coding: utf-8 -*-
    
    from wordcloud import WordCloud
    import matplotlib.pyplot as plt
    
    text = " ".join(i for i in comment)   # 待处理的字符串
    
    # 先下载SimHei.ttf字体,放置到自己的某个目录下,然后将font换成自己的目录即可
    font = r'/Users/peter/Desktop/spider/SimHei.ttf'   # 改成相应的字体的路径即可
    wc = WordCloud(collocations=False, font_path=font, # 路径
                   max_words=2000,width=4000, 
                   height=4000, margin=4).generate(text.lower())
    
    plt.imshow(wc)
    plt.axis("off")
    plt.show()
    
    wc.to_file('show_Chinese.png')  # 把词云保存下来
    

    wordcloud默认的图片背景生成的初步效果如下:

    image

    进一步处理

    从上面的词云图中看出来,有多个非常明显没有任何价值的字符信息,比如:

    大写的\color{red}{男生、女生}占据了整个词云图的绝大部分空间,这样的效果肯定不是我们需要的。我们先在待处理的信息中将它们人为地删除掉:

    # 人为设置无效的信息
    noUse = ["男生","女生","就是","因为","可以","不是","自己","什么","知道","这个","地方","而且","东西","这些","或者","基本","所以","怎么","时候","你们","我们","content","女孩","的","我",",","视频","关于","也","就","了","*","是","不",","]
    
    for col in noUse:  # 对于noUse中的每个元素,如果也在comment中,则将comment中将其删除
        while col in comment:
            comment.remove(col)
    

    进行删除操作之后,comment中的无效信息会被删除,再绘制一次词云图。

    不同的是,在这里使用了一个图片作为最终结果的背景:

    image
    # 人为设置无效的信息
    noUse = ["男生","女生","就是","因为","可以","不是","自己","什么","知道","这个","地方","而且","东西","这些","或者","基本","所以","怎么","时候","你们","我们","content","女孩","的","我",",","视频","关于","也","就","了","*","是","不",","]
    
    for col in noUse:  # 对于noUse中的每个元素,如果也在comment中,则将comment中将其删除
        while col in comment:
            comment.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 comment)   
    
    # 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/peter/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('show_Chinese_three.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('show_Chinese_four.png')  # 把词云保存下来
    

    效果如下:

    image

    另一种颜色对比:

    image

    结论

    关键词

    从改进后的词云图中可以看出来,回复的评论中出现频率高、且有意义(作者的意见😃)的词语是:

    • 家里
    • 有钱
    • 男朋友
    • 电脑、游戏、键盘(应该是男生相关的)
    • 穷养
    • 富养
    • 花钱
    • 化妆品

    结论

    1. 男生都喜欢电脑和游戏,把钱花在了游戏和装备上
    2. 女生则喜欢化妆品
    3. 大学女生的钱可能一部分来自家庭,一部分来自男朋友
    4. 家庭对男生、女生的养育态度不同:穷养与富养

    大学女生就是有钱😊

    相关文章

      网友评论

        本文标题:为何大学女生比男生看起来有钱得多

        本文链接:https://www.haomeiwen.com/subject/fuuzcktx.html