作为互联网界的两个对立的物种,产品汪与程序猿似乎就像一对天生的死对头;但是在产品开发链条上紧密合作的双方,只有通力合作,才能更好地推动项目发展。那么产品经理平日里面都在看那些文章呢?我们程序猿该如何投其所好呢?我爬取了人人都是产品经理(http://www.woshipm.com)产品经理栏目下的所有文章,看看产品经理都喜欢看什么

产品经理与程序员

1.分析背景

1.1. 为什么选择「人人都是产品经理」

人人都是产品经理是以产品经理、运营为核心的学习、交流、分享平台,集媒体、培训、招聘、社群为一体,全方位服务产品人和运营人,成立8年举办在线讲座500+期,线下分享会300+场,产品经理大会、运营大会20+场,覆盖北上广深杭成都等15个城市,在行业有较高的影响力和知名度。平台聚集了众多BAT美团京东滴滴360小米网易等知名互联网公司产品总监和运营总监。选取这个社区更有代表性。

1.2. 分析内容

  • 分析人人都是产品经理产品经理栏目下的 6574 篇文章的基本情况,包括收藏数、评论数、点赞数等
  • 发掘最受欢迎的文章及作者
  • 分析文章标题长度与受欢迎程度之间的关系
  • 展现产品经理都在看什么

1.3. 分析工具

  • Python 3.6
  • Matplotlib
  • WordCloud
  • Jieba

2. 数据抓取

使用 Python编写的爬虫抓取了人人都是产品经理社区的产品经理栏目下的所有文章并保存为csv格式,文章抓取时期为 2012年6月至 2019 年 1月 21日,共计6574篇文章。抓取 了 10个字段信息:文章标题、作者、作者简介、发文时间、浏览量、收藏量、点赞量、评论量、正文、文章链接。

2.1. 目标网站分析

这是要爬取的网页界面,可以看到是直接加载出来的,没有AJAX,爬取起来毫无难度。

人人都是产品经理

仔细观察要爬取的网页,我们可以看到页面连接有规律可循,连接中page后面的参数就是页面数,所以我们编写爬虫时可以直接用for循环来构造所有页面连接代码如下:

import requests
from bs4 import BeautifulSoup
import csv

headers = {'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8',
               'Accept-Language': 'zh-CN,zh;q=0.9,en;q=0.8',
               'Cache-Control': 'max-age=0',
               'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.110 Safari/537.36',
               'Connection': 'keep-alive',
               'Host': 'www.woshipm.com',
               'Cookie' : 't=MHpOYzlnMmp6dkFJTEVmS3pDeldrSWRTazlBOXpkRjBzRXpZOU4yVkNZWWl5QVhMVXBjMU5WcnpwQ2NCQS90ZkVsZ3lTU2Z0T3puVVZFWFRFOXR1TnVrbUV2UFlsQWxuemY4NG1wWFRYMENVdDRPQ1psK0NFZGJDZ0lsN3BQZmo%3D; s=Njg4NDkxLCwxNTQyMTk0MTEzMDI5LCxodHRwczovL3N0YXRpYy53b3NoaXBtLmNvbS9XWF9VXzIwMTgwNV8yMDE4MDUyMjE2MTcxN180OTQ0LmpwZz9pbWFnZVZpZXcyLzIvdy84MCwsJUU1JUE0JUE3JUU4JTk5JUJF; Hm_lvt_b85cbcc76e92e3fd79be8f2fed0f504f=1547467553,1547544101,1547874937,1547952696; Hm_lpvt_b85cbcc76e92e3fd79be8f2fed0f504f=1547953708'
               }
with open('data.csv', 'w', encoding='utf-8',newline='') as csvfile:
    fieldnames = ['title', 'author', 'author_des', 'date', 'views', 'loves', 'zans', 'comment_num','art', 'url']
    writer = csv.DictWriter(csvfile, fieldnames=fieldnames)
    writer.writeheader()
    for page_number in range(1, 549):
        page_url = "http://www.woshipm.com/category/pmd/page/{}".format(page_number)
        print('正在抓取第' + str(page_number) + '页>>>')
        response = requests.get(url=page_url, headers=headers)
        if response.status_code == 200:
            page_data = response.text

页面连链接构造完之后我们可以开始爬取文章详情页,提取所需要的信息,在这里用到的解析库是BeautifulSoup,整个爬虫非常简单,完整代码如下:

#!/usr/bin/env python
# -*- encoding: utf-8 -*-
#author:PM 小凯哥<xuxinkai.cn>

import requests
from bs4 import BeautifulSoup
import csv

headers = {'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8',
               'Accept-Language': 'zh-CN,zh;q=0.9,en;q=0.8',
               'Cache-Control': 'max-age=0',
               'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.110 Safari/537.36',
               'Connection': 'keep-alive',
               'Host': 'www.woshipm.com',
               'Cookie' : 't=MHpOYzlnMmp6dkFJTEVmS3pDeldrSWRTazlBOXpkRjBzRXpZOU4yVkNZWWl5QVhMVXBjMU5WcnpwQ2NCQS90ZkVsZ3lTU2Z0T3puVVZFWFRFOXR1TnVrbUV2UFlsQWxuemY4NG1wWFRYMENVdDRPQ1psK0NFZGJDZ0lsN3BQZmo%3D; s=Njg4NDkxLCwxNTQyMTk0MTEzMDI5LCxodHRwczovL3N0YXRpYy53b3NoaXBtLmNvbS9XWF9VXzIwMTgwNV8yMDE4MDUyMjE2MTcxN180OTQ0LmpwZz9pbWFnZVZpZXcyLzIvdy84MCwsJUU1JUE0JUE3JUU4JTk5JUJF; Hm_lvt_b85cbcc76e92e3fd79be8f2fed0f504f=1547467553,1547544101,1547874937,1547952696; Hm_lpvt_b85cbcc76e92e3fd79be8f2fed0f504f=1547953708'
               }
with open('data.csv', 'w', encoding='utf-8',newline='') as csvfile:
    fieldnames = ['title', 'author', 'author_des', 'date', 'views', 'loves', 'zans', 'comment_num','art', 'url']
    writer = csv.DictWriter(csvfile, fieldnames=fieldnames)
    writer.writeheader()
    for page_number in range(1, 549):
        page_url = "http://www.woshipm.com/category/pmd/page/{}".format(page_number)
        print('正在抓取第' + str(page_number) + '页>>>')
        response = requests.get(url=page_url, headers=headers)
        if response.status_code == 200:
            page_data = response.text
            if page_data:
                soup = BeautifulSoup(page_data, 'lxml')
                article_urls = soup.find_all("h2", class_="post-title")
                for item in article_urls:

                    url = item.find('a').get('href')
                    # 文章页面解析,获取文章标题、作者、作者简介、日期、浏览量、收藏量、点赞量、评论量、正文、文章链接
                    response = requests.get(url=url, headers=headers)
                    # time.sleep(3)
                    print('正在抓取:' + url)
                    # print(response.status_code)
                    if response.status_code == 200:
                        article = response.text
                        # print(article)
                        if article:
                            try:
                                soup = BeautifulSoup(article, 'lxml')
                                # 文章标题
                                title = soup.find(class_='article-title').get_text().strip()
                                # 作者
                                author = soup.find(class_='post-meta-items').find_previous_siblings()[1].find('a').get_text().strip()
                                # 作者简介
                                author_des = soup.find(class_='post-meta-items').find_previous_siblings()[0].get_text().strip()
                                # 日期
                                date = soup.find(class_='post-meta-items').find_all(class_='post-meta-item')[0].get_text().strip()
                                # 浏览量
                                views = soup.find(class_='post-meta-items').find_all(class_='post-meta-item')[1].get_text().strip()
                                # 收藏量
                                loves = soup.find(class_='post-meta-items').find_all(class_='post-meta-item')[2].get_text().strip()
                                # 点赞量
                                zans = soup.find(class_='post-meta-items').find_all(class_='post-meta-item')[3].get_text().strip()
                                # 评论量
                                comment = soup.find('ol', class_="comment-list").find_all('li')
                                comment_num = len(comment)
                                # 正文
                                art = soup.find(class_="grap").get_text().strip()

                                writer.writerow({'title':title, 'author':author, 'author_des':author_des, 'date':date, 'views':views, 'loves':int(loves), 'zans':int(zans), 'comment_num':int(comment_num), 'art':art, 'url':url})
                                print({'title':title, 'author':author, 'author_des':author_des, 'date':date, 'views':views, 'loves':loves, 'zans':zans, 'comment_num':comment_num})
                            except:
                                print('抓取失败')
    print("抓取完毕!")

在这里说一点,评论数的爬取,观察文章详情页你可以发现并没有评论数,我这里是直接计算出来的,可以看到评论是嵌套在ol里面,抓起所有的li,然后就可以计算出,代码如下:

 # 评论量
comment = soup.find('ol', class_="comment-list").find_all('li')
comment_num = len(comment)

这样,我们运行一下爬虫就能够顺利爬取594页的结果了,我这里一共抓取了6574条结果,大概也就玩了两把吃鸡就抓完了。

以上,就完成了数据的获取。有了数据我们就可以着手分析,不过这之前还需简单地进行一下数据的清洗、处理。

3. 数据清洗处理

首先,我们需要把csv文件转换为 DataFrame。

# 将csv数据转为dataframe
csv_file = "data.csv"
csv_data = pd.read_csv(csv_file, low_memory=False)  # 防止弹出警告
csv_df = pd.DataFrame(csv_data)

下面我们看一下数据的总体情况,可以看到数据的维度是6574行×10 列。需要将views列更改为数值格式、date列更改为日期格式。

date列更改为日期非常简单,代码如下:

# 修改date列时间,并转换为 datetime 格式
csv_df['date'] = pd.to_datetime(csv_df['date'])

views列处理思路是增加一列,名字就叫views_num吧,我们可以观察到views列有的数值是整数,有的则是1.7万这种,代码如下:
image

我们再输出一下看看各列数据类型:
image

可以看到数据类型已经变成我们想要的了,下面,我们看一下数据是否有重复,如果有,那么需要删除。
image

然后,我们再增加两列数据,一列是文章标题长度列,一列是年份列,便于后面进行分析。
image

以上,就完成了基本的数据清洗处理过程,针对这些数据可以开始进行分析了。

4. 描述性数据分析

通常,数据分析主要分为四类:「描述型分析」、「诊断型分析」「预测型分析」「规范型分析」。「描述型分析」是用来概括、表述事物整体状况以及事物间关联、类属关系的统计方法,是这四类中最为常见的数据分析类型。通过统计处理可以简洁地用几个统计值来表示一组数据地集中性(如平均值、中位数和众数等)和离散型(反映数据的波动性大小,如方差、标准差等)。

这里,我们主要进行描述性分析,数据主要为数值型数据(包括离散型变量和连续型变量)和文本数据。

4.1. 总体情况

先来看一下总体情况,使用了data.describe() 方法对数值型变量进行统计分析。
image

mean 表示平均值,std表示标准差,从上面可以简要得出以下几个结论:

  • 产品经理热爱学习,看到好的文章就收藏下来。75%的文章收藏量破百,50%的文章浏览量破百;
  • 产品话少,对别人的文章很少会评头论足。文章的评论数都寥寥无几。
  • 产品不愿意承认别人比自己优秀。绝大部分文章点赞数都是一二十个,所以程序猿们以后不要在产品面前吹嘘技术如何了得了,产品是不会承认你厉害的。

对于非数值型变量(author、date),使用 describe() 方法会产生另外一种汇总统计。
image

unique 表示唯一值数量,top表示出现次数最多的变量,freq表示该变量出现的次数,所以可以简单得出以下几个结论:

  • 一共有1531位作者为社区的产品经理栏目贡献了文章,其中贡献量最大的作者叫 Nairo ,贡献了315篇;
  • 在2015年1月29日栏目文章发布数最大,达到了16篇。栏目第一篇文章发布在2012年11月25日。

4.2. 不同时期文章发布的数量变化

image
从图中可以看到,网站文章发布数量在2012到2015年逐年递增,增幅很大,这可能与网站的知名度提高有关;2015年2季度之后比较平稳。后面的分析代码就不一一贴出,文末会留下代码下载链接。

4.3. 文章浏览量 TOP10

接下来,到了我们比较关心的问题:几万篇文章里,到底哪些文章写得比较好或者比较火
image

这里以阅读量作为衡量标准,排在第一的是《小白产品经理看产品:什么是互联网产品》,第一名的浏览量遥遥领先于第二名,接近百万,看来很多社区里面很多都是产品小白。而且看这几篇文章标题,貌似都是介绍什么是产品经理,产品经理干什么,看来社区里面初级产品挺多的。

4.4. 历年文章收藏量 TOP3

在了解文章的总体排名之后,我们来看看历年的文章排名是怎样的。这里,每年选取了收藏量最多的 3 篇文章。
image
image

从图中可以看出,2015年是的那篇文章收藏量是最多的,达到了2000,文章内容则是后台产品设计,看来这篇文章里面干货满满。

4.4.1. 最高产作者 TOP20

上面,我们从收藏量指标进行了分析,下面,我们关注一下发布文章的作者。前面提到发文最多的是Nairo,贡献了315篇,这里我们看看还有哪些比较高产的作者。
image

可以看到第一名遥遥领先,是个狼人,大家可以关注一下这些优质作者。

4.4.2. 平均文章收藏量最多作者 TOP 10

我们关注一个作者除了是因为文章高产以外,可能更看重的是其文章水准。这里我们选择「文章平均收藏量」(总收藏量/文章数)这个指标,来看看文章水准比较高的作者是哪些人。这里,为了避免出现「某作者只写了一篇高收藏率的文章」这种不能代表其真实水准的情况,我们将筛选范围定在至少发布过 5 篇文章的作者们。
image

对比这张图和前面的发文数量排行榜,我们可以发现这张图的作者均没有上榜,相比于数量,质量可能更重要吧。

4.5. 文章评论数最多 TOP10

说完了收藏量。下面,我们再来看看评论数量最多的文章是哪些。
image

我们可以看到大部分都与初级产品有关,而且我们可以看到评论多,收藏量也挺多的,我们进一步探寻两者之间关系。

image

我们可以发现绝大部分文章评论数和收藏量都很小。

4.6. 文章标题长度

下面,我们再来看看文章标题的长度和阅读量之间有没有什么关系。
image
我们可以看到文章标题长度在20左右时阅读量普遍较高。

4.7. 文本分析

最后,我们从这 5 万篇文章中的正文内容中看看产品经理都在看什么。
image
我们可以看到设计、工作、数据、功能、需求、项目等都是产品经理们关注的东西,产品们也很辛苦啊,程序猿以后不要吐槽自己多辛苦了。

  1. 小结
    • 本文简要分析了人人都是产品经理产品经理栏目下6574篇文章信息,大致了解了产品经理都在看什么;
    • 发掘了那些优秀的文章和作者,能够产品新人指明方向;
    • 告诉了程序猿与产品经理聊天时该说什么;
    • 本文尚未做深入的文本挖掘,而文本挖掘可能比数据挖掘涵盖的信息量更大,更有价值。进行这些分析需要机器学习和深度学习的知识。

参考资料:

  • 搜狗细胞词库;

本文源代码下载地址:
点击下载

本文首发于2019年1月份,现迁移到博客。

最后修改日期:2020-03-12

留言

撰写回覆或留言

发布留言必须填写的电子邮件地址不会公开。