BR图片下载器

BR图片下载器

Cover

Ultimate-NBA-Downloader,一包从小到大始终舍不得丢弃的玩具大杂烩。

历史回顾

对于常年混迹于体育类论坛、热爱体育的爱好者而言,搜集各类体育图片永远是一个无法避开的话题。当你看到网页上体育摄影所呈现出来的力量的美、决定胜负的精彩瞬间、令人黯然神伤的历史时刻、运动的人与自然所呈现的大和谐之时,右手根本停不下来——是的,右键,另存为,桌面。

自从互联网摆脱了电话线时代对于多媒体的掣肘,各式各样的多媒体表现形式层出不穷。图像、音频、视频、全景图、全景视频,甚至VR视频接踵而至,让人们能够足不出户便领略全世界各类体育活动、体育赛事的精彩瞬间。尤其是以美利坚为首的商业体育大国,这些多媒体手段极大地丰富了其宣传的手段,推进了其在全世界传播的进程。

对我个人而言,从最初的F1与勒芒赛车爱好者,到后来的NBA、NFL球迷,再到环法拥趸与迈入综合体育的大门,一路走来收图始终是一项不可忽视的重要任务。坦率地讲,个人自我感觉有点收图强迫症,每次看到体育运动的精彩瞬间,必定搜索枯“网”把各大站点搜个底儿掉,以寻找那爿封印了世间绝妙一瞬的精致容器。正如我喜欢拍人物与新闻题材的照片一般,收集这些体育图片就像收集时间的脚印,每每翻到它们时,脑海中或多或少会想起那些令人心潮澎湃感慨万千的时刻。想想当时的心情,想想当时的生活,别有一番滋味。对于那些最为精彩的体育时刻,看到一张好的照片,就像浑身过电打鸡血一样,一下子涌上许多肾上腺素,精神顿时抖擞起来。

如何才能更为高效地收集那些图片呢?从小到大我从未停止过自己的尝试。翻开往事的相册,抖落历史的尘埃,回忆起那些年扒图的日子吧。

手抓图时代

抓图,自然是在家里开通互联网以后的事情了。在那以前,我的所有互联网需求都在三个地方解决:爹的办公室、姐的笔记本、哥的写字台。

小时候最喜欢在各种汽车网站上搜集赛车的图片。那时候还没有高清大图的概念,凡是喜欢的汽车图,统统保存到本地。直到后来整理文件时自己才意识到,当时存了多少乱七八糟的图。

在那时,谷歌还没有封禁,首页大大的标志还是衬线字体的图片格式。搜图的一大途径就是打开谷歌图片,输入关键字,然后一张一张点进去看。嗬!我甚至能一下午都重复这同一件事儿。另一大途径就是百度图片了,不过我时常会被百度图片首页导流的“美女”标签代跑,一下午在电脑前的时光就此蹉跎……

家里很早就有电脑,但直到一段时间后才用上Windows XP。在那之前由于只有Windows 98 的安装盘,很长时间重装系统都是重装Windows 98 + Office 97的组合的。记不清是哪个版本的Excel里面还有个赛车小游戏。直到XP时代,电脑上的多媒体应用才多了起来,在Winamp、RealMediaPlayer和豪杰超级解霸的统治下诞生了千千静听与暴风影音这样的软件。头一次我发现电脑能够打开很多格式的视频了,听音乐也不用忍受难看的方块界面了,甚至vba模拟器可以跑到10倍速了。电脑全面进入酷睿与双核的时代,我也慢慢长大了。

工具箱时代

进入XP时代,乃至整个中学阶段,几乎都是IE 6陪我走过的。要不是新时代互联网浪潮的推动,我还不愿意换掉它哩。IE 6真的很经典,速度并不慢,虽说功能简单但用着顺手。后来发现了它的升级版——世界之窗。调用IE 内核用得飞起。当时的一大乐趣,就是到网上踅摸各类css模板,把自己的百度空间打扮的漂漂亮亮的,然后等着同学路过踩踩。

IE时代的各类浏览器辅助层出不穷,除了那些流氓的BHO插件栏以外,更多的是直接封装好的可执行文件,多是以易语言、VB6.0、按键精灵等奇形怪状的工具编纂而成的。犹记得被百度工具栏和AOL工具栏统治的四上巴浏览器框架、3721与hao123统治的浏览器首页。丁香鱼盗版瑞星是装机必备,同样还有暴风影音与EasyRecovery——当然,还有迅雷。当时的桌面上永远不变的是“网络图片”、“网络视频”、“全页保存”三大巨头,逻辑分区里还有“游戏截图”和“游戏录像”两大悍将。对于多媒体文件的掌控欲一下子膨胀到无以复加。截止到我把中学用的台式机重装Windows 7时,桌面上随手收集的图片视频文件多达10014个,242个文件夹,占用7.12G磁盘空间。

仍旧很喜欢搜集汽车图片,但随着知识的增长,买下一辆自己的356的希望越来越渺茫。😭 :cry:

开始爱好搜集篮球图片,从第一个认识的篮球运动员乔丹,到喜欢的球星小皇帝詹姆斯,逐渐胃口越来越大。

这个时候搜集图片不再全靠邮件另存为了。对于贴吧,我用过“绿易贴吧工具箱”;对于虎扑,我用过“虎扑相册下载工具”;对于其它满页是图的网站,我则使用世界之窗自带的全页图片嗅探筛选插件,只需点击记下,就可以选中页面中所有尺寸符合条件的图片,然后一件把这些图片保存到本地。不得不说,这个功能我非常喜欢,甚至直到如今Chrome中我还保留了类似的“Fatkun批量下载”插件。

通过最初级的自动化,我的存图大业比过去顺利得多,效率得到极大提升。然而,这样保存下来的图片有些问题,一是质量参差不齐,毕竟各个站点默认的图片分辨率不尽相同;二是文件名十分混乱——有些站点用图片原名作为路径还好,更多的像贴吧等论坛,图片文件名从来都是长串乱码,让人很难整理。最开始我还妄图手工分类整理,但面对指数增加的文件数量,最后只得作罢。期间,我想出各种歪招儿野路子来应对各种不同的情况,此处不表。总之,到最后装Windows 7的时候,我痛下决心,一定要改善这种刀耕火种的野蛮存图方法,让其变得可控而优雅。

F12时代

送走IE 9,迎来Chrome 36的最大收获,是我懂得了不用右键“查看网页源代码”,直接轻触F12即可打开控制台。我的抓图事业,也一步迈进了现代化的新时代。首先映入我眼帘的便是Flickr。右键无法保存?没关系,F12→Ctrl-F→jpg即可。Flickr上的图片质量大多非常不错,甚至有很多都是相机原图。在那短暂的年月里,我凭借F12存了不少图片。

另一大利器便是谷歌以图搜图与tineye为首的反向搜图引擎。过去,只能看见什么图存什么图;而现在,可以想要什么图去找什么图。只要找到任何分辨率版本,以图搜图总能得到不错的结果。凭借这两项“颠覆性”的新技术,我的存图武器库极大地丰富了。

Flickr的图片质量一般都很不错,这套Broad Museum图集存下来的原图平均20MB以上

这张图稀有性不算强,却在我的存图生涯里具有里程碑式的意义。拿到这张图的大约9年以前,我得到过同一张图片的印刷版海报。现在,终于拿到了版权原图,不禁有些感慨。

当然,仅靠F12还不能完全概括这一时期的手段。还有两大方法在此提及一下。

“RESTful” 请求法

标题或许起得不对,但我想表达的是一种存图的方法,即获取图片可见链接后反推原始链接。思路不一而足,但思想都是统一的——倘若对方服务器上存有原图,且作为资源而非动作存在,那么一定能通过某种参数获得该图。所谓动作,囊括登录、验证、购买等行为。无需动作就能看到的图片,就有可能想办法找到原图。

最简单的情况便是直接出原图,这种情况多出现于静态网页——有时候会用缩略图占位,点击放大即可得到原图。稍复杂一些的是后端压缩后传输,再复杂的可伴随timestamp、cookie、token、key的验证。更复杂的就需要随机应变了——毕竟,如果对方不想让你访问某个路径,他有千百种方法设下层层阻拦,最简单的一个密码就能挡住绝大部分尝试。最开始,我还十分幼稚地试图找到gettyimages等图片提供商服务中的漏洞,后来一想才明白完全是做无用功。拿到的图片的价值越多付出的代价一定也就越多,要能拿到getty的图估计就能去getty工作了……

信息流、异步加载与定制化排版

另一个问题是如何定位自己想要的图片。最简单的情况当然是图片直接存在列表或固定位置里,一张一张取出来就是了。比较复杂的情况有:图片异步加载、图片分布在不同的元素中、图片移步加载且分散在各处。对于前者我学会了selenium,对于后者我还在学习正则表达式。更加综合的情况我就要衡量一下自己付出的时间获得的图片价值是否对等了——毕竟,时间值钱!

因此,现在我已经懒到,不是唾手可得的图片不存的地步了。又是压缩又是重编码,那我干脆不存了,费大力气存下来收获微乎其微。而且,还有那么多大门敞开的图床等着我搜刮呢!

bs4时代

稍稍懂了一点Python的皮毛,我就迫不及待地开始了爬图大业。Python写起来快,可用的各类库多,什么需求都能实现,不可谓不爽。bs4解析页面,找到想要的东西也比以前右键点点点畅快了许多。这时我的爬图方法逐渐分化为两大类:单发与周期。

所谓单发,就是随机在一个网页上看到几张十几张图片,想要挑挑拣拣地保存下来。这时候右键另存为嫌慢、编脚本又嫌重用性太差。于是便诞生了抓图器这个项目。它强调看到一张图点一两下就能存下来的方便,也注重适配各种情况奇形怪状的包含图片地址的HTML元素。最终希望达到的目标是,看到一张图,无论来自什么网站,只要符合我之前见过的情况之一,就能被下载下来。

所谓周期,就是每天每周从固定网站下载图片。很多新闻、门户网站的更新是具有规律性与周期性的,踩准鼓点便能源源不断地收获图片。这种需求强调稳定性,无需多么高效,但需要完善的异常处理。同时,还需要更好的筛选能力,毕竟一下子保存大量图片,其中一定不乏食之无味弃之可惜的个体。节省存储空间,如何筛掉这些图便是亟待解决的问题。

快速可重开发性——写一个结构清晰的脚本,遇到类似网站能够快速套用。比如对于FIFA和UEFA两个网站而言。

后向兼容性——尽可能想象可能遇到的情况,减少迭代次数。

开发过程简记

写需求,分析逻辑,码码码,分块测试,码码,并行,测试,码,输入输出,git push

开发的时候每解决一个新问题都有一点新收获,最后汇总好基本没再返工就直接跑通了。看来码之前设计好还是很重要的。

执行逻辑

现在我习惯于在开发前先把整体逻辑描述一遍,这样在写程序时就不用切换思路去考虑如何设计了。诚然,这样写出来的程序再改进或者添加新功能并不方便,但同时也不必害怕逻辑错乱还得修修补补。

直接把逻辑文档贴上来,不再整理。本来还想画个类UML图,后来发现项目逻辑不复杂没必要……

1. 首先从新闻链接总表links_all.csv中读取前两个键值e.g.2709309, 2774742等等;超过1024条后将源文件命名为links_all_date.csv,取源文件首行存入新的links_all.csv,然后继续;在主函数中写

2. 将从第一页开始今日读取的链接写入[date]links_temp.csv的头部,直到读取到上一个遍历过的键值或超过5页(一天最多两页,可设定双重兜底以防删除或变更,即每次判断两次),则进入下载步骤  // 此处不采用内存栈存储是为了后面报错中断方便;
dict?json?
如果网页更新了怎么办?直接跳过;
每打开一个新的页面,重做已有key,后面文件重复会筛掉;

3. 从[date]links_temp.txt第一行开始读取,打开链接,找到页面中符合正则的图片地址并计数判断>8,遍历并改变图片地址,(open双重测试),错误的话写入[日期]logging并打印文章链接 - 图片链接到输出,并更改报错全局变量error为真,读取写入的文件的大小,若小于1280x800则删除(可加flag),并map(名称,大小),图片总数++;
// 此处不考虑去重,因为文件名相同可能内容不同;

	- 文件夹名:
	若单页面图片超过8张:./[日期]/[序号键值]标题/[序号键值](顺序)图片;否则直接写入./[日期]/[序号键值](顺序)图片
	还是先都存到同一个文件夹里,后期再进行分类。

	- 链接文件格式:
	文件名:/[序号键值].txt
	内容:链接 - 标题 - 日期 - 序号键值 - 链接 - 空行 结束
	存储路径

	- 文件名:
	// 删除crop_exact以及相关
	[序号键值](序号)文件名乱码.jpg

遍历完成后新闻链接写入[date]links_all.txt,pop[date]links_temp.txt头部

4. 当达到文件末尾或超过链接总数时结束程序,判断报错变量,如果为真则将将报错信息读取并发送邮件;如果为假则发送成功通知邮件,遍历下载链接总数/图片总数,最大最小文件,总文件大小

最后处理所有报错异常进log

模块设计

BR-py3.py - main
	|-------- links_temp-------- get_article_links
			|-------- get_picture_links
			|-------- check_n_save_pictures

最主要的步骤就是从文章链接中获取图片链接,以及下载图片。这两个步骤没有顺序关系,因而都可以并行化。

数据库之殇

最开始的想法是用自己最熟悉最擅长的……文本文件。后来想象了一下呈现的结果,一定特别难看,于是作罢。又想用个轻量级数据库,但觉得大材小用,况且数据库呈现起来也不方便。最熟悉的accessdb就别说了……等以后学习数据库的时候再学吧。

最最轻量级的数据库应该就是json文件了,但json也不好美观地呈现。因此想到了csv。用Excel打开,用notepad也能打开,增删查改都不麻烦。就它了。

多线程与多进程的执念

  CPU密集型操作 IO密集型操作 网络请求密集型操作
线性操作 94.918s 22.461s 7.329s
多线程操作 101.170s 24.860s 0.505s
多进程操作 53.889s 12.784s 0.504s

参考了这篇文章,发现HTTP请求适合Python多线程,下载图片适合多进程。当然,对于C++而言都是多线程了。

其实,如果顺序下载的话并不会慢太多,因为速度慢的主要原因是端到端带宽不够,就算请求都发出了下载图片一样只能跑满带宽而已。不知道是GFW的缘故还是节点问题。

文档与发布

写程序的时候注释的比较详细,因此就没有再认真写文档。不过这篇博客以及README应该就足以应对大部分需求了。

pip freeze由于没有建venv没法直接导出本项目的依赖。安装了pipreqs还挺方便。其实可以进一步减少依赖库的使用。

使用

没有耕坏的田,只有累死的牛。不是图太少,而是盘太小。这便是我运行脚本存10页图后的感想。

难以想象BR的盈利能否负担其数据开支。一年光是图片的存储开销就有数百吉比特,流量一定是几十倍于这个数值。要知道,BYR14年总共积累的数据还不到1T!

同样的,还有USAToday等等一系列媒体的图片每天在源源不断地发布,这令我陷入了疑虑——存那么多图究竟有意义吗?

这或许是我第一次对自己存图的行为产生了怀疑。正如我立志为NBA2k11写外挂后再也没玩儿过一样。写好了脚本,收图癖也治好了。

后记

希望这不是我收图的终点,但目前看来我是不打算再扩大收图范围了。毕竟,买硬盘也是钱啊!收了大把的图,根本不看就堆到硬盘里占空间,怎么看都是毫无意义的事情。

后记随便写一点,以后要有新的想法再更新啦。

人脸识别

收获了巨量(数十吉比特)的图片后,我开始初步构想能用这些图片做些什么了。最朴素、最基础的想法当然是做一点无监督学习对图片进行自动分类。需求很简单:从图片中标出人脸,对人脸进行识别并分类。或者,我也可以标注出一点数据集,先把詹姆斯的图片挑出来?

开坑能力

狂立flag开学前刷好题学好编程,写完外挂,剪点视频,搞完蜡烛,如果可能再玩玩小车。哦,对了,再试试找个女生尬聊。

Chen Ting

Chen Ting

The page aimed to exhibit activities & achievements during Ting's undergraduate & graduate period. Meanwhile, other aspects such as lifestyles, literary work, travel notes, etc. would interweave in the narration.

Leave a Comment

Disqus might be GFW-ed. Excited!