Board logo

标题: [原创]批量智能下载网页图片[抛砖] [打印本页]

作者: ngd     时间: 2008-3-14 17:00    标题: [原创]批量智能下载网页图片[抛砖]

在学校上网一直不是很方便,难得有机会研究了一个东东,拿出来抛砖引玉,大家共同探讨批量下载与智能下载。

需求:

在6dzone.com上看到一些不错的图片,http://www.6dzone.com/photo/wyxc/userphoto.asp?pid=8029
http://www.6dzone.com/photo/wyxc/userphoto.asp?pid=10369
但保存图片实在很麻烦,本来网速就超慢,还需要打开一个一个的网页,然后右击图片“另存为”,还是考虑一下批量下载。


分析:

目前用的较多的图片批量下载工具好像是 GlobalFetch ,下载的图片倒是很多,但99%不是自己想要的。

另外迅雷和网际快车都有批量下载功能,但必须是有共同特征的下载地址,只适合下载***001.jpg、***002.jpg、***003.jpg……之类地址的文件。

目前还没有发现一款软件可以满足我的要求,还是自己写个程序来模拟用户操作,毕竟数据都是要通过http完成的,从html代码中也能找到一些共性,把这些重复性的操作都交给程序来执行就行了。

每种语言都有各自的特点,cmd batch 做这些事实在是方便高效,即写即运行。而用高级语言实现就很麻烦,“杀鸡焉用宰牛刀”!


所需命令行工具

curl ——功能强大的命令行浏览器、下载工具
http://www.cn-dos.net/forum/view ... &highlight=curl

wget ——功能强大的命令行下载工具
http://baike.baidu.com/view/1312507.htm

sed ——功能强大的命令行流编辑器
http://www.cn-dos.net/forum/view ... 0%E6%AD%A3%E5%88%99

用好sed、grep、awk等编辑器还需掌握正则表达式

正则表达式
http://www.cn-dos.net/forum/view ... 0%E6%AD%A3%E5%88%99


要解决一个问题必须先有一个环境,毕竟一个方案不可能通吃所有问题,只针对6dzone的相册下载。个人喜欢使用遨游浏览器,先将喜欢的相册网址添加到收藏夹再将收藏的网址导出为bookmark.html文件。

使用sed解析bookmark.htm文件,获取所要的网址,
找出有网址的行
sed "/photo/!d" bookmark.htm
或者
sed -n "/photo/p" bookmark.htm
再获取引号中间的网址,合起来就是:(其中"的ASII码值为34,转换为正则表达式即为 \x22)
sed "/photo/!d;s/[^\x22]*\x22//;s/\x22.*//" bookmark.htm
另外6dzone需要注册用户认证登陆才能看到大图片,需要使用curl模拟用户登陆并导出cookie

首先得分析一下网页代码及其表单,推荐使用View page插件,另外IE的httpwatch和Firefox的TamperData都是很不错的插件!

curl提交表单一般有2种方法:get方式和post方式,这得取决于表单的method,另外还得分析一下 Action 和 提交表单要用的 Name

以下是cn-dos论坛登陆页面的html代码
----------------------------------------------------------------------------------------------------------
<FORM action=logging.php?action=login method=post><INPUT type=hidden value=28c5c8a4 name=formhash> <INPUT type=hidden value=http://www.cn-dos.net/forum/viewthread.php?tid=22634&amp;fpage=1&amp;highlight=sed%20%2B%20wget%20%2B%20%E6%AD%A3%E5%88%99&amp;sid=FHJYXn name=referer>
<TABLE cellSpacing=0 cellPadding=0 width="99%" align=center border=0>
<TBODY>
<TR>
<TD bgColor=#dde3ec>
<TABLE cellSpacing=1 cellPadding=4 width="100%" border=0>
<TBODY>
<TR class=header>
<TD colSpan=2>会员登录</TD></TR>
<TR>
<TD bgColor=#f8f9fc>隐身登录:</TD>
<TD class=smalltxt bgColor=#ffffff><SELECT name=loginmode> <OPTION value="" selected>- 使用默认 -</OPTION> <OPTION value=normal>正常模式</OPTION> <OPTION value=invisible>隐身模式</OPTION></SELECT> </TD></TR>
<TR>
<TD bgColor=#f8f9fc>界面风格:</TD>
<TD bgColor=#ffffff><SELECT name=styleid><OPTION value="" selected>- 使用默认 -</OPTION> <OPTION value=1>Default Style</OPTION></SELECT> </TD></TR>
<TR>
<TD bgColor=#f8f9fc>Cookie 有效期:</TD>
<TD class=smalltxt bgColor=#ffffff><INPUT type=radio value=31536000 name=cookietime> 一年 &nbsp; <INPUT style="BACKGROUND: #ffffcc" type=radio CHECKED value=31536000 name=cookietime> 一个月 &nbsp; <INPUT type=radio value=86400 name=cookietime> 一天 &nbsp; <INPUT type=radio value=0 name=cookietime> 浏览器进程 &nbsp; &nbsp; <A href="faq.php?page=usermaint#2" target=_blank>[相关帮助]</A></TD></TR>
<TR>
<TD bgColor=#ffffff colSpan=2 height=1></TD></TR>
<TR>
<TD align=middle colSpan=2><FONT color=red>注意:</FONT>老用户 <B>首次</B> 登录转换的PHP论坛前,请先修复密码,详情请见<A href="http://www.cn-dos.net/forum/announcement.php?id=2#2">论坛公告</A>。</TD></TR>
<TR>
<TR>
<TD width="21%" bgColor=#f8f9fc>用户名(必填):</TD>
<TD bgColor=#ffffff><INPUT style="BACKGROUND: #ffffcc" tabIndex=1 maxLength=40 size=25 name=username> &nbsp;<SPAN class=smalltxt><A href="register.php">立即注册</A></SPAN></TD></TR>
<TR>
<TD bgColor=#f8f9fc>密码(必填):</TD>
<TD bgColor=#ffffff><INPUT style="BACKGROUND: #ffffcc" tabIndex=2 type=password size=25 value="" name=password> &nbsp;<SPAN class=smalltxt><A href="member.php?action=lostpasswd">忘记密码</A></SPAN></TD></TR>
----------------------------------------------------------------------------------------------------------

用curl登陆cn-dos论坛
curl -d "username=ngd&password=cndos" http://www.cn-dos.net/forum/logging.php?action=login
顺带提一下直接在浏览器中打开并登陆可以使用下面的代码
http://www.cn-dos.net/forum/logging.php?action=login&username=ngd&password=cndos&loginsubmit=.
将登陆后的cookie保存在6dzonecookie.txt中
curl -c 6dzonecookie.txt
使用cookie文件
curl -b 6dzonecookie.txt
伪装成IE浏览器
curl -A "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.01)"
合起来就是
curl -c 6dzonecookie.txt -A "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.01)" -d "username=dddddd6&pwd=cndos" http://www.6dzone.com/user/f_login.asp>nul
wget最简单的用法
wget http://www.cn-dos.net/forum/images/default/logo.gif
我这网络不太稳定,网速超慢,再多加一些参数
wget -t 8 -w 3 -T 30 -c -N
其他的没什么好说的,主要是sed的用法,再来一个for嵌套循环就OK了。

全部代码:
@echo off
rem code by 拟谷盗 for download 6dzone photo.

curl -c 6dzonecookie.txt -A "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.01)" -d "username=dddddd6&pwd=cndos" http://www.6dzone.com/user/f_login.asp>nul

for /f "delims=" %%a in ('sed "/photo/!d;s/[^\x22]*\x22//;s/\x22.*//" bookmark.htm') do (
    for /f "usebackq delims=" %%b in (`curl %%a ^| sed "/pic_id/!d;s/[^\x22]*\x22//;s/\x22.*//;s/photo.asp/pic.asp/g;s/\/photo/http:\/\/www.6dzone.com&/g"`) do (
        curl -b 6dzonecookie.txt -A "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.01)" %%b | sed "/http:\/\/.*jpg/!d;s/.*http/http/g;s/jpg.*/jpg/g" >>picurl.list
        wget -t 8 -w 3 -T 30 -c -N -i picurl.list
        del picurl.list
    )
)
del 6dzonecookie.txt
exit/b
粗略看了一下,写的很乱,暂时就这样了,有时间再整理整理。
另外代码也不够简洁,哪位达人再帮忙改改,以后下载网页图片就方便多了!

curl+wget+sed+bat文件 下载
http://upload.cn-dos.net/img/095.rar
解压后运行 bat文件即可下载图片

[ Last edited by ngd on 2008-3-15 at 02:05 PM ]
作者: plp626     时间: 2008-3-14 18:21
对wget curl正在学习中,有楼主的这样的帖子做样例受益匪浅
在此加分鼓励楼主下次奉献

[ Last edited by plp626 on 2008-3-14 at 06:41 PM ]
作者: plp626     时间: 2008-3-14 19:51
请教楼主:(我想写个批量下载歌曲的batch.)

baidu里的mp3歌曲的url地址好像是加密的,以前论坛里vkill发过一个批量下载baidu歌曲的帖子,(测试始终没成功.)没弄懂
比如在百度搜个"不得不爱"
然后在源文件里找到第三个歌曲备选项地址为:
http://www.yantaiblog.net/UploadFiles/2007-7/aGhmbGtmbGsx.mp3
而实际链接地址是:
http://www.yantaiblog.net/UploadFiles/2007-7/76386053.mp3
用ctrl+f在整个源文件里没找到任何76386053字符,

请楼主指点迷津,怎么直接得到这个链接地址
谢谢! 感激!
作者: ngd     时间: 2008-3-14 23:30
刚刚我还以为是 XX网站用了 VirtualWall防盗链技术
原来是百度自己的加密算法,直接从搜索结果中找实际地址好像行不通。

还得继续从搜索出的结果中找个链接再爬一次,不过链接地址太长而且又有一大堆符号,用curl好像不行,可以用 wget "url" -O file 生成一个临时文件,再到这个临时文件中找出mp3的实际地址。
wget -O tmp.htm "http://220.181.38.82/m?ct=134217728&tn=baidusg,不得不爱  &word=mp3,http://www.yantaiblog.net/UploadFiles/2007-7/aGhmbGtmbGsx.mp3,,[%B2%BB%B5%C3%B2%BB%B0%AE]&si=%B2%BB%B5%C3%B2%BB%B0%AE;;%C5%CB%E7%E2%B0%D8;;51913;;51913&lm=16777216"

sed "/www.*mp3/!d;s/.*www/http:\/\/www/;s/mp3.*/mp3/" tmp.htm
你可以试一试 这个虽然麻烦了一点 但还是行得通的!look



期盼早日见到兄的程序,谨祝万事顺利!
作者: suntb     时间: 2008-3-14 23:45
用好了还真不是一般的强大
作者: plp626     时间: 2008-3-14 23:47
谢谢!
虽然基本功还很差,但有兄提供的思路我对此就很有信心,对wget还不熟悉,
继续学习吧,我相信功到自然成...
作者: ngd     时间: 2008-3-15 00:16
o(∩_∩)o...共同进步吧
难得见到志同道合的朋友,我们追求的都是 自由、开放、共享!
感觉论坛中不少用户只是为了问问题才注册的,而且好像也没有搜索的习惯~_~

另外好像见到兄在统计 论坛中的学生人数
在此报到一声

中国的教育总让人感到愤慨!上大学总不知道自己应该做什么,所有我所接触的课程我都不明白以后工作中怎么用,对我来说,要是不知道这样做能实现什么的话那就没有学的必要了,还是到这样一个论坛逛逛不错!
作者: plp626     时间: 2008-3-15 03:09
o(∩_∩)o... 知音难觅,能聊到一起就是缘分.

快要毕业了,才深知学生的幸福...感慨也没用了.
刚上大学也许不知到该干什么,到知道该干什么时, 时间不允许了,所以多学有益.

人生没有回头路, 希望兄台 大学时光 可以留下巨人的脚印^_^

                       oooO.............  
                      (....)... Oooo...  
                      .\..(.....(.....)...  
                      ..\_)..... )../....  
                      .......... (_/.....  
                      oooO.............  
                      (....)... Oooo...  
                      .\..(.....(.....)...  
                      ..\_)..... )../....  
                      .......... (_/.....  
                                oooO.............  
                                (....)... Oooo...  
                                .\..(.....(.....)...  
                                ..\_)..... )../....  
                                .......... (_/.....  
                                          oooO.............  
                                          (....)... Oooo...  
                                          .\..(.....(.....)...  
                                          ..\_)..... )../....  
                                          .......... (_/.....  
                                                    oooO.............  
                                                    (....)... Oooo...  
                                                    .\..(.....(.....)...  
                                                    ..\_)..... )../....  
                                                    .......... (_/.....  
                                                              oooO.............  
                                                              (....)... Oooo...  
                                                              .\..(.....(.....)...  
                                                              ..\_)..... )../....  
                                                              .......... (_/.....  
                                                                        oooO.............  
                                                                        (....)... Oooo...  
                                                                        .\..(.....(.....)...  
                                                                        ..\_)..... )../....  
                                                                        .......... (_/.....  
                                                                                  oooO.............  
                                                                                  (....)... Oooo...  
                                                                                  .\..(.....(.....)...  
                                                                                  ..\_)..... )../....  
                                                                                  .......... (_/.....  
                                                                                            oooO.............  
                                                                                            (....)... Oooo...  
                                                                                            .\..(.....(.....)...  
                                                                                            ..\_)..... )../....  
                                                                                            .......... (_/.....  
                                                                                                      oooO.............  
                                                                                                      (....)... Oooo...  
                                                                                                      .\..(.....(.....)...  
                                                                                                      ..\_)..... )../....  
                                                                                                      .......... (_/.....

[ Last edited by plp626 on 2008-3-15 at 03:11 AM ]
作者: knoppix7     时间: 2008-3-15 11:49
直接搜索定位 "歌曲出处:",它后面的就是URL了
作者: wanlf     时间: 2008-3-15 11:54
太强了~~~~~~
作者: knoppix7     时间: 2008-3-15 12:01
明白了.
直接
http://mp3.baidu.com/u?u=加密后的地址
用curl/wget直接下就可以了




然后来自CSDN的解密方法(既然百度自己能解密。就不用自己写了把.)
#!/bin/sh   
  #   Author   Liang   
  #   Modified   at   June   14   2004   
  #   
  rm   mp3.list   html.list   link.list   mp3topsong.html   
  wget   http://list.mp3.baidu.com/topso/mp3topsong.html   
  cat   mp3topsong.html   |   tr   \"   \\n   |   grep   htm$   >html.list   
   
  CC=1   
  for   VAL   in   `cat   html.list`   
  do   
  wget   http://list.mp3.baidu.com/topso/$VAL   -O   $CC.html   
   
  cat   $CC.html   |   tr   \"   \\n   |   grep   mp3\$   |   grep   http   |   head   -1   >>   mp3.list   
  echo   -ne   "$CC   "   >>   link.list   
  cat   $CC.html   |   tr   \"   \\n   |   grep   mp3\$   |   grep   http   |   head   -1   >>   link.list   
   
   
  CC=`expr   $CC   +   1`   
   
  done   
   
  CC=1   
  for   VAL   in   `cat   mp3.list`   
  do   
   
  echo   $CC   
  wget   $VAL   -O   $CC.mp3   
  echo   $VAL   
   
  CC=`expr   $CC   +   1`   
   
  done   
   
  more   mp3topsong.html   |   sed   "s/target=_blank/\\n/g"   |   grep   ^\>   |   grep   href   |   cut   -f1   -d\<   |   cut   -f2   -d\>   |grep   ^[0-9]   >   name.l   
  ist   
   
  CC=1   
  while   [   $CC   -le   600   ]   
  do   
  NAME=`grep   ^$CC'   '   name.list   |   gawk   '{print   $2}'`   
  LINK=`grep   ^$CC'   '   link.list   |   gawk   '{print   $2}'`   
   
  echo   $NAME   $LINK   
  CC=`expr   $CC   +   1`   
  done
作者: ngd     时间: 2008-3-15 21:01


  Quote:
直接搜索定位 "歌曲出处:",它后面的就是URL了

无语

  Quote:
明白了.直接 http://mp3.baidu.com/u?u=加密后的地址
用curl/wget直接下就可以了

LS 试过成功了吗!?

  Quote:
然后来自CSDN的解密方法(既然百度自己能解密。就不用自己写了把.)

能写出解密算法那就最好了。

刚看到这段bash代码还有点兴奋,本打算将其“翻译”成cmd batch,借以品味一下这两种shell之间的差别。
结果LS又让人失望了,第3行就不对头了(不包括注释行、空行),毕竟是2004的代码,早就不管用了,3~17行完成了mp3下载功能 但之间没有什么解密算法啊。~_~ !!
LS 可看过代码?!

[ Last edited by ngd on 2008-3-16 at 11:29 AM ]
作者: ngd     时间: 2008-3-15 21:12


  Quote:
Originally posted by plp626 at 2008-3-15 03:09:
o(∩_∩)o... 知音难觅,能聊到一起就是缘分.

到知道该干什么时, 时间不 ...

恭喜兄找到了学习和生活的方向感o(∩_∩)o...


[ Last edited by ngd on 2008-3-15 at 09:15 PM ]
作者: knoppix7     时间: 2008-3-16 19:00
明白了.直接 http://mp3.baidu.com/u?u=加密后的地址
用curl/wget直接下就可以了


试过成功.
作者: ngd     时间: 2008-3-17 00:33


  Quote:
Originally posted by knoppix7 at 2008-3-16 19:00:
明白了.直接 http://mp3.baidu.com/u?u=加密后的地址
用curl/wget直接下就可以了
试过成功.

成功下载了 error.html
作者: ngd     时间: 2008-3-17 00:48    标题: curl和sed的问题


curl "http://220.181.38.82/m?ct=134217728&tn=baidusg,不得不爱  &word=mp3,http://www.yantaiblog.net/UploadFiles/2007-7/aGhmbGtmbGsx.mp3,,[%B2%BB%B5%C3%B2%BB%B0%AE]&si=%B2%BB%B5%C3%B2%BB%B0%AE;;%C5%CB%E7%E2%B0%D8;;51913;;51913&lm=16777216"
curl: (3) [globbing] illegal character in range specification at pos 132
总感觉curl在某些方面有很多缺陷,为何出现这样的情况?
有时 url中 有 & 字符时必需使用在 & 前加转义字符,而有些时候却不需要,为何?
curl http://list.mp3.baidu.com/topso/mp3topsong.html | sed "s/\x22/\xa/g;/baidump3/!d"

curl http://list.mp3.baidu.com/topso/mp3topsong.html | sed "s/\x22/\xa/g" | sed "/baidump3/!d"
这2个命令执行的结果为何不一样?
作者: junchen2     时间: 2008-3-17 13:53
总感觉curl在某些方面有很多缺陷,为何出现这样的情况?
有时 url中 有 & 字符时必需使用在 & 前加转义字符,而有些时候却不需要,为何?
--------------------------
1我想应该跟CMD.EXE语法分析有关,cmd碰到&它认为是一个语句的结束。


这2个命令执行的结果为何不一样?
--------------------------------------------
2。sed 是以行为单位进行读取数据的。大概过程是提取curl里的一行数据读取后的内容存放在pattern space。经过 sed "s/\x22/\xa/g" 处理后,貌似生成了多行,实际上它仍然存储在pattern space,作为一个未加工完的半成品,/baidump3/!d 再对其进行处理。
反正记住
sed对它输入的数据是采取一行行读的,输入可能是以管道,文件,进程中的通信等方式。
pattern space的内容是不会以 输入 那样对待的。

[ Last edited by junchen2 on 2008-3-17 at 01:54 PM ]
作者: vkill     时间: 2008-3-18 16:24
像from提交的网页用 wget 和 curl 都可以解决,两个都试下就好了
作者: knoppix7     时间: 2008-3-18 19:02
D:\>wget "http://mp3.baidu.com/u?u=http://www.yantaiblog.net/UploadFiles/2007-7/
aGhmbGtmbGsx.mp3"
--17:52:54--  http://mp3.baidu.com/u?u=http:// ... net/UploadFiles/200
7-7/aGhmbGtmbGsx.mp3
           => `u@u=http:%2F%2Fwww.yantaiblog.net%2FUploadFiles%2F2007-7%2FaGhmbG
tmbGsx.mp3'
Resolving mp3.baidu.com... done.
Connecting to mp3.baidu.com[61.135.163.222]:80... connected.
HTTP request sent, awaiting response... 302 Object moved
Location: http://www.yantaiblog.net/UploadFiles/2007-7/76386053.mp3 [following]
--17:52:55--  http://www.yantaiblog.net/UploadFiles/2007-7/76386053.mp3
           => `76386053.mp3'
Resolving www.yantaiblog.net... done.
Connecting to www.yantaiblog.net[222.135.144.5]:80... connected.
HTTP request sent, awaiting response... 200 OK
Length: 4,505,113 [audio/mpeg]

0% [                                     ] 19,433         9.56K/s    ETA 07:38
作者: zerocq     时间: 2008-3-18 19:12
楼主能否解释一下curl的keepalive选项该在什么情况下使用,如何使用

谢谢
作者: ngd     时间: 2008-3-18 21:07


  Quote:
Originally posted by zerocq at 2008-3-18 19:12:
楼主能否解释一下curl的keepalive选项该在什么情况下使用,如何使用

谢谢

没用过 keepalive方式的
参考
curl --manual
http://curl.haxx.se/docs/manpage.html

--keepalive-time <seconds>

This option sets the time a connection needs to remain idle before sending keepalive probes and the time between individual keepalive probes. It is currently effective on operating systems offering the TCP_KEEPIDLE and TCP_KEEPINTVL socket options (meaning Linux, recent AIX, HP-UX and more). This option has no effect if --no-keepalive is used. (Added in 7.18.0)

If this option is used multiple times, the last occurrence sets the amount.

[ Last edited by ngd on 2008-4-19 at 05:15 PM ]
作者: ngd     时间: 2008-3-18 21:46


  Quote:
Originally posted by knoppix7 at 2008-3-18 19:02:
D:\>wget "http://mp3.baidu.com/u?u=http://www.yantaiblog.net/UploadFiles/2007-7/
aGhmbGtmbGsx.mp3"
--17:52:54--  [url]http://mp3.baidu.com/u?u=http://www.yantaiblog.net/UploadFiles/2 ...

奇怪!wget 1.10.2
D:\>wget "http://mp3.baidu.com/u?u=http://www.yantaiblog.net/UploadFiles/2007-7/
aGhmbGtmbGsx.mp3"
--20:32:27--  http://mp3.baidu.com/u?u=http:// ... net/UploadFiles/200
7-7/aGhmbGtmbGsx.mp3
           => `u@u=http%3A%2F%2Fwww.yantaiblog.net%2FUploadFiles%2F2007-7%2FaGhm
bGtmbGsx.mp3'
Resolving mp3.baidu.com... 220.181.38.70
Connecting to mp3.baidu.com|220.181.38.70|:80... connected.
HTTP request sent, awaiting response... 302 Found
Location: http://www.baidu.com/search/error.html [following]
--20:32:28--  http://www.baidu.com/search/error.html
           => `error.html'
Resolving www.baidu.com... 220.181.6.6, 220.181.37.55
Connecting to www.baidu.com|220.181.6.6|:80... connected.
HTTP request sent, awaiting response... 200 OK
Length: 2,699 (2.6K) [text/html]

100%[====================================>] 2,699         --.--K/s

20:32:38 (52.95 MB/s) - `error.html' saved [2699/2699]
作者: knoppix7     时间: 2008-3-19 19:41
D:\>wget --help
GNU Wget 1.8.2, a non-interactive network retriever.
作者: kioskboy     时间: 2008-8-8 11:38
curl -d "UserName=***&Password=******" http://www.netyi.net/jsLoginStatus.aspx
怎么登陆不了