前言
上篇:在手把手叫你用R语言制作网络爬虫机器人(一)中我们已经把整个新闻所有链接的URL全部解析到R里面或者以html的文件格式,下载到电脑上了,下面我们就讲讲怎么用正则表达式来进行信息的提取。在这里我们第一步就是看看网页的源代码,首先要申明一点,正则表达式之所以难,是因为必须要找出所需信息的符号特征,以符号特征来进行信息提取,而且必须要观察所有网页的共同特征,这是我们要在现实项目中积聚的经验来判断,因为我今天用的是便携电脑,另外一台电脑在做遗传算法的实验,所以可能没有上次用单位电脑那么性能好,所以不足之处请大家见谅。
我们随便打开一个新闻链接。现在不管是谷歌浏览器或者是IE浏览器点击右键都有查看源代码一项,所以我们先点开网页,右键查看源代码。在这里我们要看的源代码网页为gzz.gov.cn/10000/10276/
我们可以看见,源代码就是这样的,当然没显示完,现在我们需要找到的就是我们所需要的信息,他们包含在源代码的后面
我们观察他们的特点,所有汉字信息都包含在“ONT-FAMILY: 仿宋,仿宋_GB2312; FONT-SIZE: 14pt"> <font style="FONT-FAMILY: 黑体"> </font></span><span style="FONT-FAMILY: 黑体; FONT-SIZE: 14pt">”这个符号之后,当然我们还需要提取标题,标题我们可以看见总是在“class="moji_f">”这个符号之后,而我们所要看的日期都在"border-bottom:#CCC 1px solid;">“这个符号之后,所以大致我们提取的文本信息就是这样的,这样的规律对于每一个链接都有效,因为是同样的语言写的网页,只要把规律找到我们不必担心其他的会不会以同样的规律存在,当然在用正则表达式的时候我们还要进一步调试代码以便于他们更好的能以只管的方式表现出来,对于一些文件里存在照片的我们会在以后相信讨论。
所谓的正则表达式是通过庞大的复杂的只有电脑才懂的一堆符号里提取我们所要的信息的语法,适用于很多种语言这里我们看看最常用的几个(来源百度百科),大家要想了解可以去查看专门的书籍,这里不再重复。
d
匹配一个数字字符。等价于[0-9]。grep 要加上-P,perl正则支持
\D
匹配一个非数字字符。等价于[^0-9]。grep要加上-P,perl正则支持
\f
匹配一个换页符。等价于\x0c和\cL。
\n
匹配一个换行符。等价于\x0a和\cJ。
\r
匹配一个回车符。等价于\x0d和\cM。
\s
匹配任何不可见字符,包括空格、制表符、换页符等等。等价于[ \f\n\r\t\v]。
\S
匹配任何可见字符。等价于[^ \f\n\r\t\v]。
\t
匹配一个制表符。等价于\x09和\cI。
\v
匹配一个垂直制表符。等价于\x0b和\cK。
\w
匹配包括下划线的任何单词字符。类似但不等价于“[A-Za-z0-9_]”,这里的"单词"字符使用Unicode字符集。
\W
匹配任何非单词字符。等价于“[^A-Za-z0-9_]”。
\xn
匹配n,其中n为十六进制转义值。十六进制转义值必须为确定的两个数字长。例如,“\x41”匹配“A”。“\x041”则等价于“\x04&1”。正则表达式中可以使用ASCII编码。
\num
匹配num,其中num是一个正整数。对所获取的匹配的引用。例如,“(.)\1”匹配两个连续的相同字符。
\n
标识一个八进制转义值或一个向后引用。如果\n之前至少n个获取的子表达式,则n为向后引用。否则,如果n为八进制数字(0-7),则n为一个八进制转义值。
\nm
标识一个八进制转义值或一个向后引用。如果\nm之前至少有nm个获得子表达式,则nm为向后引用。如果\nm之前至少有n个获取,则n为一个后跟文字m的向后引用。如果前面的条件都不满足,若n和m均为八进制数字(0-7),则\nm将匹配八进制转义值nm。
\nml
如果n为八进制数字(0-7),且m和l均为八进制数字(0-7),则匹配八进制转义值nml。
\un
匹配n,其中n是一个用四个十六进制数字表示的Unicode字符。例如,\u00A9匹配版权符号(©)。
\p{P}
小写 p 是 property 的意思,表示 Unicode 属性,用于 Unicode 正表达式的前缀。中括号内的“P”表示Unicode 字符集七个字符属性之一:标点字符。
其他六个属性:
L:字母;
M:标记符号(一般不会单独出现);
Z:分隔符(比如空格、换行等);
S:符号(比如数学符号、货币符号等);
N:数字(比如阿拉伯数字、罗马数字等);
C:其他字符。
这里我们所用语言为R,本质上来说是S高级语言,所以也适用大部分正则表达式,下面我们就需要构建正则表达式来提取我们所需要的信息。
因为信息量太多一共解析了2830个源代码我们这里就以第一个到第三个为例,剩下的以同样方法处理就可以。
parsefile<-a
t<-list(NULL)
length(t)=3
for(i in 1:3){
t[[i]]<-parsefile[[i]]
}
m<-lapply(t,function(t) str_extract(t,"14pt\">.+\\w+|moji_f\">.+\\w+|1px solid;\">.+\\w+"))
#################这里我们写的正则表达式为在"14pt\">以后出现的文字文本\\w这个在正则表达式里为文本的意思,| 这个竖横表达或者的意思通过上面的我们说的我们可以知道moji_f\
后面的是题目,1px solid;\">后面的是出处和日期###########
b<-lapply(m,function(m) m[-which(is.na(m))])
######因为正则表达式会把没用用的去掉产生NA所以这步我们去掉NA#######
b
运行代码我们可以得到
可以看到我们已经提取了我们所需要的结果(因为截屏原因没有显示完),但是还有部分字符没有去掉,所以我们还得调试我们代码:
h<-lapply(b,function(b) str_extract(b,">.+\\w+|仿宋.+\\w+"))
#######################一步步除掉我们不需要的字符,初学者特别要一步一步来####
k<-lapply(h,function(h) str_replace_all(h,pattern="</span><span style=\"FONT-FAMILY: 仿宋,仿宋_GB2312; FONT-SIZE: 14pt\">|</span>|<span>|</td|>|</p",
replacement=""))
#######################当我们发现我们不能出去</span>等字样的字符时候我们就要选择str_replace_all函数取替换他们把他们替换成空值,我们输出看看########
k
运行结果为:
可以看见我们要的新闻信息出来了在这里这里除了第二个文件比较正常(大部分都是这样的文件),第一个文件是有空格符和黑体标签,第三个文件有图片所以有<img border=\"0\" src=\"/ewebeditor/uploadfile/20170401091612648.jpg\" style=\"display: block;margin:0 auto;\"</img"这样的格式,我们暂且保留图片格式,因为以后我们会利用这个下载图片。
 就是html格式里空格的意思,我们用以下命令删除掉,但是“<font style=\"FONT-FAMILY: 黑体\" </font<span style=\"FONT-FAMILY: 黑体; FONT-SIZE: 14pt\”这一部分我始终没有去掉的办法,以后我去掉了会添加上来。
j<-lapply(k,function(k) gsub("([  ])", "", k))
j
结果为:
可以看见我们除掉空字符了
接下来我们把弄好的第三个新闻输出看看
for (i in 1:3) {
write.table(j[[i]],paste('file',i,'.txt',sep=''),quote = FALSE,row.names = FALSE,col.names = FALSE)
}
转成txt文件是因为我们接下来要做txt mining 分析便于写入,如果只是想爬取文件那我们可以转换为doc格式:
for (i in 1:3) {
write.table(j[[i]],paste('file',i,'.doc',sep=''),quote = FALSE,row.names = FALSE,col.names = FALSE)
}
我们打开看看
接下来我们把代码串联起来,输出所有文件
parsefile<-a
m<-lapply(parsefile,function(parsefile) str_extract(parsefile,"14pt\">.+\\w+|moji_f\">.+\\w+|1px solid;\">.+\\w+"))
b<-lapply(m,function(m) m[-which(is.na(m))])
h<-lapply(b,function(b) str_extract(b,">.+\\w+|仿宋.+\\w+"))
k<-lapply(h,function(h) str_replace_all(h,pattern="</span><span style=\"FONT-FAMILY: 仿宋,仿宋_GB2312; FONT-SIZE: 14pt\">|</span>|<span>|</td|>|</p",
replacement=""))
j<-lapply(k,function(k) gsub("([  ])", "", k))
for (i in 1:2830) {
write.table(j[[i]],paste('file',i,'.doc',sep=''),quote = FALSE,row.names = FALSE,col.names = FALSE)
}
我们以第三个文件图片格式下载为基础来讲解,
我们检查新闻链接里图片地址(点击图片右键复制地址),接下来我们又来找规律
gzz.gov.cn/ewebeditor/u
源代码里图片地址为
蓝色的部分为图片地址,但是真正的地址要加上基本url,http://www.gzz.gov.cn/,所以我们可以写出相应的正则表达式,从服务器里抓取图片(以上面举例的第三个文件为基础)
photo<-str_extract(t[[3]],"ewebeditor/uploadfile/.+\\w+.jpg")
photo<-photo[-which(is.na(photo))]
photo
我们可以看见提取了服务器图片地址再把它结合基本url,就可以得到完整的图片下载地址
photourl<-str_c(baseurl,"/",photo)
于是我们得到了一个完整的图片服务器下载地址我们下载来看看
download.file( photourl,"photo1.jpg",mode="wb")
##############这里可以保存为任何格式的图片文件不光jpg####
得到
我们可以看见图片文件就可以下载下来了,
我们把以上代码应用到整个2830个html
photo<-str_extract(parsefile,"ewebeditor/uploadfile/.+\\w+.jpg")
photo<-photo[-which(is.na(photo))]
photo
得到293个url
photourl<-str_c(baseurl,"/",photo)
我们下载这293张图片
for (i in 1:293) {
download.file(photourl[i],paste('photo',i,'.jpg',sep=''),mode="wb")
}
大家可以看见293张图片全部下载到文件里了。
联系客服