转载

小试分答数据挖掘

背景

选了付费问答类题目,在体验分答的过程中,发现分答的模式,提问者的答案被偷听是需要1元,提问者可以分成0.5元。想到几个问题: 1. 有哪些问题是可以赚到钱的。 2. 哪些人是在分答上赚到钱的。 3. 哪些人才是分答上最受欢迎的。 4. 能否从分答的数据上分析用户是否活跃,有没有前景。 显然,这些数据是无法直接在网上直接找到的。要想得到答案,需要爬取分答的数据。 之前没有搞过类似爬取,想尝试爬取的乐趣 小试分答数据挖掘

打算怎么玩

通常的数据爬取都用python,也有很多成熟的爬取方案。但是,我想尝试一下Go。一来温习一下Go相关知识。二来学习Go上其他没有接触过的东西

数据爬取

抓包

  1. 电脑安装配置神器OWSAP ZAP,设置代理服务器,用来截取手机数据
  2. 手机设置代理服务器地址
  3. 手机打开分答应用,打开各个页面看看请求的链接和返回的数据格式

    分析请求和数据

    需要分析出哪些数据是从哪些链接请求来的,返回数据的格式。
  4. 获取账户信息
    `
    http://apis-fd.zaih.com/v1/accounts/587503258
    返回的结果是json格式
    ``
    {"answers count": 209, "avatar": "http://wx.qlogo.cn/mmopen/RZrGLEga7AiawE5sTQk0kItX6c9JR5dLkkKv1ZTosFv3Llc7upHc26pH8Ls75NYuDsr68pZzbic2UiaZqqgiaLEDVUngOpg0YgtI/0", "followers count": 16220, "gravity": -1, "id": 587503258, "income": 12777950, "introduction": "u4f17u591au660eu661fu827au4ebau7684u79c1u4ebau60c5u611fu4e13u5bb6uff0cu54a8u8be2u673au6784u82b1u9547u8463u4e8bu957fu3001u767eu4e07u7545u9500u4e66u4f5cu5bb6u2026u672cu5e73u53f0u6536u5165u5c06u5168u90e8u7528u4f5cu5973u6027u516cu76cau3002u5728u4f60u95eeu4e4bu524du5148u82b1u4e00u70b9u5c0fu94b1u628au522bu4ebau7684u542cu4e00u4e0buff0cu4e5fu8bb8u4e0du7528u95eeu5c31u80fdu627eu5230u7b54u6848u3002", "is black": false, "is followed": false, "is receive inquiry": true, "is verified": true, "nickname": "ayawawa", "price": 50000, "questions count": 3, "tags": [{"id": 17, "name": "u60c5u611f"}], "tenant": {}, "title": "u7545u9500u4e66u4f5cu5bb6uff0cu8457u6709u300au5b8cu7f8eu5173u7cfbu7684u79d8u5bc6u300bu7b49"} ``` 从上可以看到,个人信息基本都有了,回答个数(answers_count),收入(income),问题价格(price,分币)等等 奇怪地是,跟通用的api需要带个授权码appkey不同,分答接口是不需要票据就能直接拉取的。
  5. 获取问题数据
    `
    http://apis-fd.zaih.com/v1/accounts/587503258/answers?page=1ℴ_by=default&per_page=20
    每个用户回答的题目结果,分页返回。可以通过轮询查询,只要返回了空结果就结束。
    这里请求的结果有点多,就不贴了,直接对结果的格式进行分析。前面用户信息的格式,比较简单,但是要手工弄成Go的结构体也是一件麻烦事。任凭vim各种奇巧淫技终究累得半死。于是,想一定有从json的实例,直接转成Go结构体的,果然,搜到了json-to-go(https://mholt.github.io/json-to-go/)。用问题请求返回的结果。贴上去,处理结果如下
    ``
    type AutoGenerated []struct { Answer struct { DateUpdated time.Time
    json:"date_updated"
    Duration int
    json:"duration"
    FreeKey interface{}
    json:"free_key"
    ID string
    json:"id"
    IsEnableReanswer bool
    json:"is_enable_reanswer"
    IsFree bool
    json:"is_free"
    IsLiked bool
    json:"is_liked"
    IsOpposed bool
    json:"is_opposed"
    IsReanswered bool
    json:"is_reanswered"
    LikingsCount int
    json:"likings_count"
    OpposedCount int
    json:"opposed_count"
    QuestionID string
    json:"question_id"
    Voice interface{}
    json:"voice"
    }
    json:"answer"
    Asker struct { AnswersCount int
    json:"answers_count"
    Avatar string
    json:"avatar"
    ID int
    json:"id"
    Nickname string
    json:"nickname"
    Price int
    json:"price"
    Title string
    json:"title"
    }
    json:"asker"
    Content string
    json:"content"
    DateCreated time.Time
    json:"date_created"
    DateUpdated time.Time
    json:"date_updated"
    DiscussionsCount int
    json:"discussions_count"
    HasDiscussions bool
    json:"has_discussions"
    ID string
    json:"id"
    IsFendaAsk bool
    json:"is_fenda_ask"
    IsSticky bool
    json:"is_sticky"
    ListeningsCount int
    json:"listenings_count"
    Offer int
    json:"offer"
    Respondent struct { AnswersCount int
    json:"answers_count"
    Avatar string
    json:"avatar"
    ID int
    json:"id"
    Nickname string
    json:"nickname"
    Price int
    json:"price"
    Title string
    json:"title"
    }
    json:"respondent"
    RespondentID int
    json:"respondent_id"
    Status string
    json:"status"
    Type string
    json:"type"
    VisitorCount int
    json:"visitor_count"
    } ``` 清晰明了,妥妥的。 接下来的套路就是“请求-返回-解包-存储" 使用Go自带的http包和json包,请求和解析一气呵成。
`
// requestData request data from url and decode to data.
func requestData(url string, data interface{}) (err error) {
var resp *http.Response
resp, err = http.Get(url)
if err != nil {
return
}
defer resp.Body.Close()
dec := json.NewDecoder(resp.Body)
err = dec.Decode(&data)
return
}

`

爬取的面对问题

  1. 全量账号 当然,账号id不是加一递增的。如何抓取全量的用户是个问题。刚开始在分答的“找人/全部/分类”入手,把每个“分类”每一类人爬取账号。再合并。后来发现数据并不全面。后来再穷举账号,只要有数据返回的且正确(id不为0)的,这种方式要么太慢了不符合目的。要么追求速度,过于暴力,终会被被屏蔽了事。
  2. 爬取任务分发 刚开始在单机爬取,拉取完数据后再统一写入,cpu使用也只在2%左右,发现太慢了。如果目标数据量小,可以顶住,但是根据分答宣传的用户量来看显然不行。后来紧急开发了并发版本(多个go routine爬数据,单个写数据)。单核上100%,还是觉得太慢,上多进程。最终炼成。。大祸,机器被屏蔽。 每个进程根据参数按开始id,和结束id进行爬取,后面需要拆分时,再从最后获取到的id数据开始。当拆分得多了就会显得很繁琐了,不好管理。于是开始酝酿分布式方案: 从管理中心请求任务(id区间),然后根据id区间爬取; 单机上报自己的任务情况,管理中心根据各单机执行情况派发管理;控制好爬取速度,防止被屏蔽。 然而,时间和精力终究有限,这次就先玩简单的。 从API接口和数据接口,可以看到分答的接口还是相当规范的。

    数据存储

    如果直接存在文本文件上,后面数据分析用unix下awk等工具处理起来略麻烦,决定直接存储在sqlite数据库上。最初的在尝试了从解析到Go的数据,需要创建对应表,写入数据时,需要写入数据时各种繁琐。如下
    `
    stmt, err := db.Prepare("INSERT INTO account(AnswersCount, Avatar, FollowersCount, ID, IsFollowed, NickName, Price, Title) VALUES(?, ?, ?,?,?,?,?,?)")
    ` 看到需要搞这么的成员数据,这么多的"?"。后面还有更庞大的结构体在等着我时,我觉得 小试分答数据挖掘

这个时候,是该请出ORM来了,看了网上的介绍,ORM有 xorm 和 gorm ,分别看了xorm和gorm的文档。发现我还是喜欢有quickstart的文档,千言万语,不值一个demo简单明了。于是我选择了gorm先尝试一把,解决眼前问题再说,其他orm来日再来把玩,搞技术也要雨露均沾呀 小试分答数据挖掘

`
func (a Account) Save(dbName string) error {
db, err := gorm.Open("sqlite3", dbName)
if err != nil {
return err
}
defer db.Close()
db.AutoMigrate(&Account{})
db.Create(a)
return nil
}

` AutoMigrate封装了创建表格的细节。Create封装了插入表的细节。妥妥的

结果分析

对已经存放在数据库里面的数据进行有目的的统计计算。以“ 有哪些问题是可以赚到钱的”为例,从question_dbs表和accounts表取出数据

`
SELECT b.nickname, content, offer/100, listenings_count,  (profit - offer/100) AS earn FROM (SELECT respondent_id, id, content, offer,listenings_count, listenings_count*0.45 as profit FROM question_dbs ORDER BY profit DESC LIMIT 10) a LEFT OUTER JOIN (select id, Nickname, price from accounts) b ON a.respondent_id = b.id;
输出结果
``

王思聪|你如何分辨女票爱你的人还是爱你的钱?|4999|26887|7100.15 王思聪|我和你一样是网红,一样学哲学,我在分答回答最多的是你啪啪喜欢什么姿势,同样的问题我也问一下你|3000|23482|7566.9 王思聪|请问作为亚洲首富的儿子,您的人生还有什么买不起的?|3000|23294|7482.3 王思聪|作为一个普通人,特别想知道,校长平均在每个女朋友身上花费多少?|3000|20567|6255.15 王思聪|听说你是不婚主义,要是交往的女孩子意外怀孕怎么办?|3000|18932|5519.4 王思聪|你是如何处理和前女友的关系的,分手之后还是朋友吗?有没有分手后依然还爱的情况,如果有,你是怎么做的?|4999|18172|3178.4 王思聪|我替几千万适龄女性问吧:请问你择偶条件是什么?|3000|15219|3848.55 王思聪|校长,身边的朋友会找你借钱吧,如果不想借,您怎么推辞呢?如果借了,对方总拖着不还,您怎么办?|3000|13142|2913.9 王思聪|我是命理测算师,测算过你的命盘,但没有时辰颇多偏差。很想知道你和你家人是否算过命,对算命有什么看法?|4999|13111|900.95 章子怡|子怡好!每个行业都有潜规则。您觉得这些年演艺界最盛行的潜规则是什么?您遭遇过的最尴尬的潜规则是什么?|2929|11391|2196.95 ``` 结论:问题是否让人有偷听的意愿很关键,更关键地是答主的影响力。

数据展示

分析出来的数据如果用表格,然后用图来表示,整个过程显得很繁琐,例如,月回答问题量,导出csv,再用excel打开,然后出图。如果数据有更新,又需要这个过程。 后面可以考虑,展示和数据结合在一起,数据按模板输出,数据更新了,刷新页面,重读数据即可。 想法:数据可交换性,鼠标放在点,有数据显示,后续再玩

小结

  1. 账号功能,会发现越来越多应用的账号体系依附在微信上,一个社交账号依附功能(如支付,分享)建设越完善,将会被广泛推广使用。第三方需要的不仅仅是用户快速登录引流,账号之外的能力也是相当重要的。
  2. 每尝试做一件事情,有种特别的感觉,越是深入越发现自己懂得太少,需要提高的地方太多。在某些领域掌握越是肤浅,卡住的时间越长。所以要多去经历,丰富自己的见识
原文  https://mua.io/blog/post/ochapman/%E5%B0%8F%E8%AF%95%E6%95%B0%E6%8D%AE%E6%8C%96%E6%8E%98
正文到此结束
Loading...