Python 3 多线程下载百度图片搜索结果 转载来至:http://lovenight.github.io/2015/11/15/Python-3-%E5%A4%9A%E7%BA%BF%E7%A8%8B%E4%B8%8B%E8%BD%BD%E7%99%BE%E5%BA%A6%E5%9B%BE%E7%89%87%E6%90%9C%E7%B4%A2%E7%BB%93%E6%9E%9C/ 下载简单页面 查看网页源码,发现同一张图片有四种网址:
"thumbURL": "http://img1.imgtn.bdimg.com/it/u=757023778 ,2840825931 &fm=21&gp=0.jpg","middleURL": "http://img1.imgtn.bdimg.com/it/u=757023778 ,2840825931 &fm=21&gp=0.jpg","hoverURL": "http://img1.imgtn.bdimg.com/it/u=757023778 ,2840825931 &fm=23&gp=0.jpg","objURL": "http://imgsrc.baidu.com/forum/w=580/sign=b3bcc2f88a5494 ee87220f111 df4e0e1/78 fed309b3de9c82913 abac86a81800a18 d84344.jpg",
经测试,前三种都有反爬虫措施,用浏览器可以打开,但是刷新一次就403 Forbidden。用爬虫获取不到图片。
第四种objURL是指图片的源网址,获取该网址会出现三种情况:
正常。继续下载 403 Forbidden。用continue跳过。 出现异常。用try except处理。 代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 import requestsimport reimport osurl = r'http://image.baidu.com/search/index?tn=baiduimage&ipn=r&ct=201326592&cl=2&lm=-1&st=-1&fm=detail&fr=&sf=1&fmq=1447473655189_R&pv=&ic=0&nc=1&z=&se=&showtab=0&fb=0&width=&height=&face=0&istype=2&ie=utf-8&word=%E9%95%BF%E8%80%85%E8%9B%A4' dirpath = r'F:\img' html = requests.get(url).text urls = re.findall(r'"objURL":"(.*?)"' , html) if not os.path.isdir(dirpath): os.mkdir(dirpath) index = 1 for url in urls: print("Downloading:" , url) try : res = requests.get(url) if str(res.status_code)[0 ] == "4" : print("未下载成功:" , url) continue except Exception as e: print("未下载成功:" , url) filename = os.path.join(dirpath, str(index) + ".jpg" ) with open(filename, 'wb' ) as f: f.write(res.content) index += 1 print("下载结束,一共 %s 张图片" % index)
Exciting!
加载更多图片 但是上面的代码还有不足,当我们在网页中下拉时,百度会继续加载更多图片。需要再完善一下代码。
打开Chrome,按F12,切换到Network标签,然后将网页向下拉。这时浏览器地址栏的网址并没有改变,而网页中的图片却一张张增加,说明网页在后台与服务器交互数据。警察蜀黍,就是这家伙:
xhr全称XMLHttpRequest,详细介绍见百度:XMLHTTPRequest_百度百科
点开看看:
这么长一串网址,没有头绪。下拉网页,再抓一个xhr,对比一下它们的Request URL,使用在线文字对比工具:文本比较
URL末尾有三处变化,最后一项看上去是时间戳,经过测试,直接把它删了也没事。
那么只需要研究pn
和gsm
值。继续下拉,到底的时候点加载更多图片
,多抓几个对比一下URL的末尾部分:
pn=120 &rn=60 &gsm=78 pn=180 &rn=60 &gsm=b4pn=240 &rn=60 &gsm=f0pn=300 &rn=60 &gsm=12 cpn=360 &rn=60 &gsm=168
pn
是一个60为步长的等差数列。gsm
看上去是16进制,转换成十进制,发现它就是pn
值,试了也可以删掉。
经测试,rn
是步长值,最大只能取60,填入大于60的数,仍然以60为步长。如果删了rn
,则步长值变为30。pn
是图片编号,从0开始。
现在已经删了时间戳和gsm
两项了,能不能让网址再短一点?继续观察,注意到:
&se=&tab=&width =&height =
这几项没指定值,肯定没用,把没值的都删了。
再看看这两项:
queryWord=% E9 % 95 % BF% E8 % 80 % 85 % E8 % 9 B% A4 word=% E9 % 95 % BF% E8 % 80 % 85 % E8 % 9 B% A4
这就是我们本次搜索的关键词。网址中的中文会被编码成UTF-8,每个中文3个字节,每个字节前加上%号。编码和解码方法如下:
那么,我们可以写出指定关键词需要请求的所有网址:
1 2 3 4 5 6 7 8 import itertoolsimport urllibdef buildUrls (word) : word = urllib.parse.quote(word) url = r"http://image.baidu.com/search/acjson?tn=resultjson_com&ipn=rj&ct=201326592&fp=result&queryWord={word}&cl=2&lm=-1&ie=utf-8&oe=utf-8&st=-1&ic=0&word={word}&face=0&istype=2nc=1&pn={pn}&rn=60" urls = (url.format(word=word, pn=x) for x in itertools.count(start=0 , step=60 )) return urls
上面的代码中,itertools.count(start=0, step=60)表示一个从0开始,60为步长值的无限等差数列。 把这个数列的数字分别填入url作为pn值,就得到一个无限容量的url生成器,注意生成器必须用圆括号,如果写成中括号就成了列表,程序会在这一步无限执行下去。
下面开始解析每次获取的数据。我们点开看看,返回的是一串json数据。
纳尼,这个objURL怎么不是HTTP开头的。试了几种方法都没成功,Google一下,找到这个:百度图片url解码
OK,既然明白了原理,我们写一个Python版的解密实现:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 """解码百度图片搜索json中传递的url 抓包可以获取加载更多图片时,服务器向网址传输的json。 其中originURL是特殊的字符串 解码前: ippr_z2C$qAzdH3FAzdH3Ffl_z&e3Bftgwt42_z&e3BvgAzdH3F4omlaAzdH3Faa8W3ZyEpymRmx3Y1p7bb&mla 解码后: http://s9.sinaimg.cn/mw690/001WjZyEty6R6xjYdtu88&690 使用下面两张映射表进行解码。 """ str_table = { '_z2C$q' : ':' , '_z&e3B' : '.' , 'AzdH3F' : '/' } char_table = { 'w' : 'a' , 'k' : 'b' , 'v' : 'c' , '1' : 'd' , 'j' : 'e' , 'u' : 'f' , '2' : 'g' , 'i' : 'h' , 't' : 'i' , '3' : 'j' , 'h' : 'k' , 's' : 'l' , '4' : 'm' , 'g' : 'n' , '5' : 'o' , 'r' : 'p' , 'q' : 'q' , '6' : 'r' , 'f' : 's' , 'p' : 't' , '7' : 'u' , 'e' : 'v' , 'o' : 'w' , '8' : '1' , 'd' : '2' , 'n' : '3' , '9' : '4' , 'c' : '5' , 'm' : '6' , '0' : '7' , 'b' : '8' , 'l' : '9' , 'a' : '0' } char_table = {ord(key): ord(value) for key, value in char_table.items()} def decode (url) : for key, value in str_table.items(): url = url.replace(key, value) return url.translate(char_table) if __name__ == '__main__' : url = r"ippr_z2C$qAzdH3FAzdH3Ffl_z&e3Bftgwt42_z&e3BvgAzdH3F4omlaAzdH3Faa8W3ZyEpymRmx3Y1p7bb&mla" print(decode(url))
测试成功!
再从JSON字符串中找出所有的originURL:
1 2 re_url = re.compile(r'"objURL":"(.*?)"' ) imgs = re_url.findall(html)
格式化JSON推荐使用Chrome的JSON handle插件
单线程下载脚本 整理一下流程:
生成网址列表 发送HTTP请求获取json数据 解析数据得到网址 下载 整合一下上面的代码,可以写出单线程的下载脚本:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 import jsonimport itertoolsimport urllibimport requestsimport osimport reimport sysstr_table = { '_z2C$q' : ':' , '_z&e3B' : '.' , 'AzdH3F' : '/' } char_table = { 'w' : 'a' , 'k' : 'b' , 'v' : 'c' , '1' : 'd' , 'j' : 'e' , 'u' : 'f' , '2' : 'g' , 'i' : 'h' , 't' : 'i' , '3' : 'j' , 'h' : 'k' , 's' : 'l' , '4' : 'm' , 'g' : 'n' , '5' : 'o' , 'r' : 'p' , 'q' : 'q' , '6' : 'r' , 'f' : 's' , 'p' : 't' , '7' : 'u' , 'e' : 'v' , 'o' : 'w' , '8' : '1' , 'd' : '2' , 'n' : '3' , '9' : '4' , 'c' : '5' , 'm' : '6' , '0' : '7' , 'b' : '8' , 'l' : '9' , 'a' : '0' } char_table = {ord(key): ord(value) for key, value in char_table.items()} def decode (url) : for key, value in str_table.items(): url = url.replace(key, value) return url.translate(char_table) def buildUrls (word) : word = urllib.parse.quote(word) url = r"http://image.baidu.com/search/acjson?tn=resultjson_com&ipn=rj&ct=201326592&fp=result&queryWord={word}&cl=2&lm=-1&ie=utf-8&oe=utf-8&st=-1&ic=0&word={word}&face=0&istype=2nc=1&pn={pn}&rn=60" urls = (url.format(word=word, pn=x) for x in itertools.count(start=0 , step=60 )) return urls re_url = re.compile(r'"objURL":"(.*?)"' ) def resolveImgUrl (html) : imgUrls = [decode(x) for x in re_url.findall(html)] return imgUrls def downImg (imgUrl, dirpath, imgName) : filename = os.path.join(dirpath, imgName) try : res = requests.get(imgUrl, timeout=15 ) if str(res.status_code)[0 ] == "4" : print(str(res.status_code), ":" , imgUrl) return False except Exception as e: print("抛出异常:" , imgUrl) print(e) return False with open(filename, "wb" ) as f: f.write(res.content) return True def mkDir (dirName) : dirpath = os.path.join(sys.path[0 ], dirName) if not os.path.exists(dirpath): os.mkdir(dirpath) return dirpath if __name__ == '__main__' : print("欢迎使用百度图片下载脚本!\n目前仅支持单个关键词。" ) print("下载结果保存在脚本目录下的results文件夹中。" ) print("=" * 50 ) word = input("请输入你要下载的图片关键词:\n" ) dirpath = mkDir("results" ) urls = buildUrls(word) index = 0 for url in urls: print("正在请求:" , url) html = requests.get(url, timeout=10 ).content.decode('utf-8' ) imgUrls = resolveImgUrl(html) if len(imgUrls) == 0 : break for url in imgUrls: if downImg(url, dirpath, str(index) + ".jpg" ): index += 1 print("已下载 %s 张" % index)
执行脚本:
查看同目录下的results文件夹,又看到了亲切的「他」。
多线程下载脚本 上面的代码仍然有改进空间:
从JSON数据看,该关键词相关的图片有一千多张,单线程下载太慢了,时间都花在网络和硬盘IO上。加上多线程可以大大提升效率。 既然1中已经获取到图片总数,那么网址的无限容量生成器可以改成list,方便添加多线程。 多线程一直没学好,想不到更优雅的写法,大家将就看一下吧,欢迎提出改进建议。
百度图片下载脚本之多线程版:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 import urllibimport requestsimport osimport reimport sysimport timeimport threadingfrom datetime import datetime as dtfrom multiprocessing.dummy import Poolfrom multiprocessing import Queueclass BaiduImgDownloader (object) : """百度图片下载工具,目前只支持单个关键词""" str_table = { '_z2C$q' : ':' , '_z&e3B' : '.' , 'AzdH3F' : '/' } char_table = { 'w' : 'a' , 'k' : 'b' , 'v' : 'c' , '1' : 'd' , 'j' : 'e' , 'u' : 'f' , '2' : 'g' , 'i' : 'h' , 't' : 'i' , '3' : 'j' , 'h' : 'k' , 's' : 'l' , '4' : 'm' , 'g' : 'n' , '5' : 'o' , 'r' : 'p' , 'q' : 'q' , '6' : 'r' , 'f' : 's' , 'p' : 't' , '7' : 'u' , 'e' : 'v' , 'o' : 'w' , '8' : '1' , 'd' : '2' , 'n' : '3' , '9' : '4' , 'c' : '5' , 'm' : '6' , '0' : '7' , 'b' : '8' , 'l' : '9' , 'a' : '0' } re_objURL = re.compile(r'"objURL":"(.*?)".*?"type":"(.*?)"' ) re_downNum = re.compile(r"已下载\s(\d+)\s张图片" ) headers = { "User-Agent" : "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/46.0.2490.71 Safari/537.36" , "Accept-Encoding" : "gzip, deflate, sdch" , } def __init__ (self, word, dirpath=None, processNum=30 ) : if " " in word: raise AttributeError("本脚本仅支持单个关键字" ) self.word = word self.char_table = {ord(key): ord(value) for key, value in BaiduImgDownloader.char_table.items()} if not dirpath: dirpath = os.path.join(sys.path[0 ], 'results' ) self.dirpath = dirpath self.jsonUrlFile = os.path.join(sys.path[0 ], 'jsonUrl.txt' ) self.logFile = os.path.join(sys.path[0 ], 'logInfo.txt' ) self.errorFile = os.path.join(sys.path[0 ], 'errorUrl.txt' ) if os.path.exists(self.errorFile): os.remove(self.errorFile) if not os.path.exists(self.dirpath): os.mkdir(self.dirpath) self.pool = Pool(30 ) self.session = requests.Session() self.session.headers = BaiduImgDownloader.headers self.queue = Queue() self.messageQueue = Queue() self.index = 0 self.promptNum = 10 self.lock = threading.Lock() self.delay = 1.5 self.QUIT = "QUIT" self.printPrefix = "**" def start (self) : t = threading.Thread(target=self.__log) t.setDaemon(True ) t.start() self.messageQueue.put(self.printPrefix + "脚本开始执行" ) start_time = dt.now() urls = self.__buildUrls() self.messageQueue.put(self.printPrefix + "已获取 %s 个Json请求网址" % len(urls)) self.pool.map(self.__resolveImgUrl, urls) while self.queue.qsize(): imgs = self.queue.get() self.pool.map_async(self.__downImg, imgs) self.pool.close() self.pool.join() self.messageQueue.put(self.printPrefix + "下载完成!已下载 %s 张图片,总用时 %s" % (self.index, dt.now() - start_time)) self.messageQueue.put(self.printPrefix + "请到 %s 查看结果!" % self.dirpath) self.messageQueue.put(self.printPrefix + "错误信息保存在 %s" % self.errorFile) self.messageQueue.put(self.QUIT) def __log (self) : """控制台输出,加锁以免被多线程打乱""" with open(self.logFile, "w" , encoding = "utf-8" ) as f: while True : message = self.messageQueue.get() if message == self.QUIT: break message = str(dt.now()) + " " + message if self.printPrefix in message: print(message) elif "已下载" in message: downNum = self.re_downNum.findall(message) if downNum and int(downNum[0 ]) % self.promptNum == 0 : print(message) f.write(message + '\n' ) f.flush() def __getIndex (self) : """获取文件编号""" self.lock.acquire() try : return self.index finally : self.index += 1 self.lock.release() def decode (self, url) : """解码图片URL 解码前: ippr_z2C$qAzdH3FAzdH3Ffl_z&e3Bftgwt42_z&e3BvgAzdH3F4omlaAzdH3Faa8W3ZyEpymRmx3Y1p7bb&mla 解码后: http://s9.sinaimg.cn/mw690/001WjZyEty6R6xjYdtu88&690 """ for key, value in self.str_table.items(): url = url.replace(key, value) return url.translate(self.char_table) def __buildUrls (self) : """json请求网址生成器""" word = urllib.parse.quote(self.word) url = r"http://image.baidu.com/search/acjson?tn=resultjson_com&ipn=rj&ct=201326592&fp=result&queryWord={word}&cl=2&lm=-1&ie=utf-8&oe=utf-8&st=-1&ic=0&word={word}&face=0&istype=2nc=1&pn={pn}&rn=60" time.sleep(self.delay) html = self.session.get(url.format(word=word, pn=0 ), timeout = 15 ).content.decode('utf-8' ) results = re.findall(r'"displayNum":(\d+),' , html) maxNum = int(results[0 ]) if results else 0 urls = [url.format(word=word, pn=x) for x in range(0 , maxNum + 1 , 60 )] with open(self.jsonUrlFile, "w" , encoding="utf-8" ) as f: for url in urls: f.write(url + "\n" ) return urls def __resolveImgUrl (self, url) : """从指定网页中解析出图片URL""" time.sleep(self.delay) html = self.session.get(url, timeout = 15 ).content.decode('utf-8' ) datas = self.re_objURL.findall(html) imgs = [Image(self.decode(x[0 ]), x[1 ]) for x in datas] self.messageQueue.put(self.printPrefix + "已解析出 %s 个图片网址" % len(imgs)) self.queue.put(imgs) def __downImg (self, img) : """下载单张图片,传入的是Image对象""" imgUrl = img.url try : time.sleep(self.delay) res = self.session.get(imgUrl, timeout = 15 ) message = None if str(res.status_code)[0 ] == "4" : message = "\n%s: %s" % (res.status_code, imgUrl) elif "text/html" in res.headers["Content-Type" ]: message = "\n无法打开图片: %s" % imgUrl except Exception as e: message = "\n抛出异常: %s\n%s" % (imgUrl, str(e)) finally : if message: self.messageQueue.put(message) self.__saveError(message) return index = self.__getIndex() self.messageQueue.put("已下载 %s 张图片:%s" % (index + 1 , imgUrl)) filename = os.path.join(self.dirpath, str(index) + "." + img.type) with open(filename, "wb" ) as f: f.write(res.content) def __saveError (self, message) : self.lock.acquire() try : with open(self.errorFile, "a" , encoding="utf-8" ) as f: f.write(message) finally : self.lock.release() class Image (object) : """图片类,保存图片信息""" def __init__ (self, url, type) : super(Image, self).__init__() self.url = url self.type = type if __name__ == '__main__' : print("欢迎使用百度图片下载脚本!\n目前仅支持单个关键词。" ) print("下载结果保存在脚本目录下的results文件夹中。" ) print("=" * 50 ) word = input("请输入你要下载的图片关键词:\n" ) down = BaiduImgDownloader(word) down.start()
执行脚本:
欢迎使用百度图片下载脚本!目前仅支持单个关键词。下载结果保存在脚本目录下的results文件夹中。==================================================请输入你要下载的图片关键词:长者蛤2015 -11 -15 19 :25 :11.726878 **脚本开始执行2015 -11 -15 19 :25 :16.292022 **已获取 20 个Json请求网址2015 -11 -15 19 :25 :17.885767 **已解析出 30 个图片网址2015 -11 -15 19 :25 :17.917020 **已解析出 60 个图片网址..........中间省略.....2015 -11 -15 19 :33 :31.726739 已下载 980 张图片:http:2015 -11 -15 19 :33 :32.695518 已下载 990 张图片:http:2015 -11 -15 19 :33 :45.473957 已下载 1000 张图片:http:2015 -11 -15 19 :33 :50.749544 **下载完成!已下载 1000 张图片,总用时 0 :08 :39.022666 2015 -11 -15 19 :33 :50.765169 **请到 F:\PythonWorkspace\Learn\results 查看结果!2015 -11 -15 19 :33 :50.858880 **错误信息保存在 F:\PythonWorkspace\Learn\errorUrl.txt
合租室友太多,平时网速很慢,经常连百度都打不开,要刷新多次。下午测试的时候可以2分钟下完,现在居然要近9分钟。
errorUrl.txt
的内容
无法打开图片: http:403 : http:无法打开图片: http:404 : http:抛出异常: http:HTTPConnectionPool (host='www.jzxzj.com' , port=80 ) : Max retries exceeded with url: /images/xs.jpg (Caused by NewConnectionError ('<requests.packages.urllib3.connection.HTTPConnection object at 0x0851FBB0>: Failed to establish a new connection: [Errno 11002] getaddrinfo failed' ,) )抛出异常: http:HTTPConnectionPool (host='static.acfun.mm111.net' , port=80 ) : Max retries exceeded with url: /h/image/20147 /846 b7553851b6edb2305c6b87f4aed71.jpg (Caused by NewConnectionError ('<requests.packages.urllib3.connection.HTTPConnection object at 0x0888B710>: Failed to establish a new connection: [Errno 11001] getaddrinfo failed' ,) )抛出异常: http:HTTPConnectionPool (host='static.acfun.mm111.net' , port=80 ) : Max retries exceeded with url: /h/image/2015 -0 -4 /23 ebeaf5-5130 -4072 -b90e-48 ce4d122ac8.jpg (Caused by NewConnectionError ('<requests.packages.urllib3.connection.HTTPConnection object at 0x0888F1F0>: Failed to establish a new connection: [Errno 11001] getaddrinfo failed' ,) )404 : http:无法打开图片: http:无法打开图片: http:.....
logInfo.txt
内容:
2015 -11 -15 19 :25 :11.726878 **脚本开始执行2015 -11 -15 19 :25 :16.292022 **已获取 20 个Json请求网址2015 -11 -15 19 :25 :17.885767 **已解析出 30 个图片网址2015 -11 -15 19 :25 :17.917020 **已解析出 60 个图片网址2015 -11 -15 19 :25 :17.948262 **已解析出 60 个图片网址2015 -11 -15 19 :25 :17.963895 **已解析出 60 个图片网址2015 -11 -15 19 :25 :17.995146 **已解析出 60 个图片网址2015 -11 -15 19 :25 :18.010769 **已解析出 60 个图片网址2015 -11 -15 19 :25 :18.057638 **已解析出 60 个图片网址2015 -11 -15 19 :25 :18.057638 **已解析出 60 个图片网址2015 -11 -15 19 :25 :18.073264 **已解析出 60 个图片网址2015 -11 -15 19 :25 :18.073264 **已解析出 60 个图片网址2015 -11 -15 19 :25 :18.088890 **已解析出 60 个图片网址2015 -11 -15 19 :25 :18.088890 **已解析出 60 个图片网址2015 -11 -15 19 :25 :18.104516 **已解析出 60 个图片网址2015 -11 -15 19 :25 :18.104516 **已解析出 60 个图片网址2015 -11 -15 19 :25 :18.104516 **已解析出 60 个图片网址2015 -11 -15 19 :25 :18.104516 **已解析出 60 个图片网址2015 -11 -15 19 :25 :18.245137 **已解析出 60 个图片网址2015 -11 -15 19 :25 :18.260764 **已解析出 60 个图片网址2015 -11 -15 19 :25 :18.260764 **已解析出 60 个图片网址2015 -11 -15 19 :25 :18.479555 **已解析出 60 个图片网址2015 -11 -15 19 :25 :27.532965 已下载 1 张图片:http:2015 -11 -15 19 :25 :29.084964 无法打开图片: http:2015 -11 -15 19 :25 :29.522473 已下载 2 张图片:http:2015 -11 -15 19 :25 :29.822650 已下载 3 张图片:http:2015 -11 -15 19 :25 :29.938687 已下载 4 张图片:http:....
仍然可以改进的地方:
如果要搜索多个关键词,buildUrls方法应该怎么改? 如果脚本中途意外结束(比如被熊孩子点了X),如何继续下载? 线程池中的线程数需要多次测试才能找到最优值。