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

时间:2013-12-20 10:24:39

标签: javascript linux web-scraping autoscroll

我找到了一个网站,在Tumblr上托管了很多高质量的免费图片(它说你想用主题图片做任何事情:P)

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

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

3 个答案:

答案 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 &nbsp;/ &nbsp;By Tony&nbsp;Naccarato" title="http://unsplash.com/post/55904517579/download-by-tony-naccarato" class="photo_img" /></a>

<a href包含完整分辨率图片的网址。 title属性包含一个很好的唯一网址,该网址也会导致图片。我们将使用它为图像构建漂亮的唯一名称,比存储图像的名称更好。这个漂亮的唯一名称也将确保没有图像被下载两次。

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

答案 1 :(得分:2)

这是下载部分的一个小python版本。对于包含单词“Download”的行,getImageURLs函数会查找来自http://unsplash.com/page/X的数据,并在那里查找图像的'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."

答案 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