diff --git a/README.rst b/README.rst index 82be720..3e9541c 100644 --- a/README.rst +++ b/README.rst @@ -247,6 +247,12 @@ To download the last 20 pictures with hashtag #cat, do loader.download_hashtag('cat', max_count=20) +If logged in, Instaloader is also able to download user stories: + +.. code:: python + + loader.download_stories() + Each Instagram profile has its own unique ID which stays unmodified even if a user changes his/her username. To get said ID, given the profile's name, you may call diff --git a/instaloader.py b/instaloader.py index 0aec129..3a75b94 100755 --- a/instaloader.py +++ b/instaloader.py @@ -75,6 +75,10 @@ class InvalidArgumentException(NonfatalException): pass +class BadResponseException(NonfatalException): + pass + + class BadCredentialsException(InstaloaderException): pass @@ -624,10 +628,7 @@ class Instaloader: self._log() return downloaded - def download_stories(self, - username: str, - sessionfile: str, download_videos: bool = True, fast_update: bool = False) -> None: """ @@ -637,18 +638,21 @@ class Instaloader: :param download_videos: True, if videos should be downloaded """ - self.load_session_from_file(username, sessionfile) + if self.username is None: + raise LoginRequiredException('Login required to download stories') - header = self.session.headers - header['User-Agent'] = 'Instagram 10.3.2 (iPhone7,2; iPhone OS 9_3_3; en_US; en-US; scale=2.00; 750x1334) AppleWebKit/420+' + tempsession = copy_session(self.session) + header = tempsession.headers + header['User-Agent'] = 'Instagram 10.3.2 (iPhone7,2; iPhone OS 9_3_3; en_US; en-US; scale=2.00; 750x1334) ' \ + 'AppleWebKit/420+' del header['Host'] del header['Origin'] del header['X-Instagram-AJAX'] del header['X-Requested-With'] - self._log("Logged in as %s." % username) + self._sleep() url = 'https://i.instagram.com/api/v1/feed/reels_tray/' - resp = self.session.get(url) + resp = tempsession.get(url) if resp.status_code != 200: raise ConnectionException('Failed to fetch stories.') @@ -656,7 +660,7 @@ class Instaloader: data = json.loads(resp.text) if not 'tray' in data: - raise InstaloaderException('Bad story reel JSON.') + raise BadResponseException('Bad story reel JSON.') totalcount = sum([len(us["items"]) if "items" in us else 0 for us in data["tray"]]) count = 1 @@ -679,8 +683,8 @@ class Instaloader: date /= 1000 date_stamp = datetime.datetime.fromtimestamp(date) - dirname = self.dirname_pattern.format(profile=name, target=name) - filename = dirname + '/' + self.filename_pattern.format(profile=name, target=name, + dirname = self.dirname_pattern.format(profile=name, target=':stories') + filename = dirname + '/' + self.filename_pattern.format(profile=name, target=':stories', date=date_stamp, shortcode=shortcode) os.makedirs(dirname, exist_ok=True) @@ -702,7 +706,7 @@ class Instaloader: date_epoch=date) if "video_duration" in item and self.sleep: time.sleep(item["video_duration"]) - if len(item["story_locations"]) > 0: + if item["story_locations"]: location = item["story_locations"][0]["location"] if location: self.save_location(filename, location, date) @@ -710,7 +714,6 @@ class Instaloader: if fast_update and not downloaded: break - def download_feed_pics(self, max_count: int = None, fast_update: bool = False, filter_func: Optional[Callable[[Dict[str, Dict[str, Any]]], bool]] = None, download_videos: bool = True, geotags: bool = False,