左手用R右手Pyhon系列——趣直播課程抓取實戰
本文將以趣直播課程信息數據抓取為例,展示如何使用RCurl進行結合瀏覽器抓包操作進行簡易數據抓取。
library("RCurl")n library("XML")nlibrary("rlist")nlibrary("dplyr")nlibrary("jsonlite")n
按照常規的操作步驟,數據抓取首先應該通過瀏覽器後台確認該目標網頁所使用的框架和請求類型,確認網站是否提供了api訪問介面,如果可以通過API直接訪問數據包,那麼抓取工作將會變得極其簡單,倘若沒有,則才考慮直接請求整個網頁並使用xpath、css、正則或者具備路徑查詢功能的輔助包進行數據提取。
1、查看趣直播網頁後台:
url<-"http://m.quzhiboapp.com/#!/lives" n
打開該網頁之後,按F12鍵,進入Chrome瀏覽器開發者後台,定位到xhr欄目,在該欄目的Name請求名稱列表裡尋找帶有參數的項目(可以直接忽略所有.js結尾的請求文件)。
我一眼就看到了一個以listOrderByPlanTs?limit=30命名的請求項目,該項目中含有list關鍵詞、limit關鍵詞,這些關鍵詞很可能是api用於限定信息展示條目的限制參數。
下一步確認這一條是否是我們需要的請求,選中這一條請求並滑鼠單擊,首先定位到右側Preview欄目並點開,當你看到排的整整齊齊的josn數據包到的時候,毫無疑問這就是我們需要找的寶藏了。
接下來幹什麼呢,當時是查看該請求的請求類型,參數提交情況,以及請求參數、返回內容格式了。
從General欄目可以看到該請求是一個GET請求,請求地址是:
http://m.quzhiboapp.com/api/lives/listOrderByPlanTs從Request Headers中可以看到參數提交時優先接受json格式,但同時也可以接受text/plain(純文本)。
User-Agent是一個重要的請求報頭參數,告知目標伺服器該請求的客戶端設備類型。在該欄目里還有兩個不常見的參數——X-Requested-With、X-Session,先不用管如果之後影響請求結果再添加。從Response Headers中可以得知伺服器 返回的數據類型是application/json格式,utf-8編碼。這決定著我們使用什麼工具來解析返回內容。
最後一個Query String Parameters 項目是GET請求需要提交的參數,本例只有一個limit參數,用於限定單次請求返回的信息條目數,GET請求允許請求參數直接構造在請求URL裡面。
2、構造GET請求:
url<-"http://m.quzhiboapp.com/api/lives/listOrderByPlanTs"nheader=c(n "Accept"="application/json, text/plain, */*",n "User-Agent"="Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.79 Safari/537.36"n )nParam<-list("limit"=30)nchandle<-getCurlHandle(debugfunction=debugGatherer()$update,followlocation=TRUE,cookiefile="",verbose = TRUE)ncontent<-getForm(url,httpheader=header,.params=Param,.encoding="utf-8",curl=chandle)n
查看狀態碼:
getCurlInfo(chandle)$response.coden#[1] 200n
OK!!!
列印一下content的內容:
print(content) n
完美,接下來解析內容,之前說過返回內容是json,那麼這裡就需要使用具備json處理能力的包進行處理。
mycontent <- content %>% fromJSON() %>% `[[`(2)n
非常規整的數據框,都不用怎麼做清洗和缺失值替補,實在是太完美了。
3、封裝抓取函數:
接下來肯定會有小夥伴要問了,難倒只能抓這麼點數據嗎,這種情況下應該如何獲取所有課程信息,怎麼從網頁後台進行檢索,確定有多少課程量。
這個問題我也有疑問呢,帶著這個疑問 ,我們再次造訪Chrome後台。
遺憾呢,真的是看不到總課程量,只能顯示30條,怎麼辦,試一試暴力方法!!!
直接把我們請求的url地址po到瀏覽器然後訪問。
我們直接進入了這個json課程數據包,因為limit設置的30,所以信息自然就是30條嘍,不信你用Ctrl+F查找一下關鍵字,輸入一個課程id:liveId,輸入框直接顯示了該頁面一共有多少個liveId數目,沒錯就是30個。
然後我有個大膽的想法,我們可以篡改url啊我擦~
改成100果然就顯示100了哈哈哈,那就索性再大膽一些,改成1000如何???
你會發現改成1000的時候,頁面的liveId只增加了12個,是不說一共只有112門課程呢,那我們就多試幾次嘍,分別改成200、300、500試一試。
可以看到limit參數自200以後始終都沒有增加過,一直停留在112,目測一共就這麼多了。
當顯示出了112門課程的時候,你可以直接Ctrl+S保存該網頁為.json文件,直接解析,當然我們還是要做的優雅一點,直接寫在請求語句中,然後友好的返回規整的數據框。
url<-"http://m.quzhiboapp.com/api/lives/listOrderByPlanTs"nheader=c(n"Accept"="application/json, text/plain, */*",n"User-Agent"="Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.79 Safari/537.36"n)nParam<-list("limit"=150)nchandle<-getCurlHandle(debugfunction=debugGatherer()$update,followlocation=TRUE,cookiefile="",verbose = TRUE)ncontent<-getForm(url,httpheader=header,.params=Param,.encoding="utf-8",curl=chandle)ngetCurlInfo(chandle)$response.coden[1] 200nmycontent <- content %>% fromJSON() %>% `[[`(2);nrow(mycontent)n[1] 112n
啦啦啦,多麼完美的結局呀,你看數據框都不用處理缺失值,簡直是太神奇了。接下來我們僅需要剔除那些我們不想要的列就可以了。
head(mycontent)nnames(mycontent)n [1] "liveId" "subject" "attendanceCount" "needPay" "coverUrl" "previewUrl" n [7] "amount" "maxPeople" "conversationId" "status" "planTs" "beginTs"n[13] "endTs" "ownerId" "shareIcon" "created" "updated" "attendanceId" n[19] "shareId" "owner" "topic" "canJoin" "realAmount" ninvalid<-c("previewUrl","shareIcon","attendanceCount","shareId","canJoin")nmyresult<-setdiff(names(mycontent),invalid) %>% mycontent[.]nhead(myresult);dim(myresult);str(myresult) n
OK,思路整理完了,現在開始應該封裝一個像模像樣點兒的自動化小爬蟲程序了!
myforce<-function(url){n header=c( n "Accept"="application/json, text/plain, */*",n "User-Agent"="Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.79 Safari/537.36"n )n Param<-list("limit"=150)n chandle<-getCurlHandle(debugfunction=debugGatherer()$update,followlocation=TRUE,cookiefile="",verbose = TRUE)n mycontent<-getForm(url,httpheader=header,.params=Param,.encoding="utf-8",curl=chandle) %>% fromJSON() %>% `[[`(2) n print(getCurlInfo(chandle)$response.code)n invalid<-c("previewUrl","shareIcon","attendanceCount","shareId","canJoin")n myresult<-invalid %>% setdiff(names(mycontent),.) %>% mycontent[.]n print("everything is OK")n}nmydata<-myforce("http://m.quzhiboapp.com/api/lives/listOrderByPlanTs")n[1] 200n[1] "everything is OK"n
看到了令人賞心悅目的200,和everything is OK,今天午飯都有食慾啦~~~
來勁了順便給你個Python版吧~
import jsonnimport pandas as pdnfrom urllib.parse import urlencode nfrom urllib.request import urlopen,Requestndef getdata(url):n #postdatan values = {limit:150}n link=url+?+ urlencode(values)n #headersn header = {n User-Agent:Mozilla/5.0 (Windows NT 6.3; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Safari/537.36,n Accept:application/json, text/plain, */*n }n response = urlopen(Request(link,headers=header))n #查看請求狀態碼n print(response.getcode())n #使用json方法解析返回的josn數據包n myresult=json.loads(response.read())n print(len(myresult["result"]))n mydata=pd.DataFrame(myresult[result])n invalid=["previewUrl","shareIcon","attendanceCount","shareId","canJoin"]n full=list(set(list(mydata.columns)).difference(set(invalid)))n print("everything is OK")n return(mydata[full])nn#提供URL,運行抓取程序獲取數據:nurl="http://m.quzhiboapp.com/api/lives/listOrderByPlanTs"nmydata=getdata(url)n200n112neverything is OKnmydata.head(10)nmydata.info() n
由於mydata裡面的owner和topic欄位仍然是嵌套字典,沒有鋪平,接下來我們使用列表表達式鋪平嵌套字典。
mydata[avatarUrl]=[avatarUrl[avatarUrl] for avatarUrl in mydata.owner]nmydata[userId]=[avatarUrl[userId] for avatarUrl in mydata.owner]nmydata[username]=[avatarUrl[username] for avatarUrl in mydata.owner]nmydata[name]=[avatarUrl[name] for avatarUrl in mydata.topic]nmydata[topicId]=[avatarUrl[topicId] for avatarUrl in mydata.topic]n
刪除那兩列嵌套字典:
del mydata["owner"]ndel mydata["topic"]nmydata.shapen(112, 21)nmydata.head() n
最後就可以分析或者入庫啦!!!
在線課程請點擊文末原文鏈接:
Hellobi Live | 9月12日 R語言可視化在商務場景中的應用
往期案例數據請移步本人GitHub:https://github.com/ljtyduyu/DataWarehouse/tree/master/File推薦閱讀:
※當大家都在討論金剛狼3的時候,他們到底在說些什麼~
※爬蟲之常用的chrome技巧?
※拿諾貝爾獎可以長壽?——從爬蟲到簡單數據分析
※QQ空間動態爬蟲