├── setup.py ├── .github └── workflows │ └── python-publish.yml ├── LICENSE ├── README.md ├── README.rst └── socialblade └── __init__.py /setup.py: -------------------------------------------------------------------------------- 1 | from setuptools import setup 2 | 3 | setup(name='socialblade', 4 | version='1.0.5.1', 5 | description='Object oriented SocialBlade API wrapper', 6 | long_description=open('README.rst', 'r').read() , 7 | author='sl4v', 8 | author_email='iamsl4v@gmail.com', 9 | url='https://github.com/sl4vkek/python-socialblade', 10 | packages=['socialblade'], 11 | install_requires=['cloudscraper', 'dateparser'], 12 | license="UNLICENSE" 13 | ) 14 | -------------------------------------------------------------------------------- /.github/workflows/python-publish.yml: -------------------------------------------------------------------------------- 1 | # This workflows will upload a Python Package using Twine when a release is created 2 | # For more information see: https://help.github.com/en/actions/language-and-framework-guides/using-python-with-github-actions#publishing-to-package-registries 3 | 4 | name: Upload Python Package 5 | 6 | on: 7 | release: 8 | types: [created] 9 | 10 | jobs: 11 | deploy: 12 | 13 | runs-on: ubuntu-latest 14 | 15 | steps: 16 | - uses: actions/checkout@v2 17 | - name: Set up Python 18 | uses: actions/setup-python@v2 19 | with: 20 | python-version: '3.x' 21 | - name: Install dependencies 22 | run: | 23 | python -m pip install --upgrade pip 24 | pip install setuptools wheel twine 25 | - name: Build and publish 26 | env: 27 | TWINE_USERNAME: ${{ secrets.PYPI_USERNAME }} 28 | TWINE_PASSWORD: ${{ secrets.PYPI_PASSWORD }} 29 | run: | 30 | python setup.py sdist bdist_wheel 31 | twine upload dist/* 32 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | This is free and unencumbered software released into the public domain. 2 | 3 | Anyone is free to copy, modify, publish, use, compile, sell, or 4 | distribute this software, either in source code form or as a compiled 5 | binary, for any purpose, commercial or non-commercial, and by any 6 | means. 7 | 8 | In jurisdictions that recognize copyright laws, the author or authors 9 | of this software dedicate any and all copyright interest in the 10 | software to the public domain. We make this dedication for the benefit 11 | of the public at large and to the detriment of our heirs and 12 | successors. We intend this dedication to be an overt act of 13 | relinquishment in perpetuity of all present and future rights to this 14 | software under copyright law. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 17 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 18 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 19 | IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR 20 | OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 21 | ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 22 | OTHER DEALINGS IN THE SOFTWARE. 23 | 24 | For more information, please refer to 25 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Socialblade API wrapper 2 | Socialblade API wrapper.
3 | ***Added Twitch and StoryFire support*** 4 | ## Examples 5 | ### Live YouTube subscriber count 6 | Prints PewDiePie's subscriber count in real time. 7 | ```python 8 | from socialblade import YouTubeChannel 9 | 10 | 11 | pewdiepie_channel = YouTubeChannel('UC-lHJZR3Gqxm24_Vd_AJ5Yw') 12 | 13 | for sub in pewdiepie_channel.live_subscriber_count_generator(): 14 | print(sub) 15 | ``` 16 | You could also just get the subscriber count as it is at the time, like this: 17 | ```python 18 | from socialblade import YouTubeChannel 19 | 20 | 21 | pewdiepie_channel = YouTubeChannel('UC-lHJZR3Gqxm24_Vd_AJ5Yw') 22 | 23 | print(pewdiepie_channel.get_subscriber_count()) 24 | ``` 25 | ### Export a Channel's Most Viewed Videos Statistics to CSV 26 | In this example we are exporting statistics about PewDiePie's most viewed videos to CSV. 27 | ```python 28 | from socialblade import YouTubeChannel 29 | import csv 30 | from datetime import datetime 31 | import locale 32 | 33 | 34 | locale.setlocale(locale.LC_ALL, '') 35 | 36 | 37 | def create_more_readable_ints(integer): 38 | return locale.currency(integer, symbol=False, grouping=True).replace('.00', '').replace(',', "'") 39 | 40 | 41 | pewdiepie_channel = YouTubeChannel('UC-lHJZR3Gqxm24_Vd_AJ5Yw') 42 | 43 | writer = csv.writer( 44 | open( 45 | 'PewDiePie Most Viewed Videos {}.csv'.format(str(datetime.now().date())), 46 | 'w', 47 | newline='', 48 | encoding='utf-8' 49 | ) 50 | ) 51 | writer.writerow( 52 | ['Channel', 'Title', 'Created at', 'Views', 'Comments'] 53 | ) 54 | for video in pewdiepie_channel.get_most_viewed_videos(): 55 | writer.writerow( 56 | [ 57 | 'PewDiePie', 58 | video.title, 59 | str(video.created_at), 60 | create_more_readable_ints(video.views_num), 61 | create_more_readable_ints(video.comments_num) 62 | ] 63 | ) 64 | ``` 65 | You could do the same thing to any channel. You could also export different types of statistics about videos, which I will list the functions for them here: 66 | - socialblade.YouTubeChannel(channel_id).get_latest_videos() 67 | - socialblade.YouTubeChannel(channel_id).get_most_viewed_videos() 68 | - socialblade.YouTubeChannel(channel_id).get_highest_rated_videos() 69 | - socialblade.YouTubeChannel(channel_id).get_most_relevant_videos() 70 | 71 | ### Get live Twitter follower count 72 | The Twitter functionality is limited in this wrapper to retrieving follower counts. 73 | You could get a Twitter user's live follower count similer to how you get a youtuber's live follower count: 74 | ```python 75 | from socialblade import TwitterUser 76 | 77 | 78 | donald_trump_twitter = TwitterUser('realdonaldtrump').initalize() 79 | 80 | for follower in donald_trump_twitter.live_follower_counter(request_delay=500): 81 | print(follower) 82 | ``` 83 | You could also get the follower count as it is at the moment, like so: 84 | ``` 85 | from socialblade import TwitterUser 86 | 87 | 88 | donald_trump_twitter = TwitterUser('realdonaldtrump').initalize() 89 | 90 | print(donald_trump_twitter.get_follower_count()) 91 | ``` 92 | ### Get live Twitch and StoryFire follower counts 93 | Like Twitter, Twitch and StoryFire functionality is also limited to retrieving follower counts. 94 | You could compare the follower counts of a user's multiple platforms, whether that be Twitch and Twitter...:
95 | *WARNING: Twitch, Dailymotion and StoryFire may or may not work. We are still working on this issue* 96 | ```python 97 | from socialblade import TwitterUser, TwitchUser 98 | 99 | 100 | user = 'michaelreeves' 101 | 102 | reeves_twitter = TwitterUser(user).initalize() 103 | reeves_twitch = TwitchUser(user).initalize() 104 | 105 | twitter_followers = reeves_twitter.get_follower_count() 106 | twitch_followers = reeves_twitch.get_follower_count() 107 | 108 | if twitter_followers > twitch_followers: 109 | print(f"{user} has {twitter_followers - twitch_followers} more followers on Twitch than on Twitter.") 110 | else: 111 | print(f"{user} has {twitch_followers - twitter_followers} more followers on Twitter than on Twitch.") 112 | ``` 113 | ...or StoryFire and YouTube: 114 | ```python 115 | from socialblade import YouTubeChannel, StoryFireUser 116 | 117 | 118 | rgt_youtube = YouTubeChannel('UCA5RGaQc-a8tIX_AqTTmWdw').initalize() 119 | rgt_storyfire = StoryFireUser('1fozx1kcs0tuj3').initalize() 120 | 121 | for sf_subscribers in rgt_storyfire.live_follower_counter(): 122 | for yt_subscribers in rgt_youtube.live_subscriber_count_generator(): 123 | print(f"{yt_subscribers} on YouTube vs {sf_subscribers} on StoryFire.") 124 | ``` 125 | ### Get live Dailymotion follower counts. 126 | ```python 127 | from socialblade import DailymotionUser 128 | 129 | 130 | newsy = DailymotionUser('newsy').initalize() 131 | print(newsy.get_follower_count()) 132 | 133 | for follower in newsy.live_follower_counter(request_delay=500): 134 | print(follower) 135 | ``` 136 | -------------------------------------------------------------------------------- /README.rst: -------------------------------------------------------------------------------- 1 | Socialblade API wrapper 2 | ======================= 3 | 4 | | Socialblade API wrapper. 5 | | ***Added Twitch and StoryFire support*** 6 | 7 | Examples 8 | -------- 9 | 10 | Live YouTube subscriber count 11 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 12 | 13 | Prints PewDiePie's subscriber count in real time. 14 | 15 | .. code:: python 16 | 17 | from socialblade import YouTubeChannel 18 | 19 | 20 | pewdiepie_channel = YouTubeChannel('UC-lHJZR3Gqxm24_Vd_AJ5Yw') 21 | 22 | for sub in pewdiepie_channel.live_subscriber_count_generator(): 23 | print(sub) 24 | 25 | You could also just get the subscriber count as it is at the time, like 26 | this: 27 | 28 | .. code:: python 29 | 30 | from socialblade import YouTubeChannel 31 | 32 | 33 | pewdiepie_channel = YouTubeChannel('UC-lHJZR3Gqxm24_Vd_AJ5Yw') 34 | 35 | print(pewdiepie_channel.get_subscriber_count()) 36 | 37 | Export a Channel's Most Viewed Videos Statistics to CSV 38 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 39 | 40 | In this example we are exporting statistics about PewDiePie's most 41 | viewed videos to CSV. 42 | 43 | .. code:: python 44 | 45 | from socialblade import YouTubeChannel 46 | import csv 47 | from datetime import datetime 48 | import locale 49 | 50 | 51 | locale.setlocale(locale.LC_ALL, '') 52 | 53 | 54 | def create_more_readable_ints(integer): 55 | return locale.currency(integer, symbol=False, grouping=True).replace('.00', '').replace(',', "'") 56 | 57 | 58 | pewdiepie_channel = YouTubeChannel('UC-lHJZR3Gqxm24_Vd_AJ5Yw') 59 | 60 | writer = csv.writer( 61 | open( 62 | 'PewDiePie Most Viewed Videos {}.csv'.format(str(datetime.now().date())), 63 | 'w', 64 | newline='', 65 | encoding='utf-8' 66 | ) 67 | ) 68 | writer.writerow( 69 | ['Channel', 'Title', 'Created at', 'Views', 'Comments'] 70 | ) 71 | for video in pewdiepie_channel.get_most_viewed_videos(): 72 | writer.writerow( 73 | [ 74 | 'PewDiePie', 75 | video.title, 76 | str(video.created_at), 77 | create_more_readable_ints(video.views_num), 78 | create_more_readable_ints(video.comments_num) 79 | ] 80 | ) 81 | 82 | You could do the same thing to any channel. You could also export 83 | different types of statistics about videos, which I will list the 84 | functions for them here: 85 | 86 | - socialblade.YouTubeChannel(channel\_id).get\_latest\_videos() 87 | - socialblade.YouTubeChannel(channel\_id).get\_most\_viewed\_videos() 88 | - socialblade.YouTubeChannel(channel\_id).get\_highest\_rated\_videos() 89 | - socialblade.YouTubeChannel(channel\_id).get\_most\_relevant\_videos() 90 | 91 | Get live Twitter follower count 92 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 93 | 94 | | The Twitter functionality is limited in this wrapper to retrieving 95 | follower counts. 96 | | You could get a Twitter user's live follower count similer to how you 97 | get a youtuber's live follower count: 98 | 99 | .. code:: python 100 | 101 | from socialblade import TwitterUser 102 | 103 | 104 | donald_trump_twitter = TwitterUser('realdonaldtrump').initalize() 105 | 106 | for follower in donald_trump_twitter.live_follower_counter(request_delay=500): 107 | print(follower) 108 | 109 | You could also get the follower count as it is at the moment, like so: 110 | 111 | :: 112 | 113 | from socialblade import TwitterUser 114 | 115 | 116 | donald_trump_twitter = TwitterUser('realdonaldtrump').initalize() 117 | 118 | print(donald_trump_twitter.get_follower_count()) 119 | 120 | Get live Twitch and StoryFire follower counts 121 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 122 | 123 | | Like Twitter, Twitch and StoryFire functionality is also limited to 124 | retrieving follower counts. 125 | | You could compare the follower counts of a user's multiple platforms, 126 | whether that be Twitch and Twitter...: 127 | | *WARNING: Twitch, Dailymotion and StoryFire may or may not work. We 128 | are still working on this issue* 129 | 130 | .. code:: python 131 | 132 | from socialblade import TwitterUser, TwitchUser 133 | 134 | 135 | user = 'michaelreeves' 136 | 137 | reeves_twitter = TwitterUser(user).initalize() 138 | reeves_twitch = TwitchUser(user).initalize() 139 | 140 | twitter_followers = reeves_twitter.get_follower_count() 141 | twitch_followers = reeves_twitch.get_follower_count() 142 | 143 | if twitter_followers > twitch_followers: 144 | print(f"{user} has {twitter_followers - twitch_followers} more followers on Twitch than on Twitter.") 145 | else: 146 | print(f"{user} has {twitch_followers - twitter_followers} more followers on Twitter than on Twitch.") 147 | 148 | ...or StoryFire and YouTube: 149 | 150 | .. code:: python 151 | 152 | from socialblade import YouTubeChannel, StoryFireUser 153 | 154 | 155 | rgt_youtube = YouTubeChannel('UCA5RGaQc-a8tIX_AqTTmWdw').initalize() 156 | rgt_storyfire = StoryFireUser('1fozx1kcs0tuj3').initalize() 157 | 158 | for sf_subscribers in rgt_storyfire.live_follower_counter(): 159 | for yt_subscribers in rgt_youtube.live_subscriber_count_generator(): 160 | print(f"{yt_subscribers} on YouTube vs {sf_subscribers} on StoryFire.") 161 | 162 | Get live Dailymotion follower counts. 163 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 164 | 165 | .. code:: python 166 | 167 | from socialblade import DailymotionUser 168 | 169 | 170 | newsy = DailymotionUser('newsy').initalize() 171 | print(newsy.get_follower_count()) 172 | 173 | for follower in newsy.live_follower_counter(request_delay=500): 174 | print(follower) 175 | 176 | -------------------------------------------------------------------------------- /socialblade/__init__.py: -------------------------------------------------------------------------------- 1 | import cloudscraper 2 | import json 3 | import dateparser 4 | from time import sleep 5 | import re 6 | 7 | 8 | class FollowerCounter: 9 | 10 | def __init__(self, tag, lookup_url, regex, regex_url=None): 11 | self.__s = cloudscraper.create_scraper() 12 | self.lookup_url = lookup_url 13 | if regex: 14 | response = self.__s.get(regex_url.replace('{tag}', tag)).text 15 | matches = re.search(r"

(.+)

", response) 16 | tag = matches.groups(1)[0] 17 | self.tag = tag 18 | 19 | def get_follower_count(self): 20 | return int( 21 | self.__s.get( 22 | self.lookup_url, 23 | params={ 24 | 'query': self.tag 25 | } 26 | ).content.decode() 27 | ) 28 | 29 | def fail_safe_get_follower_count(self): 30 | while True: 31 | try: 32 | follower_count = self.get_follower_count() 33 | return follower_count 34 | except ValueError: 35 | pass 36 | 37 | def live_follower_counter(self, request_delay=500): 38 | while True: 39 | try: 40 | yield self.get_follower_count() 41 | sleep(request_delay) 42 | except ValueError: 43 | pass 44 | 45 | 46 | class DailymotionUser(FollowerCounter): 47 | 48 | def __init__(self, tag): 49 | super().__init__(tag, lookup_url='https://bastet.socialblade.com/dailymotion/lookup', regex=True, 50 | regex_url="https://socialblade.com/dailymotion/user/{tag}/realtime") 51 | 52 | def initalize(self): 53 | return super() 54 | 55 | 56 | class StoryFireUser(FollowerCounter): 57 | 58 | def __init__(self, channel_id): 59 | super().__init__(tag=channel_id, lookup_url='https://bastet.socialblade.com/storyfire/lookup', regex=False) 60 | 61 | def initalize(self): 62 | return super() 63 | 64 | 65 | class TwitchUser(FollowerCounter): 66 | 67 | def __init__(self, tag): 68 | super().__init__(tag, lookup_url='https://bastet.socialblade.com/twitch/lookup', regex=True, regex_url="https://socialblade.com/twitch/user/{tag}/realtime") 69 | 70 | def initalize(self): 71 | return super() 72 | 73 | 74 | class TwitterUser(FollowerCounter): 75 | 76 | def __init__(self, tag): 77 | super().__init__(tag, lookup_url='https://bastet.socialblade.com/twitter/lookup', regex=False) 78 | 79 | def initalize(self): 80 | return super() 81 | 82 | 83 | class YouTubeVideo: 84 | 85 | def __init__(self, video_id, title, created_at, comments_num, views_num, rating): 86 | self.video_id = video_id 87 | self.title = title 88 | self.created_at = dateparser.parse(created_at).date() 89 | self.comments_num = int(comments_num) 90 | self.views_num = int(views_num) 91 | self.rating = rating 92 | 93 | 94 | class YouTubeChannel: 95 | 96 | def __init__(self, channel_id): 97 | self.channel_id = channel_id 98 | self.__s = cloudscraper.create_scraper() 99 | 100 | @staticmethod 101 | def __add_videos(videos): 102 | for video in videos: 103 | try: 104 | yield YouTubeVideo( 105 | video_id=video['videoId'], 106 | title=video['title'], 107 | created_at=video['created_at'], 108 | comments_num=video['comments'], 109 | views_num=video['views'], 110 | rating=video['rating'] 111 | ) 112 | except KeyError: 113 | pass 114 | 115 | def get_latest_videos(self): 116 | """ 117 | :yield: 50 or less YouTubeVideo objects 118 | """ 119 | videos = self.__s.post( 120 | 'https://socialblade.com/js/class/youtube-video-recent', 121 | data={ 122 | 'channelid': self.channel_id 123 | } 124 | ).content.decode() 125 | videos = json.loads(videos) 126 | return YouTubeChannel.__add_videos(videos) 127 | 128 | def get_most_viewed_videos(self): 129 | """ 130 | :yield: 50 or less YouTubeVideo objects 131 | """ 132 | videos = self.__s.post( 133 | 'https://socialblade.com/js/class/youtube-video-mostviewed', 134 | data={ 135 | 'channelid': self.channel_id 136 | } 137 | ).content.decode() 138 | videos = json.loads(videos) 139 | return YouTubeChannel.__add_videos(videos) 140 | 141 | def get_highest_rated_videos(self): 142 | """ 143 | :yield: 50 or less YouTubeVideo objects 144 | """ 145 | videos = self.__s.post( 146 | 'https://socialblade.com/js/class/youtube-video-highestrated', 147 | data={ 148 | 'channelid': self.channel_id 149 | } 150 | ).content.decode() 151 | videos = json.loads(videos) 152 | return YouTubeChannel.__add_videos(videos) 153 | 154 | def get_most_relevant_videos(self): 155 | """ 156 | :yield: 50 or less YouTubeVideo objects 157 | """ 158 | videos = self.__s.post( 159 | 'https://socialblade.com/js/class/youtube-video-relevant', 160 | data={ 161 | 'channelid': self.channel_id 162 | } 163 | ).content.decode() 164 | videos = json.loads(videos) 165 | return YouTubeChannel.__add_videos(videos) 166 | 167 | def get_subscriber_count(self): 168 | """ 169 | :return: returns the channel's subscriber count (int). 170 | """ 171 | return int( 172 | self.__s.get( 173 | 'https://bastet.socialblade.com/youtube/lookup', 174 | params= 175 | { 176 | 'query': self.channel_id 177 | } 178 | ).content.decode().strip().replace("'", '') 179 | ) 180 | 181 | def live_subscriber_count_generator(self, request_delay=1000): 182 | """ 183 | :param request_delay: delay between subscriber yield in milliseconds (defaults to 1000) 184 | :yield: yields the subscriber count of the youtube channel (int) in an infinite loop 185 | """ 186 | while True: 187 | try: 188 | yield self.get_subscriber_count() 189 | sleep(request_delay / 1000) 190 | except ValueError: 191 | pass 192 | --------------------------------------------------------------------------------