Board logo

标题: 批处理提取网页中《西游记》原文 [打印本页]

作者: batman    时间: 2011-4-29 11:19     标题: 批处理提取网页中《西游记》原文

本帖最后由 batman 于 2011-4-29 12:10 编辑

要求用批处理提取http://bbs.tt365.net.cn/viewthread.php?tid=161145网页贴子中《西游记》原文。

注意原文都是用【】括起来的,但要进行去重处理。

而这个去重处理包括去除重复出现的原文以及原文中有的短句如:

【一件破烂流丢一口钟】与【一件破烂流丢一口钟】(去除后面这句)

【悟空道:“但凭尊师教诲,只是有些道气儿,弟子便就学了。”】与【只是有些道气儿】(去除后面这句)

最后所有提取的内容输出为a.txt(一行一句),可以使用临时文件,同时请尽量不使用第三方工具。
作者: namejm    时间: 2011-4-29 11:34

本帖最后由 namejm 于 2011-4-29 11:35 编辑

如果纯挑战的话
限制不使用第三方倒也无可厚非
只是恐怕愿意来挑战的就没有几个人了
动力不足是个大问题
如果能明言挑战这个题目的真实意图
并且不限制是否使用第三方
倒是有可能有大批的人来做
——你恐怕是想在论坛里抓小说吧?

下载网页肯定得用第三方
去除网页代码肯定得用第三方
若是我来做的话,就至少有两个命令行需要使用
1、curl或wget
2、HtoX32c
作者: batman    时间: 2011-4-29 11:48

2# namejm
我知道第三方的强大,但我提出这个挑战的目的就是要扩充批的实用性。

ps:jm你应该知道我在提出问题前,自己肯定是已经成功完成了的。。。。
作者: Batcher    时间: 2011-4-29 12:02

抓网页内容不用第三方也行,调用VBS嘿嘿。
作者: batman    时间: 2011-4-29 12:22

4# Batcher
思路一致,呵呵。。。
作者: asnahu    时间: 2011-4-29 12:46

严格说来VBS也是第三方
作者: caruko    时间: 2011-4-29 14:46

本帖最后由 caruko 于 2011-4-29 14:48 编辑

要获取网页内容,如果不用第三方的话,必须
start "" /min "C:\Program Files\Internet Explorer\IEXPLORE.EXE" "http://bbs.tt365.net.cn/viewthread.php?tid=161145"
打开网页,然后提取缓存。 最后根据窗口标题名,taskkill掉。
如果这些都是给定的条件,那么容易不少。否者可能要wmic开启进程了。
作者: CrLf    时间: 2011-4-29 15:01

那ie算不算第三方呢...
作者: caruko    时间: 2011-4-29 15:01

还有一种方法
1, ping bbs.tt365.net.cn 取得目标IP
2, start 网页
3, 取得缓存
4, 根据netstat -o 对比IP 获取 IE的PID,然后taskkill。
作者: Batcher    时间: 2011-4-29 15:10

ping、netstat之类的也不是built-in啊
楼主出题的本意不是让大家扣字眼到底哪些是第三方
他不让用wget/curl,你就偏偏用,他还能吃了你?
无非是让大家练练手而已
作者: CrLf    时间: 2011-4-29 15:38

10# Batcher


啊!太口怕了,版主竟然吃人...
作者: caruko    时间: 2011-4-29 16:38

本帖最后由 caruko 于 2011-4-29 16:53 编辑

发一个取【】内容的代码吧,鉴于【】都在一行,所以没有多做分析。
但就算【】内容分做2行,IF里面加一句判断 !cut:~-1!==$ 就可以了。

抓取网页内容,前面已说了方法,第三方的话更简单,就不写了。
去掉了多余的CALL。

去重只是简单的当前这句跟上一句对比,如果包含在上一句内,就不输出,并且下一句对比时忽略这一句,跟上上句对比。
  1. @echo off&setlocal enabledelayedexpansion
  2. for /f "usebackq delims=" %%i in ("viewthread[2].txt") do (
  3.     set "str=%%~i"
  4.     if not "!str:【=!" == "!str!" (
  5.         set "str=!str:【=" "#!"
  6.         set "str=!str:】=" "$!"
  7.         for %%i in ("!str!") do (
  8.             set "cut=%%~i"
  9.             if "!cut:~0,1!"=="#" if !flag! equ 1 (
  10.                 set "s_new=!cut:~1!"
  11.             ) else (
  12.                 set flag=1
  13.                 set "s_old=!cut:~1!"
  14.                 set "s_new=!cut:~1! "
  15.             )
  16.             for /f "delims=" %%S in ("!s_new!") do if "!s_old:%%S=#!"=="!s_old!" echo %%S&set "s_old=!s_new!"
  17.         )
  18.      )
  19. )
  20. pause>nul&goto :eof
复制代码

作者: qzwqzw    时间: 2011-4-29 16:38

明确一下第三方的概念
就是初始安装的操作系统中未包含的程序或者数据
不要刻意扩大或者缩小
那对解题没有任何助力

如果有必要
可以使用ASCODE技术将任何程序或数据编码
存储到批处理自身中
运行时再进行解码后调用

对于start 网页的形式
可能打开非IE内核的浏览器
这将影响缓存的确定
不建议使用
作者: batman    时间: 2011-4-29 16:41

12# caruko
最好能将所有代码写出来,大家本来就是为了交流嘛。。。

ps:去重有点麻烦哦。。。
作者: powerbat    时间: 2011-4-29 19:15

应该放在VBS出题区比较好吧?
而且也没有什么挑战性,会VBS且会xmlhttp、adodb.stream、DOM等常见“第三方”对象的使用,本题迎刃而解,关键是要知道那几个对象。

其实我想问这个问题:如何用vbs从图片中读出验证码(如果有人研究出来了,肯定不能随便公开^@^)
作者: batman    时间: 2011-4-29 19:47

15# powerbat
本题最难点在于去除局部重复内容,以我对vbs的了解,它表示压力很大。。。
作者: caruko    时间: 2011-4-29 20:17

16# batman


如果不追求节省资源+效率,可以一边写入文件,然后下一句开始findstr文本。
作者: caruko    时间: 2011-4-29 20:29

试过用IE打开网站,读缓存,但是几个问题很麻烦。
主要问题是IE打开的速度有快有慢,很难知道IE有没有将网页完全下载,除非设置较长的延时,或者等待端口time out(也很久)。

找到对应的缓存文件的方法如下:
1, ping 得到IP。
2,REG方式得到缓存主目录。
3,start web
4,在缓存主目录里,dir /s /b /ad /od /tw 得到最近访问时间的缓存文件夹。
5,netstat -o |findstr "IP"得到“PID”,然后tasklist 取得IE窗口“TITLE”。
6,进入缓存文件夹,findstr /i "<title>.*%Title%" *,查找缓存文件。

还是用NC,WGET要容易的多。
作者: batman    时间: 2011-4-29 20:34

18# caruko
是不是想得太复杂了。。。
作者: caruko    时间: 2011-4-29 20:38

如果似乎给定的网站,那么TITIE,缓存文件都是固定的。
就可以直接就找到了。
作者: asnahu    时间: 2011-4-29 21:04

楼上的同学走得太绕了
作者: CrLf    时间: 2011-4-29 22:22

本帖最后由 zm900612 于 2011-4-29 22:24 编辑

这个vbs部分是照搬别人的...
  1. @echo off&setlocal enabledelayedexpansion
  2. more>1.vbs +16 %0
  3. wscript //nologo 1.vbs "http://bbs.tt365.net.cn/viewthread.php?tid=161145" 1.htm
  4. (for /f "delims=" %%a in ('findstr /rc:"【.*】" 1.htm') do (
  5. set str=%%a【
  6. for /l %%b in (1 1 100) do (
  7. if "!str!" neq " " for /f "tokens=1* delims=】" %%c in ("!str:*【=!") do (
  8. if not defined .%%c (
  9. set .%%c=.
  10. echo %%c
  11. )
  12. )
  13. )
  14. ))>3.txt
  15. pause&exit
  16. iLocal=LCase(Wscript.Arguments(1))
  17. iRemote=LCase(Wscript.Arguments(0))
  18. Set xPost=createObject("Microsoft.XMLHTTP")
  19. xPost.Open "GET",iRemote,0
  20. xPost.Send()
  21. set sGet=createObject("ADODB.Stream")
  22. sGet.Mode=3
  23. sGet.Type=1
  24. sGet.Open()
  25. sGet.Write xPost.ResponseBody
  26. sGet.SaveToFile iLocal,2
复制代码

作者: batman    时间: 2011-4-29 23:19

22# zm900612
效率我不评论,提取的文字少了n行。。。
作者: CrLf    时间: 2011-4-29 23:23

23# batman


效率低的是vbs部分,那部分我没有一点办法,bat部分可以通过调整for /l循环数来控制用时。至于漏行,我去调试一下吧...
作者: powerbat    时间: 2011-4-29 23:52

【悟空道:“但凭尊师教诲,只是有些道气儿,弟子便就学了。”】与【只是有些道气儿】
如果短句子在前面呢?怎么处理?
作者: batman    时间: 2011-4-30 00:58

25# powerbat
可不视为重复。。。
作者: powerbat    时间: 2011-4-30 09:24

vbs
  1. Set fso = CreateObject("Scripting.FileSystemObject")
  2. Set dict = CreateObject("Scripting.Dictionary")
  3. downloader "http://bbs.tt365.net.cn/viewthread.php?tid=161145", "E:\test\aaa.htm"
  4. Set oDOM = GetObject("E:\test\aaa.htm", "htmlfile")
  5. Do Until oDOM.readyState="complete" : WScript.Sleep 200 : Loop 'complete
  6. Set tags = oDOM.getElementsByTagName("td")
  7. for each tag in tags
  8.     if 1=InStr(tag.Id,"postmessage_") then
  9.         'WScript.echo tag.innerText
  10.         StrStrReg tag.innerText, "【([^【】]+)】"
  11.     end if
  12. next
  13. Set ts = fso.OpenTextFile("result.txt", 2, true)
  14. for each key in dict.Keys()
  15.     'WScript.echo key
  16.     ts.WriteLine key
  17. next
  18. ts.Close()
  19. function downloader(url, file)
  20.   dim XMLHTTP, AdoStrm
  21.   Set XMLHTTP = CreateObject("Microsoft.XMLHTTP")
  22.   XMLHTTP.Open "GET", url, false
  23.   XMLHTTP.Send()
  24.   set AdoStrm = CreateObject("ADODB.Stream")
  25.   AdoStrm.Mode = 3
  26.   AdoStrm.Type = 1
  27.   AdoStrm.Open()
  28.   AdoStrm.Write XMLHTTP.ResponseBody
  29.   AdoStrm.SaveToFile file, 2
  30. end function
  31. function StrStrReg(srcStr, subStr)
  32.   dim regEx, Matches, Match, ret
  33.   set regEx = CreateObject("VBScript.RegExp")
  34.   regEx.Pattern = subStr
  35.   regEx.Global = true
  36.   regEx.IgnoreCase = false
  37.   set Matches = regEx.execute(srcStr)
  38.   for each Match in Matches
  39.     'ret = ret & Match.subMatches(0) & vbCrLf
  40.     Catch Match.subMatches(0)
  41.   next
  42.   StrStrReg = ret
  43. end function
  44. function Catch(txt)
  45.   for each key in dict.Keys()
  46.     if InStr(key,txt) then exit function
  47.   next
  48.   dict.Add txt, 1
  49. end function
复制代码

作者: CrLf    时间: 2011-4-30 10:58

本帖最后由 zm900612 于 2011-4-30 12:53 编辑

昨天漏了set str=%%b以便重新进入循环,而且没注意要将长句分段判断是否重复的要求,重写了下
batman说我代码效率很低,其实bat部分是冤枉的,我一向比较关心算法的效率,特别慢的算法好意思拿出来吗?这种小文件还不至于太卡,大文件才可能有明显的减速,主要是vbs下载用时太长...
  1. @echo off&setlocal enabledelayedexpansion
  2. echo %time% 开始下载
  3. more>1.vbs +22 %0
  4. wscript //nologo 1.vbs "http://bbs.tt365.net.cn/viewthread.php?tid=161145" a.htm
  5. echo %time% 下载完成
  6. (for /f "delims=" %%a in ('findstr /rc:"【.*】" a.htm') do (
  7. set str=%%a【
  8. for /l %%b in (1 1 10) do (
  9. if "!str!" neq "" for /f "tokens=1* delims=】" %%c in ("!str:*【=!") do (
  10. if "!.%%c!"=="" (
  11. set tmp=%%c
  12. for %%e in (, 。 “ ” ; : ? !) do set tmp=!tmp:%%e=","!
  13. for %%e in ("!tmp!") do set .%%~e=.
  14. set .%%c=.
  15. echo %%c
  16. )
  17. set str=%%d
  18. )
  19. )
  20. ))>a.txt
  21. echo 处理完成 %time%
  22. pause&exit
  23. iLocal=LCase(Wscript.Arguments(1))
  24. iRemote=LCase(Wscript.Arguments(0))
  25. Set xPost=createObject("Microsoft.XMLHTTP")
  26. xPost.Open "GET",iRemote,0
  27. xPost.Send()
  28. set sGet=createObject("ADODB.Stream")
  29. sGet.Mode=3
  30. sGet.Type=1
  31. sGet.Open()
  32. sGet.Write xPost.ResponseBody
  33. sGet.SaveToFile iLocal,2
复制代码
more的行数差了两行,改下
作者: batman    时间: 2011-4-30 12:22

28# zm900612
兄弟算法ok,算术不ok。。。
作者: CrLf    时间: 2011-4-30 12:45

29# batman


汗,加了那三条echo,忘了改more相应的参数
作者: caruko    时间: 2011-4-30 12:46

固定循环10次=。=
我觉得用我的将【替换为 "# ,将】替换为" ,直接达到分句效果会更好一点,for循环可以直接取出有用的句子。

去除重复,因为整个文章不长,一个变量可以放的下,就再可以用ZM那种按标点符号分句,然后匹配每个小句是否重复。

如果是不确定的长度,10次不确定,一个变量存放整个纹章也不够。
作者: CrLf    时间: 2011-4-30 12:52

循环1000次也没什么影响的,因为for的输入为空,循环数就只是微调
作者: batman    时间: 2011-4-30 12:58

30# zm900612

22?你真的要去小学进修了,哈哈。。。
作者: CrLf    时间: 2011-4-30 13:02

“将【替换为 "# ,将】替换为" ,直接达到分句效果”,这个倒是好办法,没想到
作者: terse    时间: 2011-4-30 15:08

等下试外部看怎么样
  1. @echo off
  2. (echo Set oDOM=WScript.GetObject("http://bbs.tt365.net.cn/viewthread.php?tid=161145"^)
  3. echo Do Until oDOM.readyState="complete"
  4. echo WScript.sleep 300
  5. echo Loop
  6. echo WScript.echo oDOM.documentElement.outerText)>%temp%\tem.vbs
  7. setlocal enabledelayedexpansion
  8. (
  9. for /f "delims=" %%i in ('cscript //nologo "%temp%\tem.vbs"^|find "【"') do (
  10.     set var=&set "str=%%i"
  11.     set "str=!str:*【=【!"
  12.     set "str=!str:【= 【!"
  13.     set "str=!str:】=】 !"
  14.     for %%j in (!str!) do (
  15.         set "j=%%j"
  16.         if "%%j" neq  "!j:【=!" (
  17.            if defined var (
  18.               for /f "delims=【】" %%k in ("%%j") do (
  19.                       if "!var:%%k=!" equ "!var!" set var=!var! 【%%k】
  20.               )
  21.            )else set var=%%j
  22.         )
  23.     )
  24.     for %%j in (!var!) do echo %%j
  25. )
  26. )>tem.txt
  27. del %temp%\tem.vbs&start "" tem.txt
  28. pause
复制代码

作者: batman    时间: 2011-4-30 15:47

35# terse
结果仍有重复,请兄再测试修改。。。
作者: batman    时间: 2011-4-30 15:49

我的解:
  1. @echo off&setlocal enabledelayedexpansion
  2. more +27 %~fs0>temp.vbs
  3. temp.vbs&del /q temp.vbs&set /a n+=1
  4. (for /f "delims=" %%a in ('findstr "【" a.txt') do (
  5.     set "str=%%a"
  6.     set "str=!str:【= !"&set "str=!str:】=$ !"
  7.     for %%a in (!str!) do (
  8.         set "a=%%a"&set "flag="&set "var=!a:~,-1!"
  9.         if "!a:~-1!" equ "$" (
  10.            for %%a in (!var!) do (
  11.                if defined str!n! for /l %%b in (1,1,!n!) do if "!str%%b:%%a=!" neq "!str%%b!" set "flag=a"
  12.                if not defined flag (
  13.                   echo 【%%a】
  14.                   for %%b in (!n!) do (
  15.                       set "a=!str%%b! %%a"
  16.                       if "!a:~8000!" equ "" (
  17.                          set "str%%b=!a!"
  18.                          ) else (
  19.                          set /a n+=1&set "str!n!=%%a"
  20.                       )
  21.                   )
  22.                )
  23.             )
  24.          )            
  25.      )
  26. ))>$
  27. move $ a.txt&start a.txt&goto :eof
  28. Set http = createObject("Microsoft.XMLHTTP")
  29. http.Open "get" , "http://bbs.tt365.net.cn/viewthread.php?tid=161145" , 0
  30. http.send()
  31. Set myGet = createObject("ADODB.Stream")
  32. myGet.Mode = 3
  33. myGet.Type = 1
  34. myGet.Open()
  35. myGet.Write(http.responseBody)
  36. myGet.SaveToFile "a.txt" , 2
  37. myGet.Close
  38. Set myGet = Nothing
  39. Set http = Nothing
复制代码





欢迎光临 批处理之家 (http://www.bathome.net/) Powered by Discuz! 7.2