使用javascript自动滚动,定期从网站上抓取和下载所有图像



我发现一个网站上有很多高质量的免费图片托管在汤博乐上(它说用主题图片做任何你想做的事:p)

我在Ubuntu 12.04LTS上运行。我需要写一个脚本,它会定期运行(比如每天),并且只下载之前没有下载的图像。

附加说明:它有一个javascript自动滚动器,当你到达页面底部时,图像就会被下载。

首先,您必须了解自动滚动脚本的工作原理。最简单的方法不是对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 &nbsp;/ &nbsp;By Tony&nbsp;Naccarato" title="http://unsplash.com/post/55904517579/download-by-tony-naccarato" class="photo_img" /></a>

<a href包含全分辨率图像的URL。title属性包含一个漂亮的唯一URL,该URL也指向图像。我们将使用它为图像构建一个漂亮的唯一名称,比存储它的名称要好得多。这个漂亮的唯一名称还可以确保没有图像被下载两次。

外壳脚本(unsplash.sh)

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运行脚本。

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

下面是下载部分的一个小python版本。getImageURLs函数从http://unsplash.com/page/X对于包含单词"Download"的行,请在其中查找image"src"属性。它还查找字符串current_pagetotal_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."

最新更新