R爬取百度新闻数据

距里约奥运闭幕都已过去9天,8月19日那场“李林之战”的余热早已被建林的“小目标”淹没。当时答应的稿子也拖到不了了之(默哀三分钟……

现在只希望将曾经的尝试记录下来,以求不废在总是拾人牙慧却毫无输出面前。

在刚应下来写“李林之战”的稿子时的想法很简单:1.搜寻林李对战的历史新闻来源;2.爬取这些新闻的标题或摘要;3.作简单处理后分词做成词云,再简单分析,写个稿子。哪曾知所有的所有都跪倒在“写个稿子”门前(手动黑线,小编都哭了……

正式开始:

1. 找林李对战新闻来源

没想到这第一步就是个坑啊!找了一圈竟没发现一家新闻门户有好用的历史新闻入口,最后只能求助新闻搜索,对就是百度新闻。

2. 爬取新闻标题+来源和时间+摘要

2016年8月21日,进入百度新闻,搜索[林丹 李宗伟],共给返回38页结果,前37页每页20条,第38页18条,共758条新闻。简单分析一下,第1页网址固定,第2页至第38页通过”pn”索引。

爬取网页数据用到的R包

library(rvest) 

第1页内容爬取

## 保存第1页网址
url <- "http://news.baidu.com/ns?cl=2&rn=20&tn=news&word=%E6%9E%97%E4%B8%B9%20%E6%9D%8E%E5%AE%97%E4%BC%9F"

## 读取网页,定义了UTF-8编码,但似乎并没有什么用,编码格式依然保持原样
## 保存网页中的“标题”,“来源和时间”,“摘要”
Title <- url %>% read_html("UTF-8") %>% html_nodes("h3 a") %>% html_text()
Author <- url %>% read_html("UTF-8") %>% html_nodes("p.c-author") %>% html_text()
Abstract <- url %>% read_html("UTF-8") %>% html_nodes("div.c-summary.c-row") %>% html_text()

## 将页面信息保存为DataFrame格式
page <- cbind(Title,Author,Abstract)

其余页面既然有规律就可以用循环来完成每页的重复工作

首先是生成剩余页面的地址,剩下37页,每页20条新闻。这里需要注意的是”pn”的规律,pn=(n-1)*20,最后一页可能并没有20条记录。

url.other <- sapply(seq(20,37*20,20),function(i) {
  str_c("http://news.baidu.com/ns?word=%E6%9E%97%E4%B8%B9%20%E6%9D%8E%E5%AE%97%E4%BC%9F&pn=",i,"&cl=2&ct=0&tn=news&rn=20&ie=utf-8&bt=0&et=0")
  })

每页相同的工作

myfun = function(x) {
  Title = url.other[x] %>%read_html("UTF-8") %>% html_nodes("h3 a") %>% html_text()
  Author = url.other[x] %>%read_html("UTF-8") %>% html_nodes("p.c-author") %>% html_text()
  Abstract = url.other[x] %>%read_html("UTF-8") %>% html_nodes("div.c-summary.c-row") %>% html_text()
  cbind(Title,Author,Abstract)
}

用sapply函数实现循环爬取

page.other = sapply(1:37,function(i) myfun(i))

检查爬取失败的情况

预定是抓3个内容,在反复抓取的时候,就会出现漏掉某些项的情况,也没找到具体原因。曾怀疑是网站为防止大量抓取做的设定,试过在每次抓取完后暂停3秒,模拟人为访问的情况,仍然会随机出现遗漏,这个问题就暂时放下了。检查时只要找出结果中不是3列的即可。

evil=as.matrix(cbind(evil=1:37,tf=sapply(1:37,function(i) ncol(page.other[[i]]) !=3)))
evil[evil[,2]==1,]

看看是哪些部分出错

names=matrix(rep(NA,37*6),ncol=6)
for (i in 1:37) {
  names[i,]=colnames(page.other[[i]])
  names[i,duplicated(names[i,1:3])] <- NA
}
cbind(evil[evil[,2]==1,1],names[is.na(names[,3]),1:3])

出错的页面重新爬,直到成功为止

i=1
while(i<37){
  if (ncol(page.other[[i]]) != 3) page.other[[i]]=myfun(i)
  i=i+as.numeric(ncol(page.other[[i]])==3)
}

确认一遍有没有漏掉的记录,最后再合并页面

evil=as.matrix(cbind(evil=1:37,tf=sapply(1:37,function(i) ncol(page.other[[i]]) !=3)))
evil[evil[,2]==1,]
## 合并所页面
i=1
while(i<=37) {
  page=rbind(page,page.other[[i]])
  i=i+1
}

沙湾古镇骑行记

昨天,又一次与“剑走偏锋”骑车,休闲骑行+吃一份心中的美食。“剑走偏锋”是货真价实的老司机,在广州某押运公司开运钞车多年,广州市区和周边的一些城市都很熟悉。与他骑行的经历都很不错,路线从来不是需要担心的问题,目的明确,又不失随意,其个人是个正直,不乏浪漫的胖子。

广州7月的午后1点,太阳不是一般的毒。但是既然说好了,也只能硬着头皮上,还好到洛溪大桥的时候下了一阵雨,整个后面的路程就爽多了。我似乎是挺矛盾的人,喜欢路上一个人安静的骑车,有的没的想些事,也会很想把这种经历分享给别人(类似表达的欲望),但要是真有人同我一起,似乎我又要伤脑筋了,因为思考怎么与人交流或相处本身也是件费劲的事。说到这,就想到最近一同事(贝尔)总说我适合做销售,我是怎么都想不出适合的理由来。

4点许,到达大夫山自行车公园,与“剑走偏锋”的同事平哥汇合后,从南门直奔北门。平哥挺羞射的,似乎跟我有点相似,略闷骚。他担心太阳太毒,放弃骑车选择地铁出行,大夫山上一段基情的骑行.

穿过大夫山后,沿景观大道一路就可以到沙湾古镇了。跟所有古镇一样,沙湾也是很适合拍的古镇,一句话,这很古镇。有很多小店,大多是当地人开的,网上有名的推荐品尝的店面也不少。这里的各种奶制品真心推荐(水牛奶),喜欢甜品的真不可错过。

暴雨来临前的洛溪大桥,废旧的铁器,加上整齐的建筑,色彩和结构都可以。

luoxidaqiao1

黑云压城

luoxidaqiao2

大夫山内的一个湖泊,看到一只小,另外有一只停在水杉上水鸟没能认出来(不在此图中)

dafushan

在景观大道上也过了一座桥,不记得叫什么了。开始骑车时,很喜欢在路上的感觉,可以随意停留驻足,就像这些照片。不过今天看到这张时,突然有种感慨,一晃眼毕业就2年,当停在30岁的路口,是一种什么样的心境,能否淡然?能否担当?是否仍如20出头时一样,一无所有,又无法像20岁一样,一无所惧。

lutu

进入沙湾古镇后,见广场上打陀螺的父子(猜的)

datuoluo

一些古镇的景。古镇内使用了大量色彩艳丽的琉璃玻璃,巷子里的青石板路有些年岁,至于屋顶,大多是重修过了。遇到一个专心打着非洲鼓的小女孩,那种专注,加上吉他手的随意配合,真美!

men xiangzi wuding zhuanzhu nainiuhuanghou

有那么一个瞬间,想要在这住一个晚上,看着灯光亮起,等着人流稀疏。

ruye

转了一圈,吃了些小吃,快8点时就往回走了。途经洛溪大桥,江面深灰寂静,时有货船经过。而后一路狂踩,回到动物城(大学城)。

luoxidaqiao3

重回GitHub博客写作

这博客已经荒废了两年多了。Github也真是靠谱,在找回的时候跟当初离开时一模一样。如今,离开校园已经两年多,是时候停下来记录一些东西,即使是日常所感,所闻,工作所学所需,皆可简要记录。如今还有一块熟人访问量为0的清闲之地用于写作的尝试,可谓大幸,亦可谓大悲。

栅格计算器叠加不同范围的栅格

最近用ArcGis 10帮同学做不同栅格的叠加计算,遇到些问题,google解决后记录于此。目的很简单,就是把不同栅格进行叠加,重叠的区域进行加和,不重叠区域保持不变。步骤如下:

  1. 打开Spatial Analyst Tools > Map Algebra > Raster Caculator

  2. Environment Settings > Processing Extent > Extent 设置为将要计算的栅格中extent最大的栅格

  3. 用Con()和IsNull()函数进行计算,如下:

Con( IsNull( "raster1" ) + IsNull( "raster2" ) <> 2, ( Con( IsNull("raster1" ) , 0 , "raster1" ) + Con( IsNull( "raster2" ) , 0 , "raster2")))

函数将栅格分两部分处理’<>2,’之前的处理两个栅格都为空值的区域:“两个栅格都为空即为空”;之后的处理只要有一个栅格不为空的区域:为两部分的加和,Con()目的为把两个栅格不为空的区域转为extent一致的栅格,即将栅格为空的区域用0代替,其余为栅格原始值。

需注意的是函数的大小写和运算符之间的空格。

参考Esri中国社区来生缘对相应问题的回答。