中国DOS联盟论坛

中国DOS联盟

-- 联合DOS 推动DOS 发展DOS --

联盟域名:www.cn-dos.net  论坛域名:www.cn-dos.net/forum
DOS,代表着自由开放与发展,我们努力起来,学习FreeDOS和Linux的自由开放与GNU精神,共同创造和发展美好的自由与GNU GPL世界吧!

游客:  注册 | 登录 | 命令行 | 会员 | 搜索 | 上传 | 帮助 »
中国DOS联盟论坛 » DOS批处理 & 脚本技术(批处理室) » [原创]CMD与Curl双剑合璧:自动合并多页主题
作者:
标题: [原创]CMD与Curl双剑合璧:自动合并多页主题 上一主题 | 下一主题
ikari
初级用户





积分 58
发帖 6
注册 2006-8-1
状态 离线
『楼 主』:  [原创]CMD与Curl双剑合璧:自动合并多页主题

现实需求

当遇到长串经典的讨论帖;
当看到分多页的软件教程;
当发现让人爱不释手的连载小说的时候。
如何保存这些有很多分页的内容就成为了一件冗杂而又枯燥的机械劳动。
无论是手工复制还是依靠软件保存,都需要大量的人为干预,这是身为智慧生物的我们所不能容忍的。
既然计算机的出现就是替代人进行一些繁复的工作的,那为什么不把尽可能多的工作扔给它们呢?
可惜豆腐目前还没有发现一款软件可以满足我的要求,既然没有现成的可用那就自己动手吧。

思路分析

要解决一个问题必须先有一个环境,毕竟一个方案不可能通吃所有问题。我们就先设问题是要合并论坛中常见的多页主题。
要合并一个多页主题,我们首先得获取这个主题的每一个分页的内容,这种重复性的工作让机器来做是再适合不过的了。
其次我们需要分辨用户贴出的内容从哪里开始,在哪里结束。这部分第一次需要人来完成,后面的就交给机器吧。
最后我们需要获取我们需要的内容并把它重新组织起来生成最终的成果,这同样只需机器就可以很好的完成。
只要我们满足了上面三点,我们就可以把自己从重复劳动中解救出来做其它的事情了。

解决方案

由于高级语言需要专门的学习和配套的软件,这无形提高了应用的难度,最终豆腐选择了用CMD命令行来完成这个工作。
当然,CMD命令中是没有获取网页内容的功能的,我们还需要Curl这个强大的命令行工具来助我们一臂之力。
我们就以合并CCF精品技术论坛MPlayer 2006-03-03 K&K 更新在 992 楼为例,顺着刚才的思路来一步步尝试以达到最终的Goal。

网页抓取

在Curl的帮助下,我们可以轻松的通过命令行来抓取我们想要的网页:
curl -o tmp1.txt http://bbs.et8.net/bbs/showthread.php?t=634659&page=1&pp=15
这样我们就把该主题第一页的内容保存在了tmp1.txt文件中。
对于某些需要检测浏览器信息的网站,我们可以用
-A "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0)"
来伪装成IE浏览器。
对于需要使用cookies的网站,我们可以用
-D cookie1.txt
来保存cookies,用
-b cookie1.txt
来读取cookies。
对于防盗链的网站,我们可以用
-e "http://bbs.et8.net/"
来伪装成从某个相关联接进入的。 再与CMD中强大的 FOR 命令和变量相结合,加上人类的小小智慧,就可以打造出自动抓取该主题的全部内容的脚本。
分析该主题的URL,我们可以知道 page= 表示页数,这为自动化处理提供了基础,同时我们知道该主题有73页,最终的抓取脚本如下:
@echo off
setlocal ENABLEDELAYEDEXPANSION
set last=1
for /l %%i in (1,1,73) do (
echo %%i
curl -b cookie!last!.txt -D cookie%%i.txt -A "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0)" -e "http://bbs.et8.net/bbs/showthread.php?t=634659^&page=!last!^&pp=15" -o tmp%%i.txt http://bbs.et8.net/bbs/showthread.php?t=634659^&page=%%i^&pp=15
set /a last=%%i-1
)
copy tmp*.txt temp.txt
del cookie*.txt
del tmp*.txt
endlocal
将上面脚本保存为 grab.cmd 运行后我们就的到了保存了该主题全部73页内容的 temp.txt 文件。

内容分析

由于CMD字符处理的问题,我们先把 temp.txt 另存为 ANSI 编码。
分析单页的内容后豆腐发现该论坛程序在用户内容开始之前有一个每页唯一的 <div id="posts">,
而在结束的时候有一个同样唯一的 <!-- start content table --> ,这正是我们所希望找到的可以作为标志位的地方。

文本处理

由于 FOR 命令一次只能以同样的规则处理一行的内容,于是豆腐便采用 FOR 嵌套的方式来处理整个大文件。
先用
for /f "delims=" %%i in (temp.txt) do ( echo %%i >tmp.txt )
将 temp.txt 的内容一次一行地写入 tmp.txt。
再套用另一个 FOR 来处理 tmp.txt 的一行。

标志设置

我们可以通过 FOR 的 delims= 和 tokens= 参数来分割和保存一行的内容
我们用
for /f "tokens=1-3 delims=<->= " %%j in (tmp.txt)
参数设定以 "<"、">"、"-"、"="、" "来分割一行,
并把分割后的前三段内容存入 %%j %%k %%l 三个变量中。接着我们用 if 语句来判断这三个变量是否符合设置标志位的条件:
if "%%j"=="div" if "%%k"=="id" if %%l=="posts" set flag=1
if "%%j"=="start" if "%%k"=="content" if "%%l"=="table" set flag=0
flag=1 代表用户内容开始,flag=0代表用户内容结束。

内容剪裁

由于CMD命令行处理的限制,HTML中的注释开始符号 "<!--" 会被处理成 "<--" 这就会造成不期望的内容被显示出来。
我们可以再加一个 FOR 来解决这个问题:
for /f "tokens=1-8 delims=< " %%m in (tmp.txt) do (
if not "%%t"=="-->" if not "%%s"=="-->" if not "%%r"=="-->" if not "%%q"=="-->" if not "%%p"=="-->" if not "%%o"=="-->" if not "%%m"=="ECHO" if !flag!==1 echo %%i >>new.htm)
同时,我们也完成了把开始标志位后的内容存入 new.htm 的工作。

最终脚本
@echo off
setlocal ENABLEDELAYEDEXPANSION
set flag=0
for /f "delims=" %%i in (temp.txt) do (
echo %%i >tmp.txt
for /f "tokens=1-3 delims=<->= " %%j in (tmp.txt) do (
if "%%j"=="div" if "%%k"=="id" if %%l=="posts" set flag=1
if "%%j"=="start" if "%%k"=="content" if "%%l"=="table" set flag=0
for /f "tokens=1-8 delims=< " %%m in (tmp.txt) do (
if not "%%t"=="-->" if not "%%s"=="-->" if not "%%r"=="-->" if not "%%q"=="-->" if not "%%p"=="-->" if not "%%o"=="-->" if not "%%m"=="ECHO" if !flag!==1 echo %%i >>new.htm
)
)
)
del tmp.txt
endlocal
保存脚本为 merge.cmd 运行后得到合并出的 new.htm 文件就是该主题全部1083帖的内容。

优化改进

该脚本只完成了抓取文本内容的工作,我们还可以通过判断 IMG 元素来找到图片内容,
并把 src 属性后面的路径补完成完整路径,就可以正确显示出内容中的图片。

后记总结

CMD和Curl相结合可以完成很多批量的复杂工作,虽然第一次多花点时间,但之后就可以方便的使用了。
该脚本可以顺利抓取合并CCF精品技术论坛的任意主题以及部分基于vBulletin的论坛,但对于其它论坛还需要分别修改才可使用。

本文为chenke_ikari原创,首发于豆腐的简陋小屋
本文采用Creative Commons 署名-非商业性使用-相同方式共享 2.5 China 许可协议 进行许可


[ 本帖最后由 chenke_ikari 于 2006-7-13 10:00 编辑 ]





豆腐的简陋小屋
2006-8-1 23:07
查看资料  访问主页  发短消息 网志   编辑帖子  回复  引用回复
IceCrack
中级用户

DOS之友


积分 332
发帖 168
注册 2005-10-6
来自 天涯
状态 离线
『第 2 楼』:  

豆腐的简陋小屋  这个为什么登陆不上啊



测试环境: windows xp pro sp2    高手是这样炼成的:C:\WINDOWS\Help\ntcmds.chm
2006-8-2 21:15
查看资料  发送邮件  访问主页  发短消息 网志  OICQ (369525996)  编辑帖子  回复  引用回复
无奈何
荣誉版主





积分 1338
发帖 356
注册 2005-7-15
状态 离线
『第 3 楼』:  

RE ikari
        一登录论坛就看到了你的三篇加为精华的文章,首先欢迎加入我们论坛,同时也希望以后能够更多的参加论坛的讨论。
        关于 curl 的使用,为什么不选用 curl "http://bbs.et8.net/bbs/showthread.php?t=634659&page=[1-73]" -o tmp#1.htm 这样的方式来下载多页链接呢?
        事实上我也在做一个类似于采集器功能的批处理脚本,不过只是才刚刚开始。当初我在选择使用 curl 、还是 wget 时颇为犯难, curl 有很强大的模拟浏览器的功能但没有递归下载链接的能力, wget 递归下载能力强大但没有 curl 下载顺序并有规律的链接方便。但我最终还是选择了 wget ,因为我比较看中递归下载能力及将相对链接转为绝对链接的功能,可以方便的对网页进行下一步处理。针对 wget 的不足,我写了段脚本来完成多页链接的下载,这是我提及批处理脚本的一部分。

downhtm.cmd

  Quote:

  1. @echo off
  2. for /f "eol=# tokens=1,2 delims=        " %%i in (url.txt) do (
  3.         call :setpage "%%i" %%j
  4.         )
  5. goto :EOF

  6. :setpage
  7. set flag=0
  8. set _url="%~1"
  9. set pages=%2
  10. set endpage=%pages:*-=%
  11. call set startpage=%%pages:-%endpage%=%%
  12. if "%pages:~0,1%" GTR "9" (
  13.         set pages=%pages:~1%
  14.         set startpage=1%startpage:~1%
  15.         set endpage=1%endpage%
  16.         set flag=1
  17. )
  18. for /l %%i in (%startpage%,1,%endpage%) do (
  19.         call :download %%i
  20. )
  21. goto :EOF

  22. :download
  23. set num=%1
  24. if "%flag%" == "1" (
  25.         set num=%num:~1%
  26. )
  27. call set url=%%_url:(*)=%num%%%
  28. wget -k %url%
  29. goto :EOF
        无奈何发表于    2006-08-02  22:38

url.txt
格式类似这样:
#此行是注释行,以“#”号开头
#网页序号字母开头,表示可以多位数字对齐。
http://www.cn-dos.net/forum/forumdisplay.php?fid=9&page=(*)        1-5
http://www1.mydeskcity.com/xpbz(*).htm        A01-05
http://www.cn-dos.net/forum/forumdisplay.php?fid=23
请注意downhtm.cmd 文件第二行 delims= 后为制表符,可能显示为多个空格。

   此帖被 +4 点积分        点击查看详情   
评分人:【 ngd 分数: +4  时间:2009-12-16 21:39




  ☆开始\运行 (WIN+R)☆
%ComSpec% /cset,=何奈无── 。何奈可无是原,事奈无做人奈无&for,/l,%i,in,(22,-1,0)do,@call,set/p= %,:~%i,1%<nul&ping/n 1 127.1>nul

2006-8-2 22:52
查看资料  发送邮件  发短消息 网志  OICQ (105400208)  编辑帖子  回复  引用回复
ikari
初级用户





积分 58
发帖 6
注册 2006-8-1
状态 离线
『第 4 楼』:  



  Quote:
Originally posted by IceCrack at 2006-8-2 21:15:
豆腐的简陋小屋  这个为什么登陆不上啊

由于用的国外的DDNS服务,某些省市的DNS服务器解析有问题,如果需要可以用代理或者更换DNS服务器为
61.144.227.5
203.198.7.66
就可以了,决无副作用,而且还可以解决类似Google和Gmail的问题。



豆腐的简陋小屋
2006-8-3 08:52
查看资料  访问主页  发短消息 网志   编辑帖子  回复  引用回复
ikari
初级用户





积分 58
发帖 6
注册 2006-8-1
状态 离线
『第 5 楼』:  



  Quote:
Originally posted by 无奈何 at 2006-8-2 22:52:
RE ikari
        一登录论坛就看到了你的三篇加为精华的文章,首先欢迎加入我们论坛,同时也希望以后能够更多的参加论坛的讨论。
        关于 curl 的使用,为 ...

呵呵,那是版主们抬举了,说来惭愧,无论cmd和curl豆腐都是现学现卖,想到哪里写到哪里要学习的还很多,拿到这里来就是打算抛砖引玉之用的。

关于curl下载连接的问题,豆腐的确是用了个笨办法呢,wget和斑斑的脚本 豆腐一定好好体会下再来请教。



豆腐的简陋小屋
2006-8-3 09:02
查看资料  访问主页  发短消息 网志   编辑帖子  回复  引用回复
electronixtar
铂金会员





积分 7493
发帖 2672
注册 2005-9-2
状态 离线
『第 6 楼』:  

好贴,顶~~

2006-12-23 08:20
查看资料  发送邮件  发短消息 网志   编辑帖子  回复  引用回复
keyye
新手上路





积分 19
发帖 8
注册 2006-3-31
状态 离线
『第 7 楼』:  

学习了

2006-12-24 04:31
查看资料  发送邮件  发短消息 网志   编辑帖子  回复  引用回复
asnahu
初级用户





积分 99
发帖 53
注册 2006-8-18
状态 离线
『第 8 楼』:  

无奈何斑竹的点评相当到位,如果将两个软件合并起来就好了。

2009-11-9 08:31
查看资料  发送邮件  发短消息 网志   编辑帖子  回复  引用回复

请注意:您目前尚未注册或登录,请您注册登录以使用论坛的各项功能,例如发表和回复帖子等。


可打印版本 | 推荐给朋友 | 订阅主题 | 收藏主题



论坛跳转: