Compare commits

...
10 Commits
Author SHA1 Message Date
Alexander Graf ece0d11915 Release of version 4.1.1 2018-10-07 15:17:51 +02:00
Alexander Graf 41e734e1b8 Fix fast_update in case of no download
If Instaloader was called with --fast-update and encountered a post where
nothing has been downloaded because of flags that disable download of certain
types of media, the download was aborted. This behavior is now fixed.

Closes #183.
2018-10-07 14:59:16 +02:00
Alexander Graf b7ea0d5953 download_profiles: Check errors only if required
Fixes #178, where with `--profile-pic-only` an error message is printed
(without any further implications) when downloading profile pictures of private
profiles without being logged in.
2018-09-23 10:09:08 +02:00
Alexander Graf 325e89c4b2 Print how many requests were made on 429 2018-09-06 09:17:38 +02:00
Alexander Graf e248020927 Release of version 4.1 2018-09-02 21:57:20 +02:00
Alexander Graf 5a7b76db31 Merge branch 'v4.1-dev' 2018-09-02 21:56:16 +02:00
Alexander Graf 1a239e17cb First Release Candidate for Version 4.1 2018-08-31 17:42:59 +02:00
Alexander Graf bb8749b753 Adjust rate control to current rate limits 2018-08-31 17:17:23 +02:00
Alexander Graf 18707ee232 docs: Better explanation for is_video
Closes #173.
2018-08-30 10:16:56 +02:00
Alexander Graf 084424e856 docs/codesnippets: Link to source tree on github 2018-08-30 09:18:58 +02:00
7 changed files with 32 additions and 15 deletions
+9 -5
View File
@@ -192,11 +192,6 @@ where the attributes from :class:`Post` or
Id est, the following attributes can be used with both Id est, the following attributes can be used with both
:option:`--post-filter` and :option:`--storyitem-filter`: :option:`--post-filter` and :option:`--storyitem-filter`:
- :attr:`~Post.is_video` (bool)
Post/StoryItem is a video. For example, you may skip videos::
instaloader --post-filter="not is_video" target
- :attr:`~Post.owner_username` (str), :attr:`~Post.owner_id` (int) - :attr:`~Post.owner_username` (str), :attr:`~Post.owner_id` (int)
Owner profile username / userid. Owner profile username / userid.
@@ -206,6 +201,15 @@ Id est, the following attributes can be used with both
instaloader --post-filter="date_utc <= datetime(2018, 5, 31)" target instaloader --post-filter="date_utc <= datetime(2018, 5, 31)" target
- :attr:`~Post.is_video` (bool)
Post/StoryItem is a video. For example, you may skip videos::
instaloader --post-filter="not is_video" target
This is not the same as :option:`--no-videos` and
:option:`--no-video-thumbnails`, since sidecar posts (posts that contain
multiple pictures/videos in one post) have this attribute set to False.
As :option:`--post-filter`, the following attributes can be used additionally: As :option:`--post-filter`, the following attributes can be used additionally:
- :attr:`~Post.viewer_has_liked` (bool) - :attr:`~Post.viewer_has_liked` (bool)
+3
View File
@@ -14,6 +14,9 @@ Here we present code examples that use the :ref:`python-module-instaloader` for
more advanced Instagram downloading or metadata mining than what is possible more advanced Instagram downloading or metadata mining than what is possible
with the Instaloader command line interface. with the Instaloader command line interface.
The scripts presented here can be downloaded from our source tree:
`instaloader/docs/codesnippets/ <https://github.com/instaloader/instaloader/tree/master/docs/codesnippets>`__
.. For each code snippet: .. For each code snippet:
- title - title
- brief description of what it does / motivation / how it works - brief description of what it does / motivation / how it works
+4
View File
@@ -0,0 +1,4 @@
# Advanced Instaloader Examples
This directory contains the scripts that are presented at:
https://instaloader.github.io/codesnippets.html
+1 -1
View File
@@ -1,7 +1,7 @@
"""Download pictures (or videos) along with their captions and other metadata from Instagram.""" """Download pictures (or videos) along with their captions and other metadata from Instagram."""
__version__ = '4.1b1' __version__ = '4.1.1'
try: try:
+5 -5
View File
@@ -358,18 +358,18 @@ class Instaloader:
os.makedirs(os.path.dirname(filename), exist_ok=True) os.makedirs(os.path.dirname(filename), exist_ok=True)
# Download the image(s) / video thumbnail and videos within sidecars if desired # Download the image(s) / video thumbnail and videos within sidecars if desired
downloaded = False downloaded = True
if self.download_pictures: if self.download_pictures:
if post.typename == 'GraphSidecar': if post.typename == 'GraphSidecar':
edge_number = 1 edge_number = 1
for sidecar_node in post.get_sidecar_nodes(): for sidecar_node in post.get_sidecar_nodes():
# Download picture or video thumbnail # Download picture or video thumbnail
if not sidecar_node.is_video or self.download_video_thumbnails is True: if not sidecar_node.is_video or self.download_video_thumbnails is True:
downloaded |= self.download_pic(filename=filename, url=sidecar_node.display_url, downloaded &= self.download_pic(filename=filename, url=sidecar_node.display_url,
mtime=post.date_local, filename_suffix=str(edge_number)) mtime=post.date_local, filename_suffix=str(edge_number))
# Additionally download video if available and desired # Additionally download video if available and desired
if sidecar_node.is_video and self.download_videos is True: if sidecar_node.is_video and self.download_videos is True:
downloaded |= self.download_pic(filename=filename, url=sidecar_node.video_url, downloaded &= self.download_pic(filename=filename, url=sidecar_node.video_url,
mtime=post.date_local, filename_suffix=str(edge_number)) mtime=post.date_local, filename_suffix=str(edge_number))
edge_number += 1 edge_number += 1
elif post.typename == 'GraphImage': elif post.typename == 'GraphImage':
@@ -387,7 +387,7 @@ class Instaloader:
# Download video if desired # Download video if desired
if post.is_video and self.download_videos is True: if post.is_video and self.download_videos is True:
downloaded |= self.download_pic(filename=filename, url=post.video_url, mtime=post.date_local) downloaded &= self.download_pic(filename=filename, url=post.video_url, mtime=post.date_local)
# Download geotags if desired # Download geotags if desired
if self.download_geotags and post.location: if self.download_geotags and post.location:
@@ -823,7 +823,7 @@ class Instaloader:
self.download_profilepic(profile) self.download_profilepic(profile)
# Catch some errors # Catch some errors
if profile.is_private: if profile.is_private and (tagged or highlights or posts):
if not self.context.is_logged_in: if not self.context.is_logged_in:
raise LoginRequiredException("--login=USERNAME required.") raise LoginRequiredException("--login=USERNAME required.")
if not profile.followed_by_viewer and self.context.username != profile.username: if not profile.followed_by_viewer and self.context.username != profile.username:
+4 -4
View File
@@ -57,7 +57,7 @@ class InstaloaderContext:
self.quiet = quiet self.quiet = quiet
self.max_connection_attempts = max_connection_attempts self.max_connection_attempts = max_connection_attempts
self._graphql_page_length = 50 self._graphql_page_length = 50
self.graphql_count_per_slidingwindow = graphql_count_per_slidingwindow or 20 self.graphql_count_per_slidingwindow = graphql_count_per_slidingwindow or 200
self._root_rhx_gis = None self._root_rhx_gis = None
# error log, filled with error() and printed at the end of Instaloader.main() # error log, filled with error() and printed at the end of Instaloader.main()
@@ -221,7 +221,7 @@ class InstaloaderContext:
def _sleep(self): def _sleep(self):
"""Sleep a short time if self.sleep is set. Called before each request to instagram.com.""" """Sleep a short time if self.sleep is set. Called before each request to instagram.com."""
if self.sleep: if self.sleep:
time.sleep(min(random.expovariate(0.6), 5.0)) time.sleep(min(random.expovariate(0.7), 5.0))
def get_json(self, path: str, params: Dict[str, Any], host: str = 'www.instagram.com', def get_json(self, path: str, params: Dict[str, Any], host: str = 'www.instagram.com',
session: Optional[requests.Session] = None, _attempt=1) -> Dict[str, Any]: session: Optional[requests.Session] = None, _attempt=1) -> Dict[str, Any]:
@@ -248,8 +248,7 @@ class InstaloaderContext:
is_graphql_query = 'query_hash' in params and 'graphql/query' in path is_graphql_query = 'query_hash' in params and 'graphql/query' in path
# some queries are not rate limited if invoked anonymously: # some queries are not rate limited if invoked anonymously:
query_not_limited = is_graphql_query and not self.is_logged_in \ query_not_limited = is_graphql_query and not self.is_logged_in \
and params['query_hash'] in ['9ca88e465c3f866a76f7adee3871bdd8', and params['query_hash'] in ['9ca88e465c3f866a76f7adee3871bdd8']
'472f257a40c653c64c666ce877d59d2b']
if is_graphql_query and not query_not_limited: if is_graphql_query and not query_not_limited:
waittime = graphql_query_waittime() waittime = graphql_query_waittime()
if waittime > 0: if waittime > 0:
@@ -307,6 +306,7 @@ class InstaloaderContext:
if isinstance(err, TooManyRequestsException): if isinstance(err, TooManyRequestsException):
print(textwrap.fill(text_for_429), file=sys.stderr) print(textwrap.fill(text_for_429), file=sys.stderr)
if is_graphql_query: if is_graphql_query:
print("Made {} GraphQL requests.".format(len(self.query_timestamps)), file=sys.stderr)
waittime = graphql_query_waittime(untracked_queries=True) waittime = graphql_query_waittime(untracked_queries=True)
if waittime > 0: if waittime > 0:
self.log('The request will be retried in {} seconds, at {:%H:%M}.' self.log('The request will be retried in {} seconds, at {:%H:%M}.'
+6
View File
@@ -63,6 +63,12 @@ class TestInstaloaderAnonymously(unittest.TestCase):
def test_hashtag_download(self): def test_hashtag_download(self):
self.L.download_hashtag(HASHTAG, NORMAL_MAX_COUNT) self.L.download_hashtag(HASHTAG, NORMAL_MAX_COUNT)
def test_hashtag_paging(self):
for count, post in enumerate(self.L.get_hashtag_posts(HASHTAG)):
print(post)
if count == PAGING_MAX_COUNT:
break
def test_get_id_by_username(self): def test_get_id_by_username(self):
self.assertEqual(PUBLIC_PROFILE_ID, self.assertEqual(PUBLIC_PROFILE_ID,
instaloader.Profile.from_username(self.L.context, PUBLIC_PROFILE).userid) instaloader.Profile.from_username(self.L.context, PUBLIC_PROFILE).userid)