学习sed/awk后第一发: jjwxc文章下载器

工作时经常会用到批量文本文件编辑,比如批量改个机器名啊,给所有.csproj文件加上某个xml element啊之类的。平常的做法一般是写个小c#程序扫描文件,读写内容。这些程序80%都是一样的,虽然用C#的StreamReader/Writer IO操作还算方便,每次copy-paste也累。而且很多情况下很小的改动还要建个工程,编译实在太麻烦。于是前段时间趁着假期学了一下sed/awk这对文本操作利器。

刚好老婆最近迷上看网文,叫我写个程序批量下载收藏一些。。。嗯,正好可以尝试一下新学的技能大笑

需求:从jjwxc.net上下载小说。给定URL,比如:http://www.jjwxc.net/onebook.php?novelid=1234567&chapterid=1  <- chapterid [1..n]


大致研究了一下,这个网页结构还算简单,文章正文都在<div class="noveltext">里,但有一些子div里放着一些链接需要去掉。另外正文里充斥着和背景同色的防拷贝文本,不过非常规律,普通的正则表达式就可以匹配。好了,大体步骤确定了:

  1. 用wget把url保存到文件
    wget -q -Ojjd.htm.gz %URL%
  2. gzip解压
    gzip -df jjd.htm.gz
    
  3. iconv转码(gb2312 -> utf-8)
    iconv -c -f gb2312 -t utf-8 jjd.htm > jjd.utf8.htm
  4. sed/awk抓取相应内容,做一下格式转换,最终输出到txt文件
    sed "s/>/\n/g" jjd.utf8.htm | awk -f "jjd.awk" | sed "-fjjd.sed" | awk -f "jjd.2.awk" > %OUTFILE%
前三步没什么好说的。

第四步分为a,b,c,d四段,通过管道连起来:

a. 因为sed/awk都是以行为单位的,为了方便,首先要做的是把放在同一行内的html tag放到不同的行,这样数open tag/close tag就比较容易。这一步用sed把所有的'>'字符变成换行。


b. 这一段抓取小说正文。jjd.awk的代码如下:
/<div class="noveltext"/ {
    level = 1
    next
}

level == 1 {
    print $0
}

level > 0 && /<div/ { level++ }
level > 0 && /<\/div/ { level-- }

awk可以理解成一些if... { } 语句。每个{ }外的条件满足时,执行{ }内的代码。这里一共有四个条件:
1. 如果某一行能匹配正则表达式 /<div class="noveltext"/ (这就是正文所在的div),设level为1。这个level用来跟踪目前html tree的位置。
2. 如果level为1的时候打印本行。level==1就是说在noveltext这个div内,并且不在子div中。如果写成level >= 1就会把子div中的内容也打印出来。
3,4. 进div level +1,出div level -1.


c. 上一个awk出来的内容是小说的正文加上防拷贝文本和一些残留的html tag。这里把它们去掉。jjd.sed代码如下:
s/<.*$//g
s/^[  ]\+$//g
s/^。.*@$//g
s/^。[0-9a-z]\+$//g

1. 去掉所有html tags
2. 去掉多余空格
3,4. 去掉防拷贝文字。

d. 这个awk其实不用也行,用来去掉多余的空行让结果更好看一些:
/^$/ {
    if(content > 0 && c++ < 1) {
        print $0
    }
    next
}

{
    c = 0
    content = 1
    print $0
}

把所有东西写在.cmd里,删掉临时文件,搞定:) 为了方便易用可以写个自动调用下载所有章节,做个UI什么的,但已经和sed/awk无关啦。
另外也可以不用sed/awk,而是parse xml,然后精确定位正文位置,但是html要转成well formed xml(可以用html tidy)。
用这个程序,如果正文中有&gt;等html encoded字符是不会被decode的,可以用sed在最后做一下替换。但是,得了吧,一般小说都用全角符号,连空格都是全角的!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值