R語言爬蟲系列6|動態數據抓取範例

2021-02-23 機器學習實驗室

通過前面幾期的推送,小編基本上已經將R語言爬蟲所需要的基本知識介紹完了。R雖然是以一門統計分析工具出現在大多數人印象中的,但其畢竟本質上是一門程式語言,對於爬蟲的支持雖不如Python那樣多快好省,但悉心研究一下總能做出一些讓你驚喜的效果。

 

大約很早之前,小編就寫過關於R語言爬蟲新貴rvest的抓取介紹,之前說rvest+SelectGadgetor是結構化網頁抓取的實戰利器,大家的溢美之詞不斷。詳情可見推文:

R語言爬蟲利器:rvest包+SelectorGadget抓取鏈家杭州二手房數據

 

但網絡爬蟲這個江湖太險惡,單靠一招rvest行走江湖必然兇多吉少,一不小心碰到什麼AJAX和動態網頁憑僅掌握rvest的各位必定束手無策。本文小編就簡單介紹下在用R語言進行實際的網絡數據抓取時如何將動態數據給弄到手。

 

所謂動態網頁和異步加載,在之前的系列4的時候小編已通過AJAX介紹過了,簡單而言就是我明明在網頁中看到了這個數據,但到後臺HTML中卻找不到了,這通常就是XHR在作祟。這時候我們就不要看原始的HTML數據了,需要進行二次請求,通過web開發者工具找到真實請求的url。下面小編就以兩個網頁為例,分別通過GET和POST請求拿到動態網頁數據,全過程主要使用httr包來實現,httr包可謂是RCurl包的精簡版,說其短小精悍也不為過。httr包與RCurl包在主要函數的區別如下所示:

GET請求抓取微信好友列表數據

很早之前圈子裡就看到過用Python抓取自己微信好友數據的案例分享,今天便以微信網頁版為例,探一探其網頁結構。首先登錄個人微信網頁版,右鍵打開web開發者工具,下來一大堆請求:

簡單找一下發現網頁中的微信好友列表信息並沒有呈現在HTML 中,大概可以斷定微信好友數據是通過動態加載來顯示的,所以直接定位到XHR中,經過幾番嘗試,結合右側的preview,我們會發現大量整齊劃一的數據,所以二次請求的url真的就是它了:

 

找到真正的url之後,接下來就是獲取請求信息了,切換到Headers版塊,Header版塊下的4個子信息我們都需要關注,它們是我們構造爬蟲請求頭的關鍵。

 

從Header中我們可以看到該信息是通過GET方法請求得到的,General信息下的Request URL,Request Method, Status Code; Response Headers信息下的Connection, Content-Type; Request Headers信息下的Accept, Cookie, Referer, User-Agent以及最後的Query String Parameters都是我們需要重點關注的。

找到相應的信息之後,我們便可以直接利用httr包在R中構建爬蟲請求:

#傳入微信cookie信息
Cookie <- 「我的微信cookie」
#構造請求頭
headers <- c('Accept'='application/json',
            'Content-Type'='text/plain',          
            'User-Agent'='Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.  36 (KHTML, like Gecko) Chrome/49.0.2623.221 Safari/537.36 SE 2.X Met aSr 1.0',          
            'Referer'='https://wx.qq.com/',
            'Connection'='keep-alive',
            'cookie'=Cookie
)

二次請求實際的url:

#實際請求的url
url<-"https://wx.qq.com/cgi-bin/mmwebwx-bin/webwxgetcontact?r=1507597918348&seq=0&skey=@crypt_ee7cd3e3_70091604da65a07600cfdca47b81cfaf"

GET方法單次執行請求:

#執行請求
louwill <- GET(url,add_headers(.headers =headers))

響應結果如下:

-> GET /cgi-bin/mmwebwx-bin/webwxgetcontact?r=1507597918348&seq=0&skey=@crypt_ee7cd3e3_70091604da65a07600cfdca47b81cfaf HTTP/1.1
-> Host: wx.qq.com
-> Accept-Encoding: gzip, deflate
-> Accept: application/json
-> Content-Type: text/plain
-> User-Agent: Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/49.0.2623.221 Safari/537.36 SE 2.X MetaSr 1.0
-> Referer: https://wx.qq.com/
-> Connection: keep-alive
-> cookie: 我的微信cookie
->
<- HTTP/1.1 200 OK
<- Connection: keep-alive
<- Content-Type: text/plain
<- Content-Encoding: gzip
<- Content-Length: 90977
<-

響應狀態碼為200,okay。

從響應中提取原始字符內容:

content(louwill)
[1] "{\n\"BaseResponse\": {\n\"Ret\": 0,\n\"ErrMsg\": \"\"\n}\n,\n\"MemberCount\": 658,\n\"MemberList\": [{\n\"Uin\": 0,\n\"UserName\": \"weixin\",\n\"NickName\": \"微信團隊\",\n\"HeadImgUrl\": \"/cgi-bin/mmwebwx-bin/webwxgeticon?seq=570002&username=weixin&skey=@crypt_ee7cd3e3_70091604da65a07600cfdca47b81cfaf\",\n\"ContactFlag\": 1,\n\"MemberCount\": 0,\n\"MemberList\": [],\n\"RemarkName\": \"\",\n\"HideInputBarFlag\": 0,\n\"Sex\": 0,\n\"Signature\": \"微信團隊官方帳號\",\n\"VerifyFlag\": 56,\n\"OwnerUin\": 0,\n\"PYInitial\": \"WXTD\",\n\"PYQuanPin\": \"weixintuandui\",\n\"RemarkPYInitial\": \"\",\n\"RemarkPYQuanPin\": \"\",\n\"StarFriend\": 0,\n\"AppAccountFlag\": 0,\n\"Statues\": 0,\n\"AttrStatus\": 4,\n\"Province\": \"\",\n\"City\": \"\",\n\"Alias\": \"\",\n\"SnsFlag\": 0,\n\"UniFriend\": 0,\n\"DisplayName\": \"\",\n\"ChatRoomId\": 0,\n\"KeyWord\": \"wei\",\n\"EncryChatRoomId\": \"\",\n\"IsOwner\": 0\n}\n,{\n\"Uin\": 0,\n\"UserName\": \"@34c5cc09db0a616522f7ccc7309b1d29\",\n\"NickName\": \"微信支付... <truncated>

從結果中可以看出,微信好友列表的信息就被抓取下來了,數據信息非常雜亂,需要進一步清洗整理,小編這裡重在展示GET請求獲取動態網頁數據(主要是懶)就不往下整理啦。

 

 

POST請求抓取網易雲課堂數據

雖說動態網站數據請求也有GET方法的,但小編發現POST方法才是動態網頁的主要的請求方式。受杜老師小魔方文章啟發,小編也試一下這個網頁上的效果。登錄網易雲課堂帳號,右鍵開發者工具,直接定位到XHR,查找課程數據屬於哪個url。通過嘗試和preview,可以發現課程信息都被封裝在一個studycourse.json的文件中:

 

跟GET請求方法一樣,切換到Header版塊後繼續關注General等四個子信息,但POST請求下我們需要注意的一點是:POST請求下沒有像GET請求一樣的Query String Parameters,而是由Request Payload來構造請求頭表單參數,這一點和GET方法大不相同。總而言之,在動態網頁的HTTP請求中,如果是GET請求,請求頭表單參數以name=value&name1=value1的形式直接附在url後面,如果是POST請求,請求頭表單參數以相同的形式放在構造的表單體中,所以對於網易雲課堂的數據請求在R中構造如下:

#構造請求頭
#這裡小編沒有登錄帳號,cookie就不要了
headers <- c('Accept'='application/json',
            'Content-Type'='application/json',          
            'User-Agent'='ozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/49.0.2623.221 Safari/537.36 SE 2.X MetaSr 1.0',          
            'edu-script-token'= '37aa682d1473455c8a77e6a4476e8f9e',
            'Referer'='http://study.163.com/courses',
            'Connection'='keep-alive'
)
#POST請求需要構造請求頭表單參數
payload<-list(
 'pageIndex'=1,
 'pageSize'=50,
 'relativeOffset'=0,
 'frontCategoryId'=-1
)

 二次請求實際的url:

url <- "http://study.163.com/p/search/studycourse.json"

POST方法單次執行請求:

louwill2<-POST(url,add_headers(.headers =headers),body =payload, encode="json")

結果如下:

-> POST /p/search/studycourse.json HTTP/1.1
-> Host: study.163.com
-> Accept-Encoding: gzip, deflate
-> Cookie: EDUWEBDEVICE=5d0eadccd2314c4d8bc6e758b8b23d4e; NTESSTUDYSI=d3d36984547a43d6924334ee6a184a08
-> Accept: application/json
-> Content-Type: application/json
-> User-Agent: ozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/49.0.2623.221 Safari/537.36 SE 2.X MetaSr 1.0
-> edu-script-token: 83de95a25f5d45eb84bfeff8ec334e15
-> Referer: http://study.163.com/courses
-> Connection: keep-alive
-> cookie: 網易雲課堂cookie
-> Content-Length: 69
->
>> {"pageIndex":1,"pageSize":50,"relativeOffset":0,"frontCategoryId":-1}

<- HTTP/1.1 200 OK
<- Server: nginx
<- Date: Tue, 10 Oct 2017 08:29:51 GMT
<- Content-Type: application/json;charset=UTF-8
<- Transfer-Encoding: chunked
<- Connection: keep-alive
<- Vary: Accept-Encoding
<- Server-Host: hzayq-study-platform7
<- Content-Encoding: gzip
<-
Response [http://study.163.com/p/search/studycourse.json]
 Date: 2017-10-10 08:29
 Status: 200
 Content-Type: application/json;charset=UTF-8
 Size: 71 kB

請求狀態碼200,也okay。

從響應中提取原始字符內容:

head(content(louwill2))
$result$list[[39]]
$result$list[[39]]$productId
[1] 1002971001
$result$list[[39]]$courseId
[1] 1002971001
$result$list[[39]]$productName
[1] "英語知識點解析及小學單詞帶讀"
$result$list[[39]]$productType
[1] 0
$result$list[[39]]$startTime
[1] -1
$result$list[[39]]$endTime
[1] 9.223372e+18
$result$list[[39]]$description
[1] "通過幾分鐘的微課片段,精講中小學的英語知識點,讓學生通過比較學習,把這些知識點編織成有系統的知識網。"
$result$list[[39]]$provider
[1] "中小學英語語法王"

跟前面一樣,後續的數據處理與清洗小編就懶得弄啦。POST方法與GET方法略有區別,就是需要構造請求頭表單參數。R語言針對動態網頁抓取,使用RCurl/httr包,認真分析網頁結構,一般都能搞定。

參考資料:

Automated Data Collection with R

R語言自動數據採集

R語言爬蟲實戰——網易雲課堂數據分析課程板塊數據爬取

往期精彩:

R語言爬蟲系列4|AJAX與動態網頁介紹

R語言爬蟲系列3|HTTP協議

R語言爬蟲系列2|XML&XPath表達式與R爬蟲應用

R語言爬蟲系列1|HTML基礎與R語言解析

如何寫出整潔規範的R代碼?是時候討論一下代碼規範性了

【機器學習】決策樹總結|ID3 C4.5/C5.0 CHAID CART與QUEST

R語言向量化運算:apply函數族用法心得

Python面向對象編程:數據封裝、繼承和多態

[譯]為什麼R語言是當今最值得學習的數據科學語言

一個數據科學狂熱者的學習歷程



相關焦點

  • R語言爬蟲手機app數據小筆記
    以前玩的爬蟲都是爬PC端網頁上的數據,比如以前的推文《網絡爬蟲+文本分析之解讀歷屆我們黨的全國代表大會報告》,《R語言網絡爬蟲+圖片分析之CNS
  • 跟我學R爬蟲|AJAX與動態網頁簡介
    因為知乎首頁是一個動態網站(DHTML),具體表現就是從首頁不斷下拉,網頁內容在不斷變化但url卻一直都是https://www.zhihu.com/,或者是點擊了某個地方內容也發生了變化但抬頭一看地址欄,url依然沒有變化。對這樣的網頁進行抓取哪能按照以前的簡單套路來?明顯是不可行的。
  • R語言爬蟲利器:rvest包+SelectorGadget抓取鏈家杭州二手房數據
    作者:魯偉一個數據科學踐行者的學習日記。數據挖掘與機器學習,R與Python,理論與實踐並行。個人公眾號:數據科學家養成記 (微信ID:louwill12)自打春節後從家裡回到學校以來就一直在搗鼓爬蟲,總琢磨著個抓些數據來玩玩,在文檔裡保存一些自己的datasets。
  • R語言爬蟲常用方法總結(以案例說明)
    Python傾向於做大型爬蟲,與R相比,語法相對複雜,因此Python爬蟲的學習曲線會相對陡峭。對於那些時間寶貴,又想從網上獲取數據的初學者而言,用R做爬蟲是最好的選擇,有三個原因:1、R語法相對直觀,規則更加靈活;2、對於數據量不大的用戶來數(小於百萬級),R也能夠非常自如地處理;3、先學習R爬蟲,等熟悉爬蟲的原理之後,在過渡到Python是很容易的。
  • 數據從業者必讀:抓取了一千億個網頁後我才明白,爬蟲一點都不簡單
    編者按:網際網路上有浩瀚的數據資源,要想抓取這些數據就離不開爬蟲。鑑於網上免費開源的爬蟲框架多如牛毛,很多人認為爬蟲定是非常簡單的事情。但是如果你要定期上規模地準確抓取各種大型網站的數據卻是一項艱巨的挑戰,其中包括網站的格式經常會變、架構必須能靈活伸縮應對規模變化同時要保持性能,與此同時還要挫敗網站反機器人的手段以及維護數據質量。
  • R語言爬蟲系列2|XML&XPath表達式與R爬蟲應用
    昨天跟微信上一不認識的同是搞數據技術的圈友聊天,我說最近在寫一個R語言爬蟲系列,想把Python爬蟲那一套用R實現看看,剛開始在講
  • 難道python才可以做數據抓取?今天就使用Java實現疫情數據抓取
    相信很多人像我一樣每天醒來就會看看疫情的數據,身為軟體工程專業的一員,也要充分發揮專業能力,為疫情做點什麼。設計思路使用爬蟲爬取網站中的數據並存入資料庫使用java做後端將資料庫的內容傳送到前端前端使用echarts框架對數據進行可視化技術棧開發語言Java開發工具Idea資料庫MySQL使用的第三方庫Jsoup:數據抓取gson:JSON轉換jQuery:ajax請求、DOM操作Echarts: 地圖可視化功能概述數據抓取和持久化項目抓取匯總數據及持久化抓取疫情地圖數據及持久化抓取動態播報數據及持久化疫情數據可視化項目疫情匯總數據可視化疫情地圖可視化省市詳情數據可視化動態播放可視化項目截圖
  • 網絡爬蟲違法?扯!繼續學習我的第一個爬蟲
    隨著資訊時代的迭代更新,人工智慧的興起,Python程式語言也隨之被人們廣泛學習,Python數據分析、Python web全棧、Python自動化運維等等都很受歡迎,其中還包括了Python爬蟲。但是很對人覺得Python爬蟲是違法的行為,也在懷疑自己到底要不要學爬蟲,之前有一篇文章特別火,就是《 只因寫了一段爬蟲,公司200多人被抓!》
  • 初學者如何用「python爬蟲」技術抓取網頁數據?
    在當今社會,網際網路上充斥著許多有用的數據。我們只需要耐心觀察並添加一些技術手段即可獲得大量有價值的數據。而這裡的「技術手段」就是指網絡爬蟲。 今天,小編將與您分享一個爬蟲的基本知識和入門教程:什麼是爬蟲?網絡爬蟲,也叫作網絡數據採集,是指通過編程從Web伺服器請求數據(HTML表單),然後解析HTML以提取所需的數據。
  • 2020重磅升級「Python數據科學入門與網絡爬蟲案例實戰研討會」
    Python作為一門面向對象的程式語言,簡潔的語法使得編寫十幾行代碼即可實現爬蟲功能,獲取海量網際網路數據。使用Python來編寫爬蟲實現簡單且效率高,同時爬取的數據可以使用Python強大的第三方數據處理庫來進行分析,最重要的是學習成本低,如此之好的東西怎能不學習呢?
  • R語言網絡爬蟲經驗
    希望與大家分享學習經驗,推廣並加深R語言在業界的應用。在爬蟲的時候經常爬到一個時候就自己斷了,問題是我們還看不出來是斷了還是沒有斷,因此需要往裡面加入進度條,當進度條卡住的時候,就可以停止自己的程序在斷點重新跑 1 library(tcltk)   2u <- 1:2000   3 4 5 6pb <- tkProgressBar("進度","
  • Web爬蟲:多線程、異步與動態代理初步
    3.5 快速啟動中途中斷重啟腳本,為了將已經獲取的和已經排除的目標id快速去除,可以一次性查詢出來用集合差獲取未完成的任務id,舉個慄子:pid_set  = set([r['pid'] for r in res]) if res else set()task_set = set([r for r in range(1, max_pid)])task_set = task_set
  • R語言編程入門進階(學會使用函數包)
    R語言編程入門(爬蟲函數包的使用)寫在前面的上期推文介紹了R語言編程入門,從了解R語言的5種數據結構和兩種控制結構開始,再到借上上篇推文的Readscount數據綜合利用R語言編程證明Readscount屬於負二項分布。現在再回顧一下R語言的五個數據結構:向量、矩陣、列表、數據框、因子,以及兩種控制結構,循環和判斷。
  • JS動態加載以及JavaScript void(0)的爬蟲解決方案
    # Intro對於使用JS動態加載, 或者將下一頁地址隱藏為 JavaScriptvoid(0)的網站, 如何爬取我們要的信息呢?本文以 Chrome瀏覽器為工具, 36Kr為示例網站, 使用 Json Handle 作為輔助信息解析工具, 演示如何抓取此類網站.# DetailStep 1.
  • 【R爬蟲-1】BBC Learning English
    在【R圖秀】中,我們已經學會如何從網上抓取數據並進行可視化分析。
  • 教你如何編寫第一個爬蟲
    隨著資訊時代的迭代更新,人工智慧的興起,Python程式語言也隨之被人們廣泛學習,Python數據分析、Python web全棧、Python自動化運維等等都很受歡迎,其中還包括了Python爬蟲。但是很對人覺得Python爬蟲是違法的行為,也在懷疑自己到底要不要學爬蟲,之前有一篇文章特別火,就是《 只因寫了一段爬蟲,公司200多人被抓!》
  • 爬蟲系列 | 6、詳解爬蟲中BeautifulSoup4的用法
    也就是說只有Python語言才可以通過這種方式去解析數據。BeautifulSoup 3 只支持Python2,所以已經被淘汰了。官網的介紹是這樣的Beautiful Soup 提供一些簡單的、python 式的函數用來處理導航、搜索、修改分析樹等功能。
  • 如何用R做靜態網頁的爬蟲
    所以,廣義上來說,利用程式語言搭建類似於問卷星的平臺也是數據採集階段需要掌握的技能之一;除此之外,批量收集網絡中的現有數據也是一種技能。那麼今天,小羅為大家介紹一種批量收集網絡數據的方式---網絡爬蟲。什麼是爬蟲?
  • Python——爬蟲
    網絡爬蟲:網絡爬蟲是一種按照一定規則,自動抓取全球資訊網信息的程序或腳本。簡單的說,就是用實現寫好的程序去抓取網絡上所需的數據,這樣的程序就叫網絡爬蟲。二、爬蟲分類網絡爬蟲根據使用的場景分為通用爬蟲和聚焦爬蟲。1、通用爬蟲通用爬蟲是搜尋引擎抓取系統的重要組成部分。主要是將網際網路上的網頁下載到本地,形成一個網際網路內容的鏡像備份。
  • Python新手爬蟲,簡單製作抓取廖雪峰的教程的小爬蟲
    先看幾張對比圖,分別是官網截圖和抓取下來的 txt文檔的截圖,不算那難看的排版的話,內容是一致的,圖片用 url替換了!在整個抓取過程中,除了普通的文本以外,還需要處理 3個地方,分別是:代碼、圖片、視頻,因為目前只寫到了文本文件,所以直接抓到圖片或者視頻的地址,標識清楚後寫入到 txt,這裡可以在進一步,寫到 word/pdf 或者其他文件,留待以後改進!