How It Works
Toggle navigation
How It Works
Home
About Me
Archives
Tags
小试分答数据挖掘
2016-07-30 10:22:17
1156
0
0
ochapman
#背景 选了付费问答类题目,在体验分答的过程中,发现分答的模式,提问者的答案被偷听是需要1元,提问者可以分成0.5元。想到几个问题: 1. 有哪些问题是可以赚到钱的。 2. 哪些人是在分答上赚到钱的。 3. 哪些人才是分答上最受欢迎的。 4. 能否从分答的数据上分析用户是否活跃,有没有前景。 显然,这些数据是无法直接在网上直接找到的。要想得到答案,需要爬取分答的数据。 之前没有搞过类似爬取,想尝试爬取的乐趣 ![图片标题](https://mua.io/api/file/getImage?fileId=579a9e152fa1ec184a7e52e7) #打算怎么玩 通常的数据爬取都用python,也有很多成熟的爬取方案。但是,我想尝试一下Go。一来温习一下Go相关知识。二来学习Go上其他没有接触过的东西 #数据爬取 ##抓包 1. 电脑安装配置神器OWSAP ZAP,设置代理服务器,用来截取手机数据 2. 手机设置代理服务器地址 3. 手机打开分答应用,打开各个页面看看请求的链接和返回的数据格式 ##分析请求和数据 需要分析出哪些数据是从哪些链接请求来的,返回数据的格式。 1. 获取账户信息 ``` 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不同,分答接口是不需要票据就能直接拉取的。 2. 获取问题数据 ``` http://apis-fd.zaih.com/v1/accounts/587503258/answers?page=1&order_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(?, ?, ?,?,?,?,?,?)") ``` 看到需要搞这么的成员数据,这么多的"?"。后面还有更庞大的结构体在等着我时,我觉得 ![图片标题](https://mua.io/api/file/getImage?fileId=579cb6232fa1ec184a7e52ec) 这个时候,是该请出ORM来了,看了网上的介绍,ORM有[xorm](http://xorm.io/docs/)和[gorm](http://jinzhu.me/gorm/),分别看了xorm和gorm的文档。发现我还是喜欢有quickstart的文档,千言万语,不值一个demo简单明了。于是我选择了gorm先尝试一把,解决眼前问题再说,其他orm来日再来把玩,搞技术也要雨露均沾呀 ![图片标题](https://mua.io/api/file/getImage?fileId=579cb7112fa1ec184a7e52ee) ``` 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. 每尝试做一件事情,有种特别的感觉,越是深入越发现自己懂得太少,需要提高的地方太多。在某些领域掌握越是肤浅,卡住的时间越长。所以要多去经历,丰富自己的见识
Pre:
branch云输入的设计
Next:
进程只有一个
0
likes
1156
Weibo
Wechat
Tencent Weibo
QQ Zone
RenRen
Table of content