红联Linux门户
Linux帮助

linux shell下载维基百科特色条目并统计单词词频

发布时间:2016-11-02 09:37:17来源:linux网站作者:archimekai
思路:首先使用wget下载足够的网页,然后awk配合正则表达式提取网页中的单词,最后使用awk进行词频统计并输出。
 
1、下载网站内容
首先使用wget递归下载wikipedia网站内容,为了提高采样质量,主要采集维基百科的特色(freatured)条目:
wget -r -e robots=off --wait=0.3 --level=1 -np--output-document=webpage.txt --quota=20Mhttps://en.wikipedia.org/wiki/Wikipedia:Featured_articles
参数解释:
-r 递归下载网站,
-e robots=off 使用了-r参数后,wget会以爬虫的形式下载网站,并且接受网站robots.txt的限制,不巧的是,维基百科限制了wget的爬虫访问,为此,需要让wget忽略这一限制,使用这一参数
--wait=0.3 为了防止访问频率过高被封禁IP,设置wget两次访问网站之间间隔0.3s
--level=1 递归深度为1。所输入的网页为维基百科所有特色条目的索引,所以只需要递归一层
-np 不递归父目录(noparent)
--output-document=filename 为了方便之后的处理,设置wget将网页源代码连接起来并存储到一个文件中
--quota=20M 设置最多下载20M网页内容(实际上一般会超过这一值,详细请见wget帮助),减少wget运行时间
https://en.wikipedia.org/wiki/Wikipedia:Featured_articles这是网页链接,为维基百科特色条目的索引。
 
2、提取网页文字
在分析词频的时候,必须排除网页中非文字内容的干扰,具体来说,主要是html标签和JavaScript脚本。原本这是很方便的,只要在删除JavaScript脚本后删去所有最邻近的<>之间的内容即可,但遗憾的是,shell(此处指awk, grep, egrep)中只能使用贪婪匹配,这会导致删去的内容过多(如<span>hahaha </span><span> bbbb</span>,我们希望删去所有的<span>和</span>,留下hahaha和bbbb,但是Linux会直接将整行文字匹配并删除),为此,我采用的技巧如下:
首先将>替换为换行,这样就可以确保以 `<`  开头的行只有原来 `<>` 之间的内容。然后,再将所有以`<`开头的行删掉即可,代码如下:
echo example | awk'{gsub(/>/,"\n");print;}'| awk'{gsub(/<.*/,"");print}'
但是,这样不能有效删除script标签之间的内容,因为两个script标签中的代码往往存在换行,换行干扰了上述操作。所以,还需要首先去除所有的换行,将网页连成一行,最终的代码如下:
echo example |awk 'BEGIN{p="";space=" "}{p=p""space""$0} END{print(p);}' | awk'{gsub(/<\/script>/,"\n");print}' | awk'{gsub(/<script>.*/,"");print}'| awk'{gsub(/>/,"\n");print;}'| awk'{gsub(/<.*/,"");print}'
这样即可将文件中大部分的html代码去除。
最后,文件中还有不少的换行,空格,和制表符,对这些符号,同样使用gsub进行替换,如下:
awk 'BEGIN{p="";space=" "}{p=p""space""$0} END{print(p);}'|awk '{gsub(/[\t]{1,}/," ");print}'
为了方便处理,再将输出改为一个单词一行:
egrep -o "\b[[:alpha:]]+\b"
2.1、注:如何将文件连接成一行:
我的方法是使用awk将所有的行存储到一个变量中:
awk 'BEGIN{p="";space=" "}{p=p""space""$0} END{print(p);}'
其中关键的是字符串连接的方法,awk中,假设有两个字符串:
Str1="aaaaa";
Str2="bbbb";
Str3=Str1""Str2;
使用""即可连接两个字符串
 
3、统计各个单词的词频
统计词频对于awk的关联数组是非常简单的工作,当文字整理成一个单词一行后,只需要:
awk '{ count[$0]++ } '
即可将各个单词的个数统计于count数组中,使用:
即可将数组按照下标排列好后输出:
awk '{ count[$0]++ } END{slen=asorti(count,newcount);printf("%-14s%s\n","Word","Count") ;  for(i=1;i<=slen;i++) {printf("%-14s%d\n",newcount[i],count[newcount[i]]); } }'
3.1、注:awk中的排序函数
awk中有两个排序函数:asort和asorti,使用方法为
arrayLength = assort/asorti(sourceArray, destinationArray)
使用asort可以对数值进行排序,数组的索引(下标)会被丢弃。
使用asorti可以对下标进行排序,但是数组的索引会被丢弃。
排序完成后会返回数组长度arrayLength
 
4、完整代码
最后奉上完整代码如下:
#Author     <span style="white-space:pre">        </span>Archimekai  
#Date               <span style="white-space:pre">    </span>20161102  
# !bin/bash  
filename="webpage.txt";  
wget -r -erobots=off --wait=0.3 --level=1 -np --output-document=$filename --quota=20M https://en.wikipedia.org/wiki/Wikipedia:Featured_articles  
awk'BEGIN{p="";space=" "} {p=p""space""$0}END{print(p);}' $filename | awk '{gsub(/<\/script>/,"\n");print}'| awk '{gsub(/<script>.*/,"");print}'| awk'{gsub(/>/,"\n");print;}'| awk'{gsub(/<.*/,"");print}'|awk 'BEGIN{p="";space=""} {p=p""space""$0} END{print(p);}'|awk '{gsub(/[\t]{1,}/," ");print}'|egrep -o "\b[[:alpha:]]+\b"|awk '{count[$0]++ } END{slen=asorti(count,newcount);printf("%-14s%s\n","Word","Count") ;  for(i=1;i<=slen;i++) {printf("%-14s%d\n",newcount[i],count[newcount[i]]); } }'>wordfreq.txt  
cat wordfreq.txt
部分输出:
Word          Count
A             1288
AA            2
AAA           1
AB            2
ABC           6
ABCD          1
ABN           2
AC            3
ACC           10
ACM           1
ACR           3
ACS           11
ACT           1
ACTION        3
AD            45
ADMIN         1
ADORAVI       2
ADW           4
AE            1
AEC           3
AETERNAE      1
AFAIK         1
AFD           2
 
本文永久更新地址:http://www.linuxdiyf.com/linux/25649.html