R语言爬虫系列6|动态数据抓取范例

0?wx_fmt=jpeg


通过前面几期的推送,小编基本上已经将R语言爬虫所需要的基本知识介绍完了。R虽然是以一门统计分析工具出现在大多数人印象中的,但其毕竟本质上是一门编程语言,对于爬虫的支持虽不如Python那样多快好省,但悉心研究一下总能做出一些让你惊喜的效果。

 

大约很早之前,小编就写过关于R语言爬虫新贵rvest的抓取介绍,之前说rvest+SelectGadgetor是结构化网页抓取的实战利器,大家的溢美之词不断。详情可见推文:

 

但网络爬虫这个江湖太险恶,单靠一招rvest行走江湖必然凶多吉少,一不小心碰到什么AJAX和动态网页凭仅掌握rvest的各位必定束手无策。本文小编就简单介绍下在用R语言进行实际的网络数据抓取时如何将动态数据给弄到手。

 

所谓动态网页和异步加载,在之前的系列4的时候小编已通过AJAX介绍过了,简单而言就是我明明在网页中看到了这个数据,但到后台HTML中却找不到了,这通常就是XHR在作祟。这时候我们就不要看原始的HTML数据了,需要进行二次请求,通过web开发者工具找到真实请求的url。下面小编就以两个网页为例,分别通过GET和POST请求拿到动态网页数据,全过程主要使用httr包来实现,httr包可谓是RCurl包的精简版,说其短小精悍也不为过。httr包与RCurl包在主要函数的区别如下所示:

0?wx_fmt=png


GET请求抓取微信好友列表数据

很早之前圈子里就看到过用Python抓取自己微信好友数据的案例分享,今天便以微信网页版为例,探一探其网页结构。首先登录个人微信网页版,右键打开web开发者工具,下来一大堆请求:

0?wx_fmt=png


简单找一下发现网页中的微信好友列表信息并没有呈现在HTML 中,大概可以断定微信好友数据是通过动态加载来显示的,所以直接定位到XHR中,经过几番尝试,结合右侧的preview,我们会发现大量整齐划一的数据,所以二次请求的url真的就是它了:

0?wx_fmt=png

 

找到真正的url之后,接下来就是获取请求信息了,切换到Headers版块,Header版块下的4个子信息我们都需要关注,它们是我们构造爬虫请求头的关键。


0?wx_fmt=png

 

从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的文件中:

 

0?wx_fmt=png


跟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语言自动数据采集


往期精彩:






一个数据科学狂热者的学习历程

640?
640?wx_fmt=jpeg
长按二维码.关注数据科学家养成记

640?wx_fmt=jpeg





  • 1
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值