· 9 years ago · Mar 25, 2017, 03:44 PM
1import csv
2import hashlib
3import json
4import lxml.html
5import random
6import requests
7import time
8
9
10class MusicallyFame():
11 phone_profiles = [
12 "lava",
13 "samsung",
14 "oneplusone",
15 "htc",
16 "nexus"
17 ]
18 phone_details = {
19 "lava": {
20 "os": "android 4.1.2",
21 "User-Agent": "Musical.ly/2016020601 (Android; LAVA LAVA 4.1.2;rv:16)",
22 "build": "2016020601",
23 "mobile": "LAVA Iris 501",
24 "model": "SM-G730V",
25 "sdk": "19"
26 },
27 "samsung": {
28 "os": "android 5.1.1",
29 "User-Agent": "Musical.ly/2016040101 (Android; Samsung Galaxy J3 5.1.1;rv:22)",
30 "build": "2016040101",
31 "mobile": "Samsung Galaxy J3 SM-J320Y",
32 "model": "SM-J320Y",
33 "sdk": "22"
34 },
35 "oneplusone": {
36 "os": "android 5.1.1",
37 "User-Agent": "Musical.ly/2016040101 (Android; OnePlus A0001 5.1.1;rv:22)",
38 "build": "2016040101",
39 "mobile": "OnePlus A0001",
40 "model": "A0001",
41 "sdk": "22"
42 },
43 "nexus": {
44 "os": "android 6.0.1",
45 "User-Agent": "Musical.ly/2016040101 (Android; LGE Nexus 5 6.0.1;rv:23)",
46 "build": "2016040101",
47 "mobile": "LGE Nexus 5",
48 "model": "Nexus 5",
49 "sdk": "22"
50 },
51 "htc": {
52 "os": "android 5.1.1",
53 "User-Agent": "Musical.ly/2016040101 (Android; HTC One A9 5.1.1;rv:22)",
54 "build": "2016040101",
55 "mobile": "HTC One A9",
56 "model": "A9",
57 "sdk": "22"
58 },
59 }
60
61 def __init__(self, input_file):
62 self.proxies = self.proxy_list()
63 self.input_file = input_file
64 self.common_header = {
65 "os": "android 4.1.2",
66 "User-Agent": "Musical.ly/2016020601 (Android; LAVA LAVA 4.1.2;rv:16)",
67 "build": "2016020601",
68 "mobile": "LAVA Iris 501",
69 "version": "4.7.5",
70 "X-Requested-With": "XMLHttpRequest",
71 "language": "en_US",
72 "Connection": "close",
73 "network": "WiFi",
74 "Host": "www.musical.ly",
75 "Accept-Encoding": "gzip",
76 "MIME-Version": "1.0"
77 }
78 self.signing_server = "http://45.55.203.163:8888/sign"
79 self.signature_data = {
80 "app": {
81 "-r": "Gvt1",
82 "os": "android 4.1.2",
83 "version": "4.7.5"
84 },
85 "ostype": "and",
86 "imei": "51a4454f",
87 "mac": "4C:3C:16:82:EE:F3",
88 "model": "SM-G730V",
89 "sdk": "19",
90 }
91 self.session = requests.Session()
92 # self.session.mount('https://', HTTPAdapter(max_retries=50))
93
94 def proxy_list(self):
95 content = requests.get("http://free-proxy-list.net").text
96 doc = lxml.html.document_fromstring(content)
97 lines = doc.cssselect('table.fpltable tr')
98 temp_proxies = []
99 for line in lines:
100 tds = line.cssselect('td')
101 if not tds:
102 continue
103 anonymity = tds[4].text
104 if anonymity != 'transparent' and len(tds) > 7:
105 temp_proxies.append({
106 'ip_address': tds[0].text,
107 'port': tds[1].text,
108 'country_code': tds[2].text,
109 })
110 print len(temp_proxies)
111
112 return temp_proxies
113
114 def alter_handle(self, handle):
115 alter_option = random.choice([1, 2, 3])
116 if alter_option == 1:
117 handle += random.choice([str(n) for n in range(10)])
118 elif alter_option == 2:
119 _, __ = handle[-1], handle[-2]
120 handle = handle[:-3] + _ + __
121 else:
122 handle = handle[:-1]
123
124 return handle
125
126 def generate_user(self):
127 mail_servers = ["@newmail.com", "@gmail.com", "@hotmail.com", "@yahoo.com", "@outlook.com"]
128 with open(self.input_file, "rb") as csvfile:
129 reader = csv.reader(csvfile)
130 reader.next() # Skip the header row
131 for row in reader:
132 scraped_data = dict()
133 scraped_data["country"] = row[0].decode('string-escape').decode("utf-8")
134 scraped_data["nick_name"] = row[2].decode('string-escape').decode("utf-8")
135 scraped_data["photo"] = "./photos"+row[3]+".jpg"
136
137 handle = row[3].decode('string-escape').decode("utf-8")
138 scraped_data["handle"] = self.alter_handle(handle)
139 scraped_data["bio"] = row[4].decode('string-escape').decode("utf-8")
140 scraped_data["email"] = scraped_data["handle"]+random.choice(mail_servers)
141 scraped_data["password"] = scraped_data["handle"][::-1]+random.choice(["1", "2", "3", "4", "5"])
142 yield scraped_data
143
144 def get_likes(self, account, like_counts):
145 return
146
147 def get_follows(self, account, follow_counts):
148 return
149
150 def get_a_phone(self, phone):
151 #random value for imei and mac no
152 imei = ''.join(random.choice('0123456789abcdef') for i in range(8))
153 val = ''.join(random.choice('0123456789ABCDEF') for i in range(12))
154 mac = ':'.join(val[i:i+2] for i in xrange(0, 12, 2))
155 self.signature_data["imei"] = imei
156 self.signature_data["mac"] = mac
157
158 if phone in self.phone_profiles:
159 self.common_header["os"] = self.phone_details[phone]["os"]
160 self.common_header["User-Agent"] = self.phone_details[phone]["User-Agent"]
161 self.common_header["build"] = self.phone_details[phone]["build"]
162 self.common_header["mobile"] = self.phone_details[phone]["mobile"]
163
164 self.signature_data["app"]["os"] = self.phone_details[phone]["os"]
165 self.signature_data["model"] = self.phone_details[phone]["model"]
166 self.signature_data["sdk"] = self.phone_details[phone]["sdk"]
167
168 return
169
170 def get_proxy(self, country):
171 if not self.proxies:
172 self.proxies = self.proxy_list()
173
174 temp_proxies = list(self.proxies)
175 retries = 0
176
177 for proxy in temp_proxies:
178 if proxy['country_code'] == country:
179 address = "%s:%s" % (proxy['ip_address'], proxy['port'])
180 self.proxies.remove(proxy)
181 try:
182 _proxy = {"http": "http://"+address, "https": "https://"+address}
183 response = self.session.get("http://ipecho.net/plain", proxies=_proxy)
184 if address.split(':')[0] == response.text:
185 return _proxy
186
187 raise Exception()
188 except:
189 print 'get error, when checking proxy, try to get next proxy'
190 retries += 1
191 if retries == 5:
192 self.proxy_list()
193
194 if retries == 10:
195 break
196
197 return False
198
199 def unset_proxy(self):
200 self.session.proxies = None
201
202 # Function to get signature
203 def get_signature(self):
204 payload = {"data": json.dumps(self.signature_data)}
205 response = self.session.get(self.signing_server, data=payload)
206 try:
207 return str(json.loads(response.text)["signature"])
208 except ValueError:
209 return "signature not received"
210
211 # function to generate get request Id
212 def get_unique_id(self):
213 request_id = hashlib.md5(str(random.random())).hexdigest()
214 request_id = request_id[:8]+"-"+request_id[8:12]+"-"+request_id[12:16]+"-"+request_id[16:20]+"-"+request_id[20:]
215 return request_id
216
217 # function for time stamp
218 def get_time_stamp(self):
219 a = time.time()*1000
220 return "%.0f" % a
221
222 def prepare_header(self, url, method):
223 request_id = self.get_unique_id()
224 timestamp = self.get_time_stamp()
225 self.session.headers.clear()
226 self.session.headers = dict(self.common_header)
227 self.session.headers["X-Request-ID"] = request_id
228 self.signature_data["app"]["X-Request-ID"] = request_id
229 self.signature_data["serviceTime"] = timestamp
230 self.signature_data["app"]["method"] = method
231 self.signature_data["app"]["url"] = url
232 request_signature = self.get_signature()
233 self.session.headers["X-Request-Sign2"] = request_signature
234 return
235
236 def prepare_registration_data(self, handle, email, password):
237 user = '''{"handle":"%s","email":"%s","password":"%s"}''' % (handle, email, password)
238 post_url = "http://www.musical.ly/rest/v2/users/register"
239 boundary = "27c8b11a-9b7e-4849-a665-7f1a04edf2b7"
240 data = (
241 """
242--%(boundary)s
243Content-Disposition: form-data; name="user"
244Content-Type: application/json; charset=utf-8
245Content-Length: %(content_length)s
246\r\n%(user)s
247--%(boundary)s--
248 """ % {
249 "boundary": boundary,
250 "content_length": len(user),
251 "user": user
252 }).replace("\n", "\r\n") # HTTP uses DOS-style line endings.
253
254 # update current headers
255 self.session.headers["Content-Type"] = "multipart/mixed; boundary=\"%s\"" % boundary
256 return data
257
258 def prepare_profile_data(self, user_id, instagram_id, handle, nick_name):
259 data = (
260 """
261--2b8a2224-07c6-4463-bb4b-364576e556ad
262Content-Disposition: form-data; name="user"
263Content-Type: application/json; charset=utf-8
264Content-Length: 276
265
266{"userSettingDTO":{"policyVersion":1,"duet":false,"secret":false,"hideLocation":false,"privateChat":true,"userId":%(user_id)},"instagramID":%(instagram_id),"userDesc":"Editing Test name","gender":"n","handle":%(handle),"nickName":%(nick_name),"userId":%(user_id)}
267--2b8a2224-07c6-4463-bb4b-364576e556ad--
268 """ % {
269 "user_id": user_id,
270 "instagram_id": instagram_id,
271 "handle": handle,
272 "nick_name": nick_name
273 })
274 return data
275
276 def register_accounts(self, count):
277 output_fp = open('success.csv', 'w')
278 output_writer = csv.writer(output_fp, delimiter=',')
279
280 all_users = self.generate_user()
281 for i in xrange(count):
282 user_data = all_users.next()
283 self.get_a_phone(random.choice(self.phone_profiles))
284 country = user_data["country"]
285 proxy = self.get_proxy(country)
286 if not proxy:
287 proxy = self.get_proxy("US")
288
289 if not proxy:
290 continue
291
292 method = "POST"
293 url = "https://www.musical.ly/rest/v2/users/register"
294 self.prepare_header(url, method)
295 handle = user_data["handle"]
296 email = user_data["email"]
297 password = user_data["password"]
298 data = self.prepare_registration_data(handle, email, password)
299
300 try:
301 response = self.session.post(url, data=data, proxies=proxy, headers=self.session.headers)
302
303 # profile edit
304 # put photo
305
306 if response.status_code == 200:
307 response_status = response.json().get('success', False)
308 if response_status:
309 output_writer.writerow([handle, password, email])
310 args = {
311 "username": "@"+handle,
312 "password": password,
313 "remember_me": "on"
314 }
315 login_url = "http://www.musical.ly/v2/login.do"
316 self.prepare_header(login_url, "POST")
317 response = self.session.post(login_url, params=args, headers=self.session.headers, proxies=proxy)
318
319 if response.status_code == 200:
320 pass
321
322 print response.content
323 print response.status_code
324
325 except Exception, e:
326 print e
327 pass
328
329 self.session.cookies.clear()
330 self.unset_proxy()
331
332 output_fp.close()