2018年,我在简书写下了这些文字

转眼间,2018年即将过去,各种APP开始推送我在2018年做了那些时间,花了多少时间在这些APP上面。当然我们的生活还得掌握在自己的手上,我需要给我这一年来的写作做一个总结。

我的文章基本都在简书上,从2016年到现在将近写了300篇,本次的数据挖掘主要基于简书平台。

数据获取

数据挖掘的第一步是在于数据获取,数据获取的常见策略就是网页爬虫。我本身就是靠爬虫入门Python,后期也花了一些时间在爬虫的练习上,所以这一步难不倒我。代码如下:

# 构建抓取的主页面
headers = {
    "user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.98 Safari/537.36",
    "accept": "text/html, */*; q=0.01"
}
# 构建爬取链接
url = "https://www.jianshu.com/u/9ea40b5f607a?order_by=shared_at"
data = {
    'page': 1
}
# 爬取所有文章页面的URL
pattern = re.compile(r'<a.*href=("/p/[0-9a-zA-Z]*")>')
# 一共296篇,每页9篇
page_num = math.floor( 296 / 9) 
page_url = []
for i in range(1, page_num+2):
    data['page'] = i
    r = requests.get(url = url, headers=headers, params=data)
    # 判断返回码是否为200
    if r.status_code == 200:
        # 从主页面解析出其他页面的网址
        hrefs = re.findall(pattern=pattern, string=r.text)
        # 去重
        hrefs = list(set(hrefs))
        # 加入url
        page_url += hrefs
        # 随机等待几秒, 避免对服务器造成太大压力
        time.sleep(random.random() * 10 / 2)
    else:
        #如果不为200, 则返回当前的爬取页面
        print("current page is:{}".format(i))
        break
# 保存所有的URL地址信息
url_file = open('page_url.txt','w')
for url in page_url:
    url_file.write('https://www.jianshu.com' + url[1:-1] + '\n')
    
url_file.close()
# 为了方便进行时间分析,将时间以时间戳(timestamp)的形式进行存放
# 获取的时间是当地时间
def time_convert(localtime, fmt="%Y.%m.%d %H:%M"):
    tmp_time = time.strptime(localtime,fmt)
    tmp_stamp = time.mktime(tmp_time)
    return tmp_stamp
def parse_page_url(url, headers):
    r = requests.get(url, headers=headers)
    soup = BeautifulSoup(r.content, "lxml")
    # 标题
    title = str(soup.find(attrs={"class":"title"}).string)
    # 文章发布时间
    publish_time = soup.find(attrs={"class":"publish-time"})
    first_publish_time = time_convert(str(publish_time.string[:-1]))
    ## 并非所有文章都会有更新
    if publish_time.get('title'):
        last_update_time = time_convert(" ".join(publish_time['title'].split(" ")[1:]))
    else:
        last_update_time = ""
    # 除了字数,标题和日期外, 其他是动态加载
    # 仔细观察网页,发现最后有一个<script type="application/json">部分记录着需要的信息
    # 多级结构
    info_dict = json.loads(str(soup.find(attrs={"data-name":"page-data"}).string))
    #print(info_dict)
    likes_count = info_dict['note']['likes_count']
    views_count = info_dict['note']['views_count']
    public_wordage = info_dict['note']['public_wordage']
    # 返回字典
    return {
        'title' : title,
        'first_time': first_publish_time,
        'last_time': last_update_time,
        'likes': likes_count,
        'views': views_count,
        'words': public_wordage
    }
stat_list = []
for url in open("./page_url.txt",'r'):
    url = url.strip()
    time.sleep(random.random() * 10 / 2)
    print("Processing {}".format(url))
    result = parse_page_url(url, headers=headers)
    print("The title is {}".format(result['title']))
    print("The view is {}".format(result['views']))
    stat_list.append(result)
# 数据保存为JSON格式
with open('artile_stat.json','w', encoding="utf-8") as file:
    file.write(json.dumps(stat_list,indent=2,ensure_ascii=False))

代码虽然很长,但是逻辑比较简单,就是先获取我所有的文章的URL,然后从每个URL中获取每个文章的如下信息(这里没有获取文章全文,后期如果做文本挖掘的话,会考虑下载全文。)

  • 文章名
  • 发表日期
  • 字数
  • 阅读量
  • 喜欢数

其中获取阅读量和喜欢数的过程比较麻烦,因为简书稍微把这些信息藏了起来,利用了js脚本最后进行加载,所以找了半天。(估计未来就要用ajax技术反爬取了)

还有一点,我将时间也特意转成了时间戳的形式,方便涉及到时间序列的分析。

最后数据保存为JSON格式,便于不同程序间的数据交互。

数据探索

数据探索原本计划用的R语言,但是考虑连续性,就继续用了Python(毕竟我又不是只会一门R语言)。

加载数据,查看数据是否能够被pandas识别。

import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
df = pd.read_json('./artile_stat.json', encoding="utf-8")
df.head()

pandas非常智能的将时间戳用人类更加喜欢的形式进行了展示。

前5行

第一个问题: 我到目前为止一共写了多少字,有多少人看?

total_words = np.sum(df['words'])
total_views = np.sum(df['views'])
total_likes = np.sum(df['likes'])
print(total_words, total_views, total_likes)
# 334190 335781 1512

简书本身也是有字数统计和收获的喜欢数统计,我进行了比较之后发现两者基本吻合。而总阅读量则是简书没有提供给我的信息。

数据显示,从2016年开始到现在,我一共写了30多万字,有30多万的浏览次数,考虑到我写了快300篇,也就是平均每篇的1000阅读量。那么,只要我坚持写下去,再写700篇,阅读量就能破百万了。

# 统计不同年份的字数,喜欢数,字数
year_stat = df.groupby([pd.Grouper(freq="1Y", key="first_time")]).sum()
year_stat.iloc[:,1:3].plot(kind="line")

那么这些数据细化到每一年又是一种怎样的变化呢?

阅读量
喜欢数

尽管我写的东西的确实越来越多了,但是后期专业性越来强,技术内容越来越多,反而我的阅读量是越来越少。但是阅读量并不是衡量作品的最好指标,毕竟很多阅读量仅仅是来自于搜索引擎,喜欢数可能才是更好的指标,所以从这个角度,我写的东西反倒是更受专业的人的喜欢了。希望2019年,我也不在局限于我自己的专业领域,也要多扯淡,写点群众们喜闻乐见的文章。

以上算是年度性的总结,如果单独看2018年,还可以看下哪一个月的写作量最高,以及我喜欢在周几推送文章呢?

index = df.first_time > pd.to_datetime('2018-1-1',format="%Y-%m-%d")
year2018 = df[index]
month_stat = year2018.groupby(pd.Grouper(freq="1W",key="first_time"))
month_stat.count().iloc[:,2].plot(kind="line")
一年中的发表分布

我发现今年的6月份和7月份写的东西很少,然而我也记不起当时自己为何写的那么少,反思一下,可能天气太热,没有状态。

week_stat = year2018.groupby(df['first_time'].dt.dayofweek)['title'].count()
week_stat.plot(kind="bar")
一周的发文分布

这里的0表示周一,5和6就是周六和周日,这个分布就非常容易理解了,毕竟周末是休息的时间呀。

接下来就是评选下我的年度最受欢迎的文章了, 我最喜欢其中snakemake--我最喜欢的流程管理工具, 因为snakemake是我使用频率比较频繁的工具,所以里面会有很多新的体会在里面,而且我也安利了很多人去用它。

year2018.sort_values(by="views", ascending=False).iloc[0:10,:]
年度十佳

最后做一个词云,总结下我的2018吧。

# 词频分析
import jieba
all_words = "\n".join(df.title)
words = jieba.lcut(all_words)
counts = {}
stopwords = [line.strip() for line in open("./STOP_USE.txt", encoding="utf-8").readlines()]

for word in words:
    if word not in stopwords:
        if len(word) == 1:
            continue
        else:
            counts[word] = counts.get(word,0) + 1
from PIL import Image
from wordcloud import WordCloud, STOPWORDS, ImageColorGenerator
stopwords += list(STOPWORDS)
my_mask = np.array(Image.open("./mask.jpg"))
wc = WordCloud(width= 3000,
               height= 1500,
               max_words= 300,
               background_color="white", 
               mask=my_mask,
               stopwords=stopwords, 
               max_font_size=50,
              font_path='./SourceHanSerifCN-Regular.ttf')
wc.generate(" ".join(words))
wc.to_file("result.pdf")
我的2018
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,482评论 6 481
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,377评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 152,762评论 0 342
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,273评论 1 279
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,289评论 5 373
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,046评论 1 285
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,351评论 3 400
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,988评论 0 259
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,476评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,948评论 2 324
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,064评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,712评论 4 323
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,261评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,264评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,486评论 1 262
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,511评论 2 354
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,802评论 2 345

推荐阅读更多精彩内容