成長(zhǎng)會(huì)是一個(gè)面向成長(zhǎng)和持續(xù)行動(dòng)的學(xué)習(xí)行動(dòng)型社群。成長(zhǎng)會(huì)論壇是成長(zhǎng)會(huì)成員行動(dòng)記錄、交流的平臺(tái),一人一年就一貼,持續(xù)蓋樓,行動(dòng)記錄和交流,一年的記錄都在一個(gè)貼子里。成長(zhǎng)會(huì)論壇使用的是QQ群論壇??赡芤?yàn)椴皇球v訊核心產(chǎn)品的關(guān)系,這個(gè)論壇不那么好用,還經(jīng)常“抽風(fēng)”。
成長(zhǎng)會(huì)論壇沉淀了大量用戶(hù)信息(現(xiàn)在社群人數(shù)超過(guò)1000),個(gè)人成長(zhǎng)計(jì)劃和行動(dòng)記錄,以及成員之間的交流討論。
成長(zhǎng)會(huì)論壇有這么多數(shù)據(jù),自然成了我學(xué)習(xí)Python爬蟲(chóng)的試驗(yàn)田。學(xué)了幾天后,我用Python寫(xiě)了以下東西:
- Python爬蟲(chóng)抓取個(gè)人信息,行業(yè)(職業(yè))、特長(zhǎng)愛(ài)好,3個(gè)月內(nèi)的目標(biāo),進(jìn)行數(shù)據(jù)分析。
- 新消息提醒工具。如你關(guān)注的成員發(fā)表了貼子,可以在微信上收到提醒?;蛘咂渌嗽谀愕奶酉铝粞曰蚧貜?fù)了你,都可以收到微信的通知消息。
- 自動(dòng)回貼機(jī)器人??梢栽诔绦蛑邪l(fā)貼,或在其他人成長(zhǎng)貼下留言。
一、登錄驗(yàn)證問(wèn)題
在抓取成長(zhǎng)會(huì)論壇數(shù)據(jù)之前,測(cè)試過(guò)簡(jiǎn)單爬蟲(chóng)代碼。不涉及登錄的數(shù)據(jù)抓到,就是拿到網(wǎng)頁(yè)源代碼,然后解析網(wǎng)頁(yè)拿到數(shù)據(jù),用正則或BeautifulSoup或XPath,10多行代碼就能抓取到想要的數(shù)據(jù),Python真是簡(jiǎn)單粗暴,非常好用。
如果有登錄url,表單對(duì)應(yīng)字段名,做起來(lái)也比較簡(jiǎn)單。所以群論壇登錄驗(yàn)證,首先想到是在源代碼里查查找表單提交的url,表單的屬性字段。通過(guò)仔細(xì)查找源碼,表單屬性字段也找到了,但表單提交采用的是js,跳轉(zhuǎn)了幾次,實(shí)在是找不到登錄提交的url。無(wú)法登錄,論壇中的數(shù)據(jù)一個(gè)也拿不到。
第二個(gè)想到的辦法是API接口,感覺(jué)騰訊應(yīng)該提供了像第三方登錄一樣給群論壇使用,到騰訊開(kāi)放平臺(tái)上去找,還是沒(méi)有找到線(xiàn)索,想想也是,QQ群論壇就不是第三方產(chǎn)品。
我以為還是要回到j(luò)s上來(lái)找,后來(lái)我看到大榜在看js的書(shū),還看得比較深。我問(wèn)他能不能幫我在js文件中找找。他一聽(tīng),就說(shuō)不要,用Fiddler抓包就可以做,提交和返回的數(shù)據(jù)都可以拿到,加密數(shù)據(jù)也可以。他說(shuō)做過(guò)Java爬蟲(chóng),就給我演示了一下。
在Fiddler中果然看到論壇是經(jīng)過(guò)幾次跳轉(zhuǎn)重定向的,下圖就是顯示的登陸url,headers所傳遞的參數(shù)(用戶(hù)名和密碼)。

之前我只是看過(guò)簡(jiǎn)單的Python語(yǔ)法和網(wǎng)上的一段爬取貼吧圖片的代碼,在了解了urllib2, requests傳遞cookie實(shí)現(xiàn)登陸后,我發(fā)現(xiàn),之前的方法對(duì)于登陸QQ群論壇來(lái)說(shuō)就是個(gè)誤區(qū)。果斷把Fiddler中的這段字符串拷過(guò)來(lái),一試就抓取到論壇帖子的列表頁(yè),登陸成功!
我一邊感嘆Fiddler的好用,一邊想網(wǎng)絡(luò)的種種不安全。在很多地方不開(kāi)啟兩步驗(yàn)證的話(huà),用戶(hù)名和密碼就形同虛設(shè)。
二、成長(zhǎng)帖子數(shù)據(jù)分析
實(shí)現(xiàn)了登錄驗(yàn)證之后,就開(kāi)始了我的數(shù)據(jù)抓取和分析。第一步我關(guān)心的是成員的職業(yè)(行業(yè))、年齡,興趣愛(ài)好,3個(gè)月內(nèi)的行動(dòng)和改變計(jì)劃,以及在成長(zhǎng)會(huì)論壇打卡記錄的情況。
為了方便分析,以上所有的數(shù)據(jù)爬取下來(lái),寫(xiě)入一個(gè)Excel文件。后面也很方便快速進(jìn)行圖形化數(shù)據(jù)的展現(xiàn)。
QQ群論壇功能還是很簡(jiǎn)單,看到首頁(yè)上沒(méi)有瀏覽量和發(fā)貼的統(tǒng)計(jì)排名,我又增加了一個(gè)爬蟲(chóng),在每個(gè)人的帖子里,把閱讀量和回復(fù)數(shù)(個(gè)人打卡+回訪(fǎng)留言)抓取下來(lái),得到成長(zhǎng)帖人氣TOP10(閱讀量前10名),由于回復(fù)數(shù)是個(gè)人打卡記錄加上互動(dòng)留言,另外寫(xiě)了一個(gè)函數(shù),抓取每條記錄時(shí)判斷是不是貼主發(fā)出來(lái)的,并進(jìn)行統(tǒng)計(jì),得到成長(zhǎng)帖子記錄打卡TOP10。
這兩個(gè)數(shù)據(jù)統(tǒng)計(jì)我在QQ群進(jìn)行了分享,在TOP10的帖子下留言告訴他們Python爬取的數(shù)據(jù)統(tǒng)計(jì)結(jié)果。后來(lái)我又思考,這個(gè)工作Python也可以自動(dòng)完成,于是做了下面《第六、自動(dòng)發(fā)帖功能》

三、中文分詞問(wèn)題
由于每個(gè)人的成長(zhǎng)貼,在是word里寫(xiě)好后粘貼過(guò)來(lái)的。每一次的數(shù)據(jù)抓取用了BeautifulSoup抓取到第一帖后,就用了字符串匹配的方式,來(lái)獲取相應(yīng)的信息,如每個(gè)人行業(yè)(職業(yè))。
感覺(jué)到分詞的重要,是因?yàn)閹统砷L(zhǎng)會(huì)的小朋友抓取了兩次數(shù)據(jù),如想找到考研,考上外、廣外,MTI的同學(xué)有哪些,聯(lián)系方式和考研經(jīng)過(guò)。就需要找出這些詞關(guān)聯(lián)的特征詞,用戶(hù)的記錄習(xí)慣。而我沒(méi)有這方面的經(jīng)驗(yàn),也沒(méi)有學(xué)習(xí)過(guò)。所以只能根據(jù)我的理解,做一些簡(jiǎn)單的匹配,再經(jīng)過(guò)Excel分類(lèi)匯總,找出精準(zhǔn)數(shù)據(jù)。其實(shí)這個(gè)詞還好一點(diǎn),后面也應(yīng)一個(gè)同學(xué)要求找有視頻編輯處理,平面設(shè)計(jì),圖片處理能力的同學(xué)。這時(shí)我在Excel中直接二次查詢(xún),快速找到后再進(jìn)行校驗(yàn),發(fā)現(xiàn)這次搜索的準(zhǔn)確率是80%。
但要找到有學(xué)習(xí)PPT計(jì)劃或在學(xué)習(xí)PPT的同學(xué),這個(gè)詞我就拿不準(zhǔn),因?yàn)楹芏嗳嗽谟涗浿杏蠵PT這個(gè)詞,可能只是工作中寫(xiě)PPT。搜哪些詞,特征詞是什么就很關(guān)鍵。
四、分頁(yè)數(shù)據(jù)抓取
要爬取用戶(hù)所有的帖子,就需要分頁(yè)爬完用戶(hù)所有的分頁(yè)數(shù)據(jù),一開(kāi)始我的想法是一個(gè)循環(huán),從第一頁(yè)往后,直到抓到的頁(yè)面中沒(méi)有用戶(hù)信息為止。但是看到第一頁(yè)上有頁(yè)數(shù)的信息,改變了一下做法,爬取第一頁(yè)信息時(shí),順便把用戶(hù)總頁(yè)數(shù)拿到。應(yīng)該還可能優(yōu)化成遞歸調(diào)用。
五、Ajax數(shù)據(jù)抓取
論壇的消息提醒,是Ajax數(shù)據(jù),從爬取的網(wǎng)頁(yè)源代碼里看不到新消息。如果拿到新消息,再結(jié)合發(fā)送郵件(《七、發(fā)送郵件問(wèn)題》)就可以做一個(gè)論壇消息提醒助手,在收到回復(fù),或留言時(shí),在微信中就能收到一個(gè)推送消息。
同樣是通過(guò)Fiddler找到請(qǐng)求新消息的URL,順利拿到返回的json數(shù)據(jù),解析到消息來(lái)源和內(nèi)容。QQ群論壇如果收到新消息,是從title上看到提示的。如果做一個(gè)簡(jiǎn)單的消息提醒工具就非常簡(jiǎn)單。

六、自動(dòng)發(fā)貼功能
自動(dòng)回復(fù)機(jī)器人,論貼發(fā)貼機(jī)器人,一直是我想實(shí)現(xiàn)的功能。不只是能發(fā)廣(la)告(ji),還能做出一些好玩的東西,如對(duì)于成長(zhǎng)貼記錄沒(méi)有更新的同學(xué),可以發(fā)留言提醒;跟蹤成長(zhǎng)計(jì)劃的實(shí)施情況,給一些有趣的提醒;定期發(fā)布成長(zhǎng)貼的人氣,更新情況。如果結(jié)合郵件發(fā)送,用戶(hù)會(huì)收到更及時(shí)的消息。如果用戶(hù)綁定了微信,就會(huì)收到微信的推送。
在實(shí)現(xiàn)自動(dòng)發(fā)貼功能時(shí),遇到的最大問(wèn)題,也是登錄!Fiddler抓取到了發(fā)貼提交的地址,使用了cookie,還是發(fā)不了,返回的json字符串是“登錄后再操作”。還想到這一的方法,先訪(fǎng)問(wèn)一下論壇頁(yè)面,然后繼續(xù)使用這個(gè)request再提交表單,然并卵。
再次回到思路上,發(fā)現(xiàn)提交表單時(shí),是在headers中提交cookie的,在Fiddler中抓取了headers,對(duì)的,就這么長(zhǎng)長(zhǎng)的一段,構(gòu)造了一個(gè)header。發(fā)貼成功了!接下來(lái),利用這個(gè)修改一個(gè)參數(shù),在別人的帖子下留言也可以。

接下來(lái)作中文亂碼的測(cè)試,通過(guò)。但是遇到一個(gè)怪異的問(wèn)題,有時(shí)候能發(fā)送,有時(shí)候服務(wù)器請(qǐng)求出現(xiàn)timeout, 猜測(cè)是請(qǐng)求headers里的某個(gè)關(guān)鍵數(shù)據(jù)沒(méi)有掌握,經(jīng)過(guò)多次發(fā)貼測(cè)試,把Content-Length基本弄清楚,Content-Length如果存在并且有效的話(huà),則必須和消息內(nèi)容的傳輸長(zhǎng)度完全一致(如果過(guò)短則會(huì)截?cái)?,過(guò)長(zhǎng)則會(huì)導(dǎo)致超時(shí)。)。
七、發(fā)送郵件功能
這個(gè)功能關(guān)乎到微信上能不能收到推送消息。基本沒(méi)有什么難度,10分鐘搞定!
#coding=utf-8
import smtplib
from email.mime.text import MIMEText
import os
import sys
import exceptions
reload(sys)
sys.setdefaultencoding('utf-8')
#發(fā)送郵件的列表
mailto_list=['1379977300@qq.com','522502197@qq.com']
mail_host="smtp.126.com" #設(shè)置服務(wù)器
mail_user="ppy2790" #用戶(hù)名
mail_pass="1234567" #口令
mail_postfix="126.com" #發(fā)件箱的后綴
def send_mail(to_list,sub,content):
me="成長(zhǎng)貼小助手"+"<"+mail_user+"@"+mail_postfix+">"
msg = MIMEText(content,_subtype='plain',_charset='utf-8')
msg['Subject'] = sub
msg['From'] = me
msg['To'] = ";".join(to_list)
try:
server = smtplib.SMTP()
server.connect(mail_host)
server.login(mail_user,mail_pass)
server.sendmail(me, to_list, msg.as_string())
server.close()
return True
except Exception, e:
print str(e)
return False
結(jié)語(yǔ)
在成長(zhǎng)會(huì)論壇上爬取數(shù)據(jù),是從一段下載圖片的Demo開(kāi)始,拿過(guò)來(lái)就修改、測(cè)試,再進(jìn)行分析,快速編寫(xiě)代碼,再找解決方案,目標(biāo)驅(qū)動(dòng)學(xué)習(xí),是我學(xué)習(xí)Python的經(jīng)驗(yàn)。
附:論壇爬取的數(shù)據(jù)分析在:《成長(zhǎng)會(huì)不完全大數(shù)據(jù)-Python爬蟲(chóng)案例》