├── flickrDownloader
├── __init__.py
├── utils.py
└── flickrDownloader.py
├── flickr.apikey
├── .idea
├── vcs.xml
├── misc.xml
├── inspectionProfiles
│ └── profiles_settings.xml
├── modules.xml
└── flickr-image-downloader.iml
├── setup.py
├── LICENSE
├── .gitignore
├── main_usage_examples.py
└── README.md
/flickrDownloader/__init__.py:
--------------------------------------------------------------------------------
1 | from flickrDownloader import *
--------------------------------------------------------------------------------
/flickr.apikey:
--------------------------------------------------------------------------------
1 | INSERT_HERE_YOUR_API_KEY
2 | (request an api key here: https://www.flickr.com/services/api/misc.api_keys.html)
3 |
--------------------------------------------------------------------------------
/.idea/vcs.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/.idea/misc.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/.idea/inspectionProfiles/profiles_settings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/.idea/modules.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/.idea/flickr-image-downloader.iml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/setup.py:
--------------------------------------------------------------------------------
1 | from setuptools import setup
2 | from setuptools import find_packages
3 |
4 |
5 | setup(name='flickrDownloader',
6 | version='0.1.3',
7 | description='Helper for Flickr photos.search API',
8 | author='Riccardo Del Chiaro',
9 | author_email='riccardo.delchiaro@gmail.com',
10 | url='https://github.com/nagash91/python-flickr-image-downloader',
11 | license='MIT',
12 | packages=find_packages(),
13 | package_dir={'flickrDownloader':'flickrDownloader'},
14 | long_description=open('README.md').read(),
15 | requires=['requests']
16 | )
17 |
18 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2017 Riccardo Del Chiaro
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Uncomment next line to not share the flickr.apikey:
2 | # flickr.apikey
3 |
4 | # Ignore building files (generated by setuptools, setup.py)
5 | build
6 | dist
7 | *.egg-info
8 |
9 | # Byte-compiled / optimized / DLL files
10 | __pycache__/
11 | *.py[cod]
12 | *$py.class
13 |
14 | # Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and Webstorm
15 | # Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839
16 |
17 | # User-specific stuff:
18 | .idea/**/workspace.xml
19 | .idea/**/tasks.xml
20 |
21 | # Sensitive or high-churn files:
22 | .idea/**/dataSources/
23 | .idea/**/dataSources.ids
24 | .idea/**/dataSources.xml
25 | .idea/**/dataSources.local.xml
26 | .idea/**/sqlDataSources.xml
27 | .idea/**/dynamic.xml
28 | .idea/**/uiDesigner.xml
29 |
30 | # Gradle:
31 | .idea/**/gradle.xml
32 | .idea/**/libraries
33 |
34 | # Mongo Explorer plugin:
35 | .idea/**/mongoSettings.xml
36 |
37 | ## File-based project format:
38 | *.iws
39 |
40 | ## Plugin-specific files:
41 |
42 | # IntelliJ
43 | /out/
44 |
45 | # mpeltonen/sbt-idea plugin
46 | .idea_modules/
47 |
48 | # JIRA plugin
49 | atlassian-ide-plugin.xml
50 |
51 | # Crashlytics plugin (for Android Studio and IntelliJ)
52 | com_crashlytics_export_strings.xml
53 | crashlytics.properties
54 | crashlytics-build.properties
55 | fabric.properties
--------------------------------------------------------------------------------
/flickrDownloader/utils.py:
--------------------------------------------------------------------------------
1 | import os
2 | import urllib2
3 | from urllib2 import Request, urlopen
4 | from urllib2 import URLError, HTTPError
5 |
6 | def string_or_path(string_or_file):
7 | if os.path.isfile(string_or_file):
8 | ret = open(string_or_file, 'r').read()
9 | else:
10 | ret = string_or_file
11 | return ret
12 |
13 |
14 | def web_downloader(link_list, download_path, save_filename_prefix="", save_filename_postfix="_", forced_extension=None,
15 | verbose=False, ignore_errors=False):
16 | # type: (list(str), str, str, str, bool, bool) -> None
17 |
18 | client_header = {
19 | "User-Agent": "Mozilla/5.0 (X11; Linux i686) AppleWebKit/537.17 (KHTML, like Gecko) Chrome/24.0.1312.27 Safari/537.17"}
20 |
21 | if download_path != "" and not os.path.isdir(download_path):
22 | os.mkdir(download_path)
23 |
24 | error_count = 0
25 | for k, link in enumerate(link_list):
26 |
27 | try:
28 | req = Request(link, headers=client_header)
29 | response = urlopen(req)
30 | if forced_extension is not None:
31 | extension = forced_extension
32 | else:
33 | extension = os.path.splitext(link)[1].lower()
34 | output_file = open(os.path.join(download_path, save_filename_prefix + save_filename_postfix + str(k)
35 | + extension), 'wb')
36 | data = response.read()
37 | output_file.write(data)
38 | response.close()
39 | if verbose:
40 | print("completed ====> " + str(k))
41 |
42 | # IN this saving process we are just skipping the URL if there is any error
43 | except IOError: # If there is any IOError
44 | error_count += 1
45 | if not ignore_errors:
46 | print("IOError on image " + str(k))
47 |
48 | except HTTPError: # If there is any HTTPError
49 | error_count += 1
50 | if not ignore_errors:
51 | print("HTTPError" + str(k))
52 |
53 | except URLError:
54 | error_count += 1
55 | if not ignore_errors:
56 | print("URLError " + str(k))
57 |
58 | except ValueError:
59 | error_count += 1
60 | if not ignore_errors:
61 | print("ValueERROR " + str(k))
62 |
63 | if verbose:
64 | print("\nAll are downloaded")
65 | if verbose or not ignore_errors:
66 | print("Total Errors ----> " + str(error_count) )
67 |
68 | return error_count
69 |
70 |
71 |
72 | import re, urlparse
73 | def urlEncodeNonAscii(b):
74 | return re.sub('[\x80-\xFF]', lambda c: '%%%02x' % ord(c.group(0)), b)
75 |
76 |
77 | # USE urllib2.quote instead
78 | # def iriToUri(iri):
79 | # parts= urlparse.urlparse(iri)
80 | # return urlparse.urlunparse(
81 | # part.encode('idna') if parti==1 else urlEncodeNonAscii(part.encode('utf-8'))
82 | # for parti, part in enumerate(parts)
83 | # )
--------------------------------------------------------------------------------
/main_usage_examples.py:
--------------------------------------------------------------------------------
1 | from flickrDownloader import *
2 |
3 |
4 | api_key = "INSERT_HERE_YOUR_API_KEY" # if you want to insert your apikey in source code
5 | api_key = "flickr.apikey" # if you want to read apikey from file
6 |
7 | # If you want to share your code in git, you may want not to share your api key too!
8 | # In that case, insert your api key in the flickr.apikey file and add flickr.apikey in your .gitignore
9 |
10 |
11 | # Available licenses: (from: https://www.flickr.com/services/api/explore/flickr.photos.licenses.getInfo)
12 | #
13 | # {"id": 0, "name": "All Rights Reserved", "url": ""},
14 | # {"id": 4, "name": "Attribution License", "url": "https:\/\/creativecommons.org\/licenses\/by\/2.0\/"},
15 | # {"id": 6, "name": "Attribution-NoDerivs License", "url": "https:\/\/creativecommons.org\/licenses\/by-nd\/2.0\/"},
16 | # {"id": 3, "name": "Attribution-NonCommercial-NoDerivs License", "url": "https:\/\/creativecommons.org\/licenses\/by-nc-nd\/2.0\/"},
17 | # {"id": 2, "name": "Attribution-NonCommercial License", "url": "https:\/\/creativecommons.org\/licenses\/by-nc\/2.0\/"},
18 | # {"id": 1, "name": "Attribution-NonCommercial-ShareAlike License", "url": "https:\/\/creativecommons.org\/licenses\/by-nc-sa\/2.0\/"},
19 | # {"id": 5, "name": "Attribution-ShareAlike License", "url": "https:\/\/creativecommons.org\/licenses\/by-sa\/2.0\/"},
20 | # {"id": 7, "name": "No known copyright restrictions", "url": "https:\/\/www.flickr.com\/commons\/usage\/"},
21 | # {"id": 8, "name": "United States Government Work", "url": "http:\/\/www.usa.gov\/copyright.shtml"},
22 | # {"id": 9, "name": "Public Domain Dedication (CC0)", "url": "https:\/\/creativecommons.org\/publicdomain\/zero\/1.0\/"},
23 | # {"id": 10, "name": "Public Domain Mark", "url": "https:\/\/creativecommons.org\/publicdomain\/mark\/1.0\/"}
24 | license_id = 10 # "using public domain mark" license
25 |
26 |
27 | link_list = flickr_photos_downloader(api_key,
28 | query_text="david michelangelo",
29 | # tags="",
30 | tag_mode=FlickrTagMode.all,
31 | download_path="michelangelo_download",
32 | image_size=FlickrImageSize.square_150x150,
33 | n_images=100,
34 | verbose=True,
35 | license_id=license_id)
36 |
37 | flickr_photos_downloader(api_key,
38 | n_images=10,
39 | query_text="Firenze",
40 | tags="Art",
41 | tag_mode=FlickrTagMode.any,
42 | image_size=FlickrImageSize.longedge_1600,
43 | content_type=FlickrContentType.photos,
44 | media=FlickrMedia.photos,
45 | download_path="img_downloads",
46 | save_filename_prefix="flickr_downloaded_",
47 | forced_extension=None,
48 | verbose=True,
49 | ignore_errors=False,
50 | license_id=license_id)
51 |
52 |
53 | only_link = flickr_photos_links(api_key,
54 | n_images=1500,
55 | query_text="Firenze",
56 | tags="Art",
57 | tag_mode=FlickrTagMode.any,
58 | image_size=FlickrImageSize.longedge_1600,
59 | content_type=FlickrContentType.photos,
60 | media=FlickrMedia.photos,
61 | verbose=True,
62 | ignore_errors=False,
63 | license_id=license_id)
64 |
65 | for i, link in enumerate(only_link):
66 | print str(i) + "\t-\t" + link
67 |
68 | responsesJson = flickr_photos_search(api_key,
69 | n_images=1500,
70 | query_text="Firenze",
71 | tags="Art",
72 | tag_mode=FlickrTagMode.any,
73 | content_type=FlickrContentType.photos,
74 | media=FlickrMedia.photos,
75 | response_format=FlickrResponseFormat.JSON,
76 | license_id=license_id)
77 |
78 |
79 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Python Flickr Images Downloader
2 | Python functions for searching and downloading images/links from Flickr.
3 | Use the flickr.photos.search API to search image (using tags/text):
4 | https://www.flickr.com/services/api/explore/flickr.photos.search
5 |
6 | ## Compatability
7 | Tested only on python 2.7
8 |
9 | ## Limitations
10 | Not all the possible search arguments are implemented (for example place, geolocalization, and others).
11 |
12 |
13 | ## Disclaimer
14 | This program lets you download tons of images from Flickr.
15 | Please do not violate its copyright or license terms.
16 |
17 | Flickr photos licenses API:
18 | https://www.flickr.com/services/api/flickr.photos.licenses.getInfo.html
19 | https://www.flickr.com/services/api/explore/flickr.photos.licenses.getInfo
20 |
21 | ## Install
22 | git clone https://github.com/nagash91/python-flickr-image-downloader.git
23 | cd python-flickr-image-downloader
24 | python setup.py install
25 |
26 |
27 | ## Usage
28 | ```python
29 | from flickrDownloader import *
30 |
31 | api_key = "INSERT_HERE_YOUR_API_KEY" # if you want to insert your apikey in source code
32 | api_key = "flickr.apikey" # if you want to read apikey from file
33 |
34 | license_id = 10 # "using public domain mark" license
35 |
36 | # Get links and download photos:
37 | flickr_photos_downloader(api_key,
38 | n_images=10,
39 | query_text="Firenze",
40 | tags="Art",
41 | tag_mode=FlickrTagMode.any,
42 | image_size=FlickrImageSize.longedge_1600,
43 | content_type=FlickrContentType.photos,
44 | media=FlickrMedia.photos,
45 | download_path="img_downloads",
46 | save_filename_prefix="flickr_downloaded_",
47 | forced_extension=None,
48 | verbose=True,
49 | ignore_errors=False,
50 | license_id=license_id)
51 |
52 | # Get links only:
53 | only_link = flickr_photos_links(api_key,
54 | n_images=1500,
55 | query_text="Firenze",
56 | tags="Art",
57 | tag_mode=FlickrTagMode.any,
58 | image_size=FlickrImageSize.longedge_1600,
59 | content_type=FlickrContentType.photos,
60 | media=FlickrMedia.photos,
61 | verbose=True,
62 | ignore_errors=False,
63 | license_id=license_id)
64 | # Print links:
65 | for i, link in enumerate(only_link):
66 | print str(i) + "\t-\t" + link
67 | ```
68 |
69 |
70 |
71 | Available options:
72 |
73 | ```python
74 | # ENUM DEFINED FOR OPTIONS:
75 |
76 | class FlickrContentType(Enum):
77 | default = ""
78 | photos = "&content_type=1"
79 | screenshoots = "&content_type=2"
80 | other = "&content_type=3"
81 | photos_screenshots = "&content_type=4"
82 | screenshoots_other = "&content_type=5"
83 | photos_other = "&content_type=6"
84 | photos_screenshots_other = "&content_type=7"
85 |
86 |
87 | class FlickrTagMode(Enum):
88 | default = ""
89 | any = '&tag_mode=any' # logic OR
90 | all = '&tag_mode=all' # logic AND
91 |
92 |
93 | class FlickrMedia(Enum):
94 | default = ""
95 | photos = "&media=photos"
96 | videos = "&media=videos"
97 |
98 |
99 | class FlickrResponseFormat(Enum):
100 | JSON = "&format=json&nojsoncallback=1"
101 | JSONP = "&format=json"
102 | XML = "&format=rest"
103 | PHP_SERIAL = "&format=php_serial"
104 | default = JSON
105 |
106 | class FlickrImageSize(Enum):
107 | default = ""
108 | square_75x75 = "_s" # 75 x 75
109 | square_150x150 = "_q" # 150 x 150
110 | longedge_100 = "_t" # 100 on the longest edge
111 | longedge_240 = "_m" # 240 on the longest edge
112 | longedge_320 = "_n" # 320 on the longest edge
113 | longedge_500 = "_-" # 500 on the longest edge
114 | longedge_640 = "_z" # 640 on the longest edge
115 | longedge_800 = "_c" # 800 on the longest edge (flickr new feature from 01/03/2012)
116 | longedge_1024 = "_b" # 1024 on the longest edge
117 | longedge_1600 = "_h" # 1600 on the longest edge (flickr new feature from 01/03/2012)
118 | longedge_2048 = "_k" # 2048 on the longest edge (flickr new feature from 01/03/2012)
119 | ```
120 |
--------------------------------------------------------------------------------
/flickrDownloader/flickrDownloader.py:
--------------------------------------------------------------------------------
1 | import json
2 | import urllib2
3 | from enum import Enum
4 | import requests
5 | from requests import Response
6 |
7 | from utils import string_or_path
8 | from utils import web_downloader
9 |
10 | # TODO: always using public for now
11 | class FlickrPrivacyFilter(Enum):
12 | default = u""
13 | public = u"&privacy_filter=1"
14 | friends = u"&privacy_filter=2"
15 | family = u"&privacy_filter=3"
16 | friends_family = u"&privacy_filter=4"
17 | private = u"&privacy_filter=5"
18 |
19 |
20 | class FlickrContentType(Enum):
21 | default = u""
22 | photos = u"&content_type=1"
23 | screenshoots = u"&content_type=2"
24 | other = u"&content_type=3"
25 | photos_screenshots = u"&content_type=4"
26 | screenshoots_other = u"&content_type=5"
27 | photos_other = u"&content_type=6"
28 | photos_screenshots_other = u"&content_type=7"
29 |
30 |
31 | class FlickrTagMode(Enum):
32 | default = u""
33 | any = u'&tag_mode=any' # logic OR
34 | all = u'&tag_mode=all' # logic AND
35 |
36 |
37 | class FlickrMedia(Enum):
38 | default = u""
39 | photos = u"&media=photos"
40 | videos = u"&media=videos"
41 |
42 |
43 | class FlickrResponseFormat(Enum):
44 | JSON = u"&format=json&nojsoncallback=1"
45 | JSONP = u"&format=json"
46 | XML = u"&format=rest"
47 | PHP_SERIAL = u"&format=php_serial"
48 | default = JSON
49 |
50 | class FlickrImageSize(Enum):
51 | default = u""
52 | square_75x75 = u"_s" # 75 x 75
53 | square_150x150 = u"_q" # 150 x 150
54 | longedge_100 = u"_t" # 100 on the longest edge
55 | longedge_240 = u"_m" # 240 on the longest edge
56 | longedge_320 = u"_n" # 320 on the longest edge
57 | longedge_500 = u"_-" # 500 on the longest edge
58 | longedge_640 = u"_z" # 640 on the longest edge
59 | longedge_800 = u"_c" # 800 on the longest edge (flickr new feature from 01/03/2012)
60 | longedge_1024 = u"_b" # 1024 on the longest edge
61 | longedge_1600 = u"_h" # 1600 on the longest edge (flickr new feature from 01/03/2012)
62 | longedge_2048 = u"_k" # 2048 on the longest edge (flickr new feature from 01/03/2012)
63 |
64 |
65 | # TODO: original image: jpg, gif or png according to the source format, not supported yet
66 | # original = "_o"
67 | # Require original secret (o-secret) but in responses I can't see that entry:
68 | # https://farm{farm-id}.staticflickr.com/{server-id}/{id}_{o-secret}_o.(jpg|gif|png)
69 | # class FlickrImageExtension(Enum):
70 | # jpg = "jpg"
71 | # png = "png"
72 | # gif = "gif"
73 | # default = jpg
74 |
75 | # TODO: add localizations
76 | def flickr_photos_search(api_key_or_file_path, # type: unicode
77 | n_images=100, # type: int
78 | query_text=None, # type: unicode
79 | tags=None, # type: unicode
80 | tag_mode=FlickrTagMode.default, # type: FlickrTagMode
81 | content_type=FlickrContentType.default, # type: FlickrContentType
82 | media=FlickrMedia.default, # type: FlickrMedia
83 | response_format=FlickrResponseFormat.JSON, # type: FlickrResponseFormat
84 | license_id=None
85 | ):
86 | # type: (unicode, int, unicode, unicode, FlickrTagMode, FlickrContentType, FlickrMedia, FlickrResponseFormat) -> list(Response)
87 | """
88 |
89 | :rtype: list(Response)
90 | """
91 | MAX_IMAGES_PER_PAGE = 500 # fixed by flickr api
92 | if isinstance(api_key_or_file_path, str):
93 | api_key_or_file_path = unicode(api_key_or_file_path, "UTF-8")
94 | if not isinstance(api_key_or_file_path, unicode):
95 | raise ValueError(u"api_key_or_file_path must be a unicode (flickr api key or path to text file containing key).")
96 | api_key = string_or_path(api_key_or_file_path).split(" ")[0].split("\n")[0]
97 |
98 |
99 | query = u"https://api.flickr.com/services/rest/?method=flickr.photos.search"
100 | query += u"&api_key=" + api_key
101 |
102 | if isinstance(query_text, str):
103 | query_text = unicode(query_text, "UTF-8")
104 | if isinstance(tags, str):
105 | tags = unicode(tags, "UTF-8")
106 | #if isinstance(query_text, unicode):
107 | if query_text is not None:
108 | query += u"&text=" + urllib2.quote(query_text.encode('utf-8'))
109 |
110 | #if isinstance(tags, unicode):
111 | if tags is not None:
112 | query += u"&tags=" + urllib2.quote(tags.encode('utf-8')) + tag_mode.value
113 | # query.replace(" ", "%20")
114 | query += content_type.value + media.value + response_format.value + FlickrPrivacyFilter.public.value
115 |
116 | if license_id is not None:
117 | query += u"&license_id=" + unicode(license_id)
118 |
119 | rest = n_images % MAX_IMAGES_PER_PAGE
120 | n_queries = n_images/MAX_IMAGES_PER_PAGE
121 | query_len_list = [MAX_IMAGES_PER_PAGE] * n_queries
122 | if rest > 0:
123 | query_len_list.append(rest)
124 |
125 | responses = []
126 | for i, query_len in enumerate(query_len_list):
127 | page_query = query + u"&per_page=" + unicode(query_len) + u"&page=" + unicode(i+1)
128 | responses.append(requests.get(page_query))
129 |
130 | return responses
131 |
132 |
133 | def flickr_photos_links(api_key_or_file_path, # type: unicode
134 | n_images=100, # type: int
135 | query_text=None, # type: unicode
136 | tags=None, # type: unicode
137 | image_size=FlickrImageSize.default, # type: FlickrImageSize
138 | tag_mode=FlickrTagMode.default, # type: FlickrTagMode
139 | content_type=FlickrContentType.default, # type: FlickrContentType
140 | media=FlickrMedia.default, # type: FlickrMedia
141 | license_id=None,
142 | verbose=False,
143 | ignore_errors=False,
144 | max_error_retries=3
145 | ):
146 | # type: (...) -> list(unicode)
147 |
148 | retry = 0
149 | links = []
150 |
151 | while retry < max_error_retries:
152 | links = []
153 |
154 | try:
155 | responses = flickr_photos_search(api_key_or_file_path=api_key_or_file_path, n_images=n_images,
156 | query_text=query_text, tags=tags, tag_mode=tag_mode,
157 | content_type=content_type, media=media,
158 | response_format=FlickrResponseFormat.JSON, license_id=license_id)
159 |
160 | for response in responses:
161 | if response.ok:
162 | content = response.content
163 | data = json.loads(content)
164 |
165 |
166 | if 'photos' in data.keys():
167 | data = data['photos']['photo']
168 | for d in data:
169 | # https://farm{farm-id}.staticflickr.com/{server-id}/{id}_{secret}_[mstzb].jpg
170 | lnk = u"https://farm{}.staticflickr.com/{}/{}_{}{}.jpg"\
171 | .format(d['farm'], d['server'], d['id'], d['secret'], image_size.value)
172 | links.append(lnk)
173 | else:
174 | if not ignore_errors:
175 | print(u"Format error in received json (can't find key 'photos').")
176 | if 'message' in data.keys():
177 | print(u"Received Message: {}".format(data['message'].encode("utf-8")))
178 |
179 | else:
180 | if not ignore_errors:
181 | print(u"Flickr response not ok.")
182 | if verbose:
183 | print(u"Links retrived from flickr responses: {}".format(len(links)))
184 | return links
185 |
186 | except ValueError as v:
187 | retry-=1
188 | if verbose or not ignore_errors:
189 | print(u"Value Error in flickr_photos_links process:")
190 | print(v.message)
191 | if retry list(unicode)
219 |
220 | links = flickr_photos_links(api_key_or_file_path=api_key_or_file_path, query_text=query_text, tags=tags, n_images=n_images,
221 | image_size=image_size, tag_mode=tag_mode, content_type=content_type, media=media,
222 | verbose=verbose, ignore_errors=ignore_errors, license_id=license_id, max_error_retries=max_error_retries)
223 | web_downloader(link_list=links, download_path=download_path, save_filename_prefix=save_filename_prefix,
224 | forced_extension=forced_extension, verbose=verbose, ignore_errors=ignore_errors)
225 | return links
226 |
227 |
228 |
229 |
230 |
231 |
232 | # Flickr Documentations:
233 | # For search:
234 | # https://www.flickr.com/services/api/explore/flickr.photos.search
235 | # (use public = 1 in the query!)
236 | # (log in in flickr to automatically insert my api key).
237 | #
238 | #
239 | # To download images, look at here: https://www.flickr.com/services/api/misc.urls.html
240 | # example: http://farm3.staticflickr.com/2636/32179988483_cd41d8fca9_b.jpg
241 | #
242 | # Otherwise you can use getSize query and use the source response to get the direct link:
243 | # http://www.flickr.com/services/api/flickr.photos.getSizes.html
244 | #
245 |
246 |
247 |
248 |
249 |
250 |
251 |
252 |
253 |
254 |
255 |
256 |
257 | # * * * * * * * * * * * * * * * * * * * SEARCH API * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
258 | # SEARCH API ( https://www.flickr.com/services/api/flickr.photos.search.html )
259 | # EXAMPLE OF QUERY:
260 | # https://api.flickr.com/services/rest/?method=flickr.photos.search
261 | # &api_key=API_KEY
262 | # &tags=art
263 | # &text=david
264 | # &per_page=100
265 | # &page=1
266 | # &format=json
267 |
268 | # tags (Facoltativo)
269 | # A comma-delimited list of tags. Photos with one or more of the tags listed will be returned. You can exclude results
270 | # that match a term by prepending it with a - character.
271 |
272 | # tag_mode (Facoltativo)
273 | # Either 'any' for an OR combination of tags, or 'all' for an AND combination. Defaults to 'any' if not specified.
274 |
275 | # text (Facoltativo)
276 | # A free text search. Photos who's title, description or tags contain the text will be returned. You can exclude results
277 | # that match a term by prepending it with a - character.
278 |
279 | # sort (Facoltativo)
280 | # The order in which to sort returned photos. Deafults to date-posted-desc (unless you are doing a radial geo query, in
281 | # which case the default sorting is by ascending distance from the point specified). The possible values are:
282 | # date-posted-asc,
283 | # date-posted-desc,
284 | # date-taken-asc,
285 | # date-taken-desc,
286 | # interestingness-desc,
287 | # interestingness-asc,
288 | # relevance.
289 |
290 |
291 | # privacy_filter (Facoltativo)
292 | # Return photos only matching a certain privacy level.
293 | # This only applies when making an authenticated call to view photos you own.
294 | # Valid values are:
295 | # 1 public photos
296 | # 2 private photos visible to friends
297 | # 3 private photos visible to family
298 | # 4 private photos visible to friends & family
299 | # 5 completely private photos
300 |
301 |
302 | # content_type (Facoltativo)
303 | # Content Type setting:
304 | # 1 for photos only.
305 | # 2 for screenshots only.
306 | # 3 for 'other' only.
307 | # 4 for photos and screenshots.
308 | # 5 for screenshots and 'other'.
309 | # 6 for photos and 'other'.
310 | # 7 for photos, screenshots, and 'other' (all).
311 |
312 |
313 | # media (Facoltativo)
314 | # Filter results by media type. Possible values are all (default), photos or videos
315 |
316 |
317 |
318 | # per_page (Facoltativo)
319 | # Number of photos to return per page. If this argument is omitted, it defaults to 100. The maximum allowed value is 500.
320 |
321 | # page (Facoltativo)
322 | # The page of results to return. If this argument is omitted, it defaults to 1.
323 |
324 |
325 |
326 |
327 | # FOR LOCALIZATION:
328 |
329 | # geo_context (Facoltativo)
330 | # Geo context is a numeric value representing the photo's geotagginess beyond latitude and longitude.
331 | # For example, you may wish to search for photos that were taken "indoors" or "outdoors".
332 | # The current list of context IDs is :
333 | # 0, not defined.
334 | # 1, indoors.
335 | # 2, outdoors.
336 | # Geo queries require some sort of limiting agent in order to prevent the database from crying.
337 | # This is basically like the check against "parameterless searches" for queries without a geo component.
338 | #
339 |
340 | # A tag, for instance, is considered a limiting agent as are user defined min_date_taken and min_date_upload parameters
341 | # If no limiting factor is passed we return only photos added in the last 12 hours (though we may extend the limit in the future).
342 | # lat (Facoltativo)
343 | # A valid latitude, in decimal format, for doing radial geo queries.
344 | # Geo queries require some sort of limiting agent in order to prevent the database from crying.
345 | # This is basically like the check against "parameterless searches" for queries without a geo component.
346 | # A tag, for instance, is considered a limiting agent as are user defined min_date_taken and min_date_upload parameters
347 | # If no limiting factor is passed we return only photos added in the last 12 hours
348 | # (though we may extend the limit in the future).
349 |
350 | # lon (Facoltativo)
351 | # A valid longitude, in decimal format, for doing radial geo queries.
352 | # Geo queries require some sort of limiting agent in order to prevent the database from crying.
353 | # This is basically like the check against "parameterless searches" for queries without a geo component.
354 | # A tag, for instance, is considered a limiting agent as are user defined min_date_taken and min_date_upload parameters
355 | # If no limiting factor is passed we return only photos added in the last 12 hours
356 | # (though we may extend the limit in the future).
357 |
358 |
359 | # radius (Facoltativo)
360 | # A valid radius used for geo queries, greater than zero and less than 20 miles (or 32 kilometers), for use with point-based geo queries. The default value is 5 (km).
361 |
362 | # radius_units (Facoltativo)
363 | # The unit of measure when doing radial geo queries. Valid options are "mi" (miles) and "km" (kilometers). The default is "km".
364 |
365 |
366 |
367 | # bbox (Facoltativo)
368 | # A comma-delimited list of 4 values defining the Bounding Box of the area that will be searched.
369 | # The 4 values represent the bottom-left corner of the box and the top-right corner, minimum_longitude,
370 | # minimum_latitude, maximum_longitude, maximum_latitude.
371 | # Longitude has a range of -180 to 180 , latitude of -90 to 90. Defaults to -180, -90, 180, 90 if not specified.
372 | # Unlike standard photo queries, geo (or bounding box) queries will only return 250 results per page.
373 | # Geo queries require some sort of limiting agent in order to prevent the database from crying.
374 | # This is basically like the check against "parameterless searches" for queries without a geo component.
375 | # A tag, for instance, is considered a limiting agent as are user defined min_date_taken and min_date_upload parameters
376 | # If no limiting factor is passed we return only photos added in the last 12 hours (though we may extend the limit in the future).
377 |
378 | # accuracy (Facoltativo)
379 | # Recorded accuracy level of the location information. Current range is 1-16 :
380 | # World level is 1
381 | # Country is ~3
382 | # Region is ~6
383 | # City is ~11
384 | # Street is ~16
385 | # Defaults to maximum value if not specified.
386 | # * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
387 |
--------------------------------------------------------------------------------