Python запросы: скачать только если новее

Каков стандартный питонный способ загрузки нового файла с сервера, только если серверная копия новее локальной?

Либо мой python-search-fu сегодня очень слабый, либо нужно действительно запустить свой собственный анализатор даты и времени, как показано ниже. Там действительно нет requests.header.get_datetime_object('last-modified')? или же request.save_to_file(url, outfile, maintain_datetime=True)?

import requests
import datetime

r = requests.head(url)
url_time = r.headers['last-modified']
file_time = datetime.datetime.fromtimestamp(os.path.getmtime(dstFile))
print url_time  #emits 'Sat, 28 Mar 2015 08:05:42 GMT' on my machine
print file_time #emits '2015-03-27 21:53:28.175072' 

if time_is_older(url_time, file_time):
    print 'url modtime is not newer than local file, skipping download'
    return
else:
    do_download(url)
    os.utime(dstFile, url_time) # maintain server's file timestamp

def time_is_older(str_time, time_object):
    ''' Parse str_time and see if is older than time_object.
        This is a fragile function, what if str_time is in different locale?
    '''
    parsed_time = datetime.datetime.strptime(str_time, 
        #Fri, 27 Mar 2015 08:05:42 GMT
        '%a, %d %b %Y %X %Z')
    return parsed_time < time_object

3 ответа

import requests
import datetime
from dateutil.parser import parse as parsedate
r = requests.head(url)
url_time = r.headers['last-modified']
url_date = parsedate(url_time)
file_time = datetime.datetime.fromtimestamp(os.path.getmtime(dstFile))
if url_date > file_time :
    donwload it !

Я использовал следующий код, который также учитывает часовой пояс и гарантирует, что оба объекта datetime осведомлены.

import datetime
import requests
from dateutil.parser import parse as parsedate

r = requests.head(url)
url_datetime = parsedate(r.headers['Last-Modified']).astimezone()
file_time = datetime.datetime.fromtimestamp(path.getmtime(dst_file)).astimezone()
if(url_date > file_time):
    user_agent = {"User-agent": "Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:46.0) Gecko/20100101 Firefox/46.0"}
    r = requests.get(url, headers=user_agent)
    with open(file, 'wb') as fd:
        for chunk in r.iter_content(4096):
            fd.write(chunk)

Глагол HEAD не включает заголовок Last-Modified, но вместо него можно использовать ETag. Это непрозрачная строка, обычно хеш файла, которая изменится при изменении ресурса. Это больше работы и требует локального хранения хеша. Вы также можете рассмотреть возможность использования модуля Request-Cache, что может быть более простым решением. Вот что я придумал:

      def podcast_updated(podcast: Podcast) -> bool:
    # Based on our saved last-updated time, are there new episodes? If not, don't
    # hammer their server. Internet manners. Method - call HEAD instead of GET
    # Note that HEAD doesn't include a timestamp, but does include the cache ETag, so
    # we simply snapshot the etag to disk and see if it differs.
    filename = podcast.name + '-timestamp.json'
    try:
        r = requests.head(podcast.rss_url)
        url_etag = r.headers['ETag']
        file_etag = open(filename, 'r').read()

        if file_etag == url_etag:
            log.info(f'No new episodes found in podcast {podcast.name}')
            return False
    except FileNotFoundError:
        log.warning(f'File {filename} not found, creating.')

    open(filename, 'w').write(url_etag)
    return True
Другие вопросы по тегам