我找到了一个网站,在Tumblr上托管了很多高质量的免费图片(它说你想用主题图片做任何事情:P)
我在Ubuntu 12.04LTS上运行。我需要编写一个定期运行的脚本(比如说每天)并只下载之前没有下载过的图像。
附加说明:它有一个javascript自动滚动器,当你到达页面底部时会下载图像。
答案 0 :(得分:9)
首先,您必须了解自动滚动脚本的工作原理。最简单的方法是不对javascript进行反向工程,而是查看网络活动。最简单的方法是使用Firebug Firefox插件并查看“Net”面板中的活动。您很快就会看到该网站是以页面形式组织的:
unsplash.com/page/1
unsplash.com/page/2
unsplash.com/page/3
...
滚动时,脚本会请求下载后续页面。
因此,我们实际上可以编写一个脚本来下载所有页面,解析所有图像的html并下载它们。如果你看一下html代码,你会看到图像以漂亮而独特的形式存在:
<a href="http://bit.ly/14nUvzx"><img src="http://31.media.tumblr.com/2ba914db5ce556ee7371e354b438133d/tumblr_mq7bnogm3e1st5lhmo1_1280.jpg" alt="Download / By Tony Naccarato" title="http://unsplash.com/post/55904517579/download-by-tony-naccarato" class="photo_img" /></a>
<a href
包含完整分辨率图片的网址。 title
属性包含一个很好的唯一网址,该网址也会导致图片。我们将使用它为图像构建漂亮的唯一名称,比存储图像的名称更好。这个漂亮的唯一名称也将确保没有图像被下载两次。
mkdir imgs
I=1
while true ; do # for all the pages
wget unsplash.com/page/$I -O tmppage
grep '<a href.*<img src.*title' tmppage > tmppage.imgs
if [ ! -s tmppage.imgs ] ; then # empty page - end the loop
break
fi
echo "Reading page $I:"
sed 's/^.*<a href="\([^"]*\)".*title="\([^"]*\)".*$/\1 \2/' tmppage.imgs | while read IMG POST ; do
# for all the images on page
TARGET=imgs/`echo $POST | sed 's|.*post/\(.*\)$|\1|' | sed 's|/|_|g'`.jpg
echo -n "Photo $TARGET: "
if [ -f $TARGET ] ; then # we already have this image
echo "already have"
continue
fi
echo "downloading"
wget $IMG -O $TARGET
done
I=$((I+1))
done
创建包装脚本usplash.cron
:
#!/bin/bash
export PATH=... # might not be needed, but sometimes the PATH is not set
# correctly in cron-called scripts. Copy the PATH setting you
# normally see under console.
cd YOUR_DIRECTORY # the directory where the script and imgs directory is located
{
echo "========================"
echo -n "run unsplash.sh from cron "
date
./unsplash.sh
} >> OUT.log 2>> ERR.log
然后在crontab中添加此行(在控制台上发出crontab -e
后):
10 3 * * * PATH_to_the/unsplash.cron
这将每天3:10运行脚本。
答案 1 :(得分:2)
这是下载部分的一个小python版本。对于包含单词“Download”的行,getImageURLs
函数会查找来自http://unsplash.com/page/X的数据,并在那里查找图像的'src'属性。它还会查找字符串current_page
和total_pages
(存在于javascript代码中),以了解要继续运行的时间。
目前,它首先从所有页面检索所有URL,对于这些URL,如果相应文件在本地不存在,则下载图像。根据页码编号随时间的变化,一旦找到文件的本地副本,停止查找图像URL可能会更有效。这些文件存储在执行脚本的目录中。
另一个答案很好地解释了如何确保每天都能执行这样的事情。
#!/usr/bin/env python
import urllib
import pprint
import os
def getImageURLs(pageIndex):
f = urllib.urlopen('http://unsplash.com/page/' + str(pageIndex))
data = f.read()
f.close()
curPage = None
numPages = None
imgUrls = [ ]
for l in data.splitlines():
if 'Download' in l and 'src=' in l:
idx = l.find('src="')
if idx >= 0:
idx2 = l.find('"', idx+5)
if idx2 >= 0:
imgUrls.append(l[idx+5:idx2])
elif 'current_page = ' in l:
idx = l.find('=')
idx2 = l.find(';', idx)
curPage = int(l[idx+1:idx2].strip())
elif 'total_pages = ' in l:
idx = l.find('=')
idx2 = l.find(';', idx)
numPages = int(l[idx+1:idx2].strip())
return (curPage, numPages, imgUrls)
def retrieveAndSaveFile(fileName, url):
f = urllib.urlopen(url)
data = f.read()
f.close()
g = open(fileName, "wb")
g.write(data)
g.close()
if __name__ == "__main__":
allImages = [ ]
done = False
page = 1
while not done:
print "Retrieving URLs on page", page
res = getImageURLs(page)
allImages += res[2]
if res[0] >= res[1]:
done = True
else:
page += 1
for url in allImages:
idx = url.rfind('/')
fileName = url[idx+1:]
if not os.path.exists(fileName):
print "File", fileName, "not found locally, downloading from", url
retrieveAndSaveFile(fileName, url)
print "Done."
答案 2 :(得分:1)
The fantastic original script done by TMS不再适用于新的unsplash网站。这是一个更新的工作版本。
#!/bin/bash
mkdir -p imgs
I=1
while true ; do # for all the pages
wget "https://unsplash.com/grid?page=$I" -O tmppage
grep img.*src.*unsplash.imgix.net tmppage | cut -d'?' -f1 | cut -d'"' -f2 > tmppage.imgs
if [ ! -s tmppage.imgs ] ; then # empty page - end the loop
break
fi
echo "Reading page $I:"
cat tmppage.imgs | while read IMG; do
# for all the images on page
TARGET=imgs/$(basename "$IMG")
echo -n "Photo $TARGET: "
if [ -f $TARGET ] ; then # we already have this image
echo "file already exists"
continue
fi
echo -n "downloading (PAGE $I)"
wget $IMG -O $TARGET
done
I=$((I+1))
done