follow()   B
last analyzed

Complexity

Conditions 5

Size

Total Lines 17

Duplication

Lines 11
Ratio 64.71 %

Importance

Changes 6
Bugs 5 Features 3
Metric Value
cc 5
dl 11
loc 17
rs 8.5454
c 6
b 5
f 3
1
# -*- coding: utf-8 -*-
2
import requests
3
import sys
4
import socket
5
import os
6
import datetime
7
from functools import reduce
8
import time
9
from random import randint
10
import sys
11
from art import tprint
12
DEBUG=False
13
import gc
14
15
def help_func():
16
    tprint("help")
17
    print("By Sepand Haghighi\n")
18
    print("python -m gitfollow")
19
    print("- run  (run gitfollow)\n")
20
    print("- test (run tests)\n")
21
    print("- help (help page)\n")
22
def zero_insert(input_string):
23
    '''
24
    This function get a string as input if input is one digit add a zero
25
    :param input_string: input digit az string
26
    :type input_string:str
27
    :return: modified output as str
28
    '''
29
    if len(input_string)==1:
30
        return "0"+input_string
31
    return input_string
32
33
def time_convert(input_string):
34
    '''
35
    This function convert input_string from uptime from sec to DD,HH,MM,SS Format
36
    :param input_string: input time string  in sec
37
    :type input_string:str
38
    :return: converted time as string
39
    '''
40
    input_sec=float(input_string)
41
    input_minute=input_sec//60
42
    input_sec=int(input_sec-input_minute*60)
43
    input_hour=input_minute//60
44
    input_minute=int(input_minute-input_hour*60)
45
    input_day=int(input_hour//24)
46
    input_hour=int(input_hour-input_day*24)
47
    return zero_insert(str(input_day))+" days, "+zero_insert(str(input_hour))+" hour, "+zero_insert(str(input_minute))+" minutes, "+zero_insert(str(input_sec))+" seconds"
48
49
def url_maker_following(Name,page_number):
50
    '''
51
    This function return github following page url
52
    :param Name: Username
53
    :param page_number: page nubmer of following page
54
    :type Name:str
55
    :type Page:int
56
    :return: github following url as string
57
    '''
58
    return "https://github.com/"+Name+"?page="+str(page_number)+"&tab=following"
59
60
def url_maker_repo(Name,page_number):
61
    '''
62
    This function return github repo page url
63
    :param Name: Username
64
    :param page_number: page nubmer of repos page
65
    :type Name:str
66
    :type Page:int
67
    :return: github repos url as string
68
    '''
69
    return "https://github.com/"+Name+"?page="+str(page_number)+"&tab=repositories"
70
def url_maker_follower(Name,page_number):
71
    '''
72
    This function return github follower page url
73
    :param Name: username
74
    :param page_number: page number of follower page
75
    :type Name:str
76
    :type page_number:int
77
    :return: github follower url as string
78
    '''
79
    return "https://github.com/" + Name + "?page=" + str(page_number) + "&tab=followers"
80
def url_maker_star(Name,page_number):
81 View Code Duplication
    '''
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
82
    This function return github stars page url
83
    :param Name: username
84
    :param page_number: page number of stars
85
    :type Name :str
86
    :type page_number:int
87
    :return: github star url as string
88
    '''
89
    return "https://github.com/"+Name+"?page="+str(page_number)+"&tab=stars"
90
def repo_extract(input_string,username):
91
    '''
92
    This function extract repo from raw_html
93
    :param input_string: raw input html
94
    :param user_name: user_name
95
    :type input_string:str
96
    :type user_name:str
97
    :return: repo_list as list
98
    '''
99
    try:
100
        user_list=[]
101
        index=0
102
        shift=len(username)+1
103
        while(index!=-1):
104 View Code Duplication
            index=input_string.find('src="/'+username,index+shift,len(input_string))
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
105
            length=input_string[index:].find('graphs/')
106
            star_repo=input_string[index+5:index+length]
107
            if star_repo.find("<svg")==-1 and len(star_repo)!=0:
108
                user_list.append(star_repo)
109
        return user_list
110
    except Exception as ex:
111
        pass
112
113
def star_extract(input_string):
114
    '''
115
    This function extract stared repo from raw_html
116
    :param input_string: raw input html
117
    :param follower_name: follower_name
118
    :type input_string:str
119
    :type follower_name:str
120
    :return: user_list as list
121
    '''
122
    user_list=[]
123
    index=0
124
    try:
125
        while(index!=-1):
126
            index=input_string.find('<a class="muted-link mr-3',index+33,len(input_string))
127
            length=input_string[index+33:].find('stargazers">\n')
128
            star_repo=input_string[index+34:index+33+length]
129
            if star_repo.find("<svg")==-1 and len(star_repo)!=0:
130
                user_list.append(star_repo)
131
        return user_list
132
    except Exception as ex:
133
        pass
134
def org_list_gen(name):
135
    url=url_maker_follower(name,1)
136
    raw_data=get_html(url)
137
    org_index = raw_data.find("col-9 float-left pl-2")
138
    org_data = raw_data[:org_index]
139
    index=0
140
    org_list=[]
141
    while (index != -1):
142
        index = org_data.find('alt="@', index + 6, len(org_data))
143
        length = org_data[index + 6:].find('"')
144
        org_name = org_data[index + 6:index + 6 + length]
145
        if org_name != name:
146
            org_list.append(org_name)
147
    return org_list[:-1]
148
def user_list_gen(input_string,follower_name):
149
    '''
150
    This function extract usernames from raw_html
151
    :param input_string: raw input html
152
    :param follower_name: follower_name
153
    :type input_string:str
154
    :type follower_name:str
155
    :return: user_list as list
156
    '''
157
    try:
158
        user_list = []
159
        index = 0
160
        org_index=input_string.find("col-9 float-left pl-2")
161
        repo_data=input_string[org_index:]
162
        while(index!=-1):
163
            index=repo_data.find('alt="@',index+6,len(input_string))
164
            length=repo_data[index+6:].find('"')
165
            user_name=repo_data[index+6:index+6+length]
166
            if user_name!=follower_name:
167
                user_list.append(user_name)
168
        return user_list[:-1]
169
    except Exception as ex:
170
        pass
171
def get_html(url):
172
    '''
173
    This function extract raw_html file
174
    :param url: url
175
    :type url:str
176
    :return: html data
177
    '''
178
    time.sleep(create_random_sleep())
179
    if internet()==True:
180
        new_session=requests.session()
181
        new_session.cookies.clear()
182 View Code Duplication
        raw_html=new_session.get(url)
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
183
        new_session.close()
184
        raw_data=raw_html.text
185
        if "Not Found" in raw_data:
186
            print("Invalid Github User")
187
            sys.exit()
188
        return raw_data
189
    else:
190
        print("Error In Internet")
191
        pass
192
193
194
def end_check(input_string):
195
    '''
196
    This function check end page
197
    :param input_string: raw html
198
    :type input_string:str
199
    :return: True or False
200
    '''
201
    if input_string.find("reached the end")!=-1:
202
        return True
203
    else:
204
        return False
205
def follower_list_gen(follower_name,page_number=0,counter=0):
206
    '''
207
    This function generate follower_list
208
    :param follower_name: username
209
    :type follower_name:str
210
    :return: username follower list
211
    '''
212
    try:
213
        follower_list = []
214
        while (True):
215
            page_number += 1
216
            follower_url = url_maker_follower(follower_name, page_number)
217
            follower_html = get_html(follower_url)
218
            if end_check(follower_html) == True:
219
                break
220
            temp_list = user_list_gen(follower_html,follower_name)
221
            follower_list.extend(temp_list)
222
        return follower_list
223
    except Exception as ex:
224
        if counter>3:
225
            sys.exit()
226
        error_log("Error In Page "+str(page_number)+" Follower Page")
227
        follower_list_gen(follower_name,page_number,counter+1)
228
def repo_list(username,page_number=0,counter=0):
229
    '''
230
    This function return stared_repo list
231
    :param username: username
232
    :type username:str
233
    :return: stared repo as list
234
    '''
235
    try:
236
        repo_list_temp=[]
237
        while (True):
238
            page_number += 1
239
            repo_url = url_maker_repo(username, page_number)
240
            repo_html = get_html(repo_url)
241
            temp_list = repo_extract(repo_html,username)
242
            if len(temp_list)==0:
243
                break
244
            repo_list_temp.extend(temp_list)
245
        return repo_list_temp
246
    except Exception as ex:
247
        if counter>3:
248
            sys.exit()
249
        error_log("Error In Page " + str(page_number) + " Repos Page")
250
        repo_list(username,page_number,counter+1)
251
def star_list(username,page_number=0,counter=0):
252 View Code Duplication
    '''
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
253
    This function return stared_repo list
254
    :param username: username
255
    :type username:str
256
    :return: stared repo as list
257
    '''
258
    try:
259
        star_list_temp=[]
260
        while (True):
261
            page_number += 1
262
            star_url = url_maker_star(username, page_number)
263
            star_html = get_html(star_url)
264
            temp_list = star_extract(star_html)
265
            if len(temp_list)==0:
266
                break
267
            star_list_temp.extend(temp_list)
268
        return star_list_temp
269
    except Exception as ex:
270
        if counter>3:
271
            sys.exit()
272
        error_log("Error In Page " + str(page_number) + " Stars Page")
273
        star_list(username,page_number,counter+1)
274
275
def following_list_gen(follower_name,page_number=0,counter=0):
276
    '''
277
    This function generate following list
278
    :param follower_name: username
279
    :type follower_name:str
280
    :return: username following list
281
    '''
282
    try:
283
        following_list = []
284
        while (True):
285
            page_number+=1
286
            following_url = url_maker_following(follower_name, page_number)
287
            following_html = get_html(following_url)
288
            if end_check(following_html) == True:
289
                break
290
            temp_list = user_list_gen(following_html,follower_name)
291
            following_list.extend(temp_list)
292
        return following_list
293
    except Exception as ex:
294
        if counter>3:
295
            sys.exit()
296
        error_log("Error In Page " + str(page_number) + " Following Page")
297
        following_list_gen(follower_name,page_number,counter+1)
298
299
def error_log(msg):
300
    """
301
    Create the errorlog of the app
302
    :param msg: error message
303
    :type msg:str
304
    """
305
    if "log" not in os.listdir():
306
        os.mkdir("log")
307
    file = open(reduce(os.path.join, [os.getcwd(), "log", "error_log.txt"]), "a")
308
    file.write(str(datetime.datetime.now()) + " --> " + str(msg) + "\n")
309
    file.close()
310
311
def internet(host="8.8.8.8", port=53, timeout=10):
312
    """
313
    Check Internet Connections.
314
    :param  host: the host that check connection to
315
    :param  port: port that check connection with
316
    :param  timeout: times that check the connnection
317
    :type host:str
318
    :type port:int
319
    :type timeout:int
320
    :return bool: True if Connection is Stable
321
    >>> internet() # if there is stable internet connection
322
    True
323
    >>> internet() # if there is no stable internet connection
324
    False
325
    """
326
    try:
327
        socket.setdefaulttimeout(timeout)
328
        socket.socket(socket.AF_INET, socket.SOCK_STREAM).connect((host, port))
329
        return True
330
    except Exception as ex:
331
        return False
332
333
def create_random_sleep(index=1,min_time=1,max_time=3):
334
    '''
335
    This function generate sleep time with random processes
336
    :param index: index to determine first page  and messages(index = 0 is for first page)
337
    :param min_time: minimum time of sleep
338
    :param max_time: maximum time of sleep
339
    :type index:int
340
    :type min_time:int
341
    :type max_time:int
342
    :return: time of sleep as integer (a number between max and min)
343
    '''
344
    if index==0:
345
        time_sleep = 5
346
        if DEBUG==True:
347
            print("Wait "+str(time_sleep)+" sec for first search . . .")
348
    else:
349
        time_sleep = randint(min_time, max_time)
350
        if DEBUG==True:
351
            print("Wait "+str(time_sleep)+" sec for next search . . .")
352
    if DEBUG==True:
353
        print_line(70,"*")
354
    return time_sleep
355
356
def print_line(number=30,char="-"):
357
    '''
358
    This function print line in screen
359
    :param number: number of items in each line
360
    :param char: each char of line
361
    :return: None
362
    '''
363
    line=""
364
    for i in range(number):
365
        line=line+char
366
    print(line)
367
368
369
def list_maker(username,keyword=["1"]):
370
    '''
371
    This function create following and follower list
372
    :param username: username
373
    :type username:str
374
    :return: (list_1,list_2) as tuple
375
    '''
376
    try:
377
        print("Collecting Follower Information ...")
378
        print_line(70, "*")
379
        list_1 = follower_list_gen(username)
380
        file = open(username + "_follower.log", "w")
381
        print(str(len(list_1)) + " Followers --> " + username + "_follower.log")
382
        print_line(70, "*")
383
        file.write("\n".join(list_1))
384
        file.close()
385
        print('Collecting Following Information ...')
386
        print_line(70, "*")
387
        list_2 = following_list_gen(username)
388
        file = open(username + "_following.log", "w")
389
        print(str(len(list_2)) + " Following --> " + username + "_following.log")
390
        print_line(70, "*")
391
        file.write("\n".join(list_2))
392
        file.close()
393
        if "1" in keyword:
394
            print('Collecting Stars Information ...')
395
            print_line(70, "*")
396
            stars=star_list(username)
397
            file = open(username + "_stars.log", "w")
398
            print(str(len(stars)) + " Stars --> " + username + "_stars.log")
399
            print_line(70, "*")
400
            file.write("\n".join(stars))
401
            file.close()
402
        if "2" in keyword:
403
            print('Collecting Repos Information ...')
404
            print_line(70, "*")
405
            repos = repo_list(username)
406
            file = open(username + "_repos.log", "w")
407
            print(str(len(repos)) + " Repos --> " + username + "_repos.log")
408
            print_line(70, "*")
409
            file.write("\n".join(repos))
410
            file.close()
411
        if "3" in keyword:
412
            print('Collecting Organizations Information ...')
413
            print_line(70, "*")
414
            orgs = org_list_gen(username)
415
            file = open(username + "_orgs.log", "w")
416
            print(str(len(orgs)) + " Organizations --> " + username + "_orgs.log")
417
            print_line(70, "*")
418
            file.write("\n".join(orgs))
419
            file.close()
420
        return (sorted(list_1),sorted(list_2))
421
    except Exception as ex:
422
        error_log(str(ex))
423
424
def dif(list_1,list_2,username):
425
    '''
426
    This function generate dif files
427
    :param list_1:follower list
428
    :param list_2: following list
429
    :type list_1:list
430
    :type list_2:list
431
    :return: None
432
    '''
433
    try:
434
        file = open(username + "_NotFollower.log", "w")
435
        dif_list_1 = list(set(list_2) - set(list_1))
436
        print(str(len(dif_list_1)) + " Following - Not Follower --> " + username + "_NotFollower.log")
437
        print_line(70, "*")
438
        file.write("\n".join(dif_list_1))
439
        file.close()
440
        file = open(username + "_NotFollowing.log", "w")
441
        dif_list_2 = list(set(list_1) - set(list_2))
442
        print(str(len(dif_list_2)) + " Follower - Not Following --> " + username + "_NotFollowing.log")
443 View Code Duplication
        print_line(70, "*")
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
444
        file.write("\n".join(dif_list_2))
445
        file.close()
446
        return [sorted(dif_list_1),sorted(dif_list_2)]
447
    except Exception as ex:
448
        print("[Error] dif function faild")
449
def unfollow(username,password,id_list):
450
    for user in id_list:
451
        response=requests.delete("https://api.github.com/user/following/" + user, auth=(username, password))
452
        status_code=int(response.status_code)
453
        if status_code!=204:
454
            if status_code==401:
455
                print("[Error] Authentication Error")
456
                return False
457
            elif status_code==403:
458
                print("[Error] Maximum number of login attempts exceeded")
459
                sys.exit()
460 View Code Duplication
            else:
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
461
                print("[Error] in " + user + " unfollow!")
462
        else:
463
            print(user+" Unfollowed")
464
        time.sleep(3)
465
    return True
466
def follow(username,password,id_list):
467
    for user in id_list:
468
        response = requests.put("https://api.github.com/user/following/" + user, auth=(username, password))
469
        status_code = int(response.status_code)
470
        if status_code!=204:
471
            if status_code==401:
472
                print("[Error] Authentication Error")
473
                return False
474
            elif status_code==403:
475
                print("[Error] Maximum number of login attempts exceeded")
476
                sys.exit()
477
            else:
478
                print("[Error] in "+user+" follow!")
479
        else:
480
            print(user+" Followed")
481
        time.sleep(3)
482
    return True
483
def get_input(func_1=input,func_2=input):
484
    tprint("git\nfollow")
485
    username = func_1("Please Enter Your Github Username : ")
486
    keys=func_2("1- Collecting Stars Information\n2- Collecting Repos Information\n3- Collecting Organizations Information (Enter Number Seperated By , )")
487
    keys=keys.split(",")
488
    return [username,keys]
489
def run(func_1=input,func_2=input,func_3=input):
490
    password = ""
491
    auth=False
492
    time_1 = time.perf_counter()
493
    [username,keys]=get_input(func_1=func_1,func_2=func_2)
494
    (list_1, list_2) = list_maker(username,keys)
495
    dif_lists = dif(list_1, list_2, username)
496
    time_2 = time.perf_counter()
497
    dif_time = str(time_2 - time_1)
498
    print("Data Generated In " + time_convert(dif_time) + " sec")
499
    print("Log Files Are Ready --> " + os.getcwd())
500
    if len(dif_lists[0])>0:
501
        input_data = func_3("Unfollow Non-follower?Yes[y],No[n] ")
502
        if input_data.upper() == "Y":
503
            while(auth==False):
504
                password = func_2("Please Enter Password : ")
505
                print("Processing ... ")
506
                auth=unfollow(username, password, dif_lists[0])
507
    if len(dif_lists[1])>0:
508
        input_data = func_3("Follow Non-following?Yes[y],No[n] ")
509
        if input_data.upper() == "Y":
510
            if auth==True:
511
                print("Processing ... ")
512
                auth= follow(username, password, dif_lists[1])
513
            while(auth==False):
514
                password = func_2("Please Enter Password : ")
515
                print("Processing ... ")
516
                auth=follow(username, password, dif_lists[1])
517
    gc.collect()
518
519
def test_function_1(a):
520
    return 'sarminh'
521
def test_function_2(a):
522
    return "1,2,3"
523
def test_function_3(a):
524
    return "y"
525
526
527
528
529
530
531
532
533
534
535
536
537