· 10 years ago · Apr 07, 2016, 02:48 AM
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 if "register" in url or "login.do" in url:
229 self.signature_data["app"].pop("slider-show-cookie",None)
230 self.signature_data["app"]["-r"] = ''.join(random.choice('0123456789abcdefGHIJSTUVW') for i in range(4))
231 self.signature_data["app"]["X-Request-ID"] = request_id
232 self.signature_data["serviceTime"] = timestamp
233 self.signature_data["app"]["method"] = method
234 self.signature_data["app"]["url"] = url
235 request_signature = self.get_signature()
236 self.session.headers["X-Request-Sign2"] = request_signature
237 return
238
239 def prepare_registration_data(self, handle, email, password):
240 user = '''{"handle":"%s","email":"%s","password":"%s"}''' % (handle, email, password)
241 post_url = "http://www.musical.ly/rest/v2/users/register"
242 boundary = "27c8b11a-9b7e-4849-a665-7f1a04edf2b7"
243 data = (
244 """
245--%(boundary)s
246Content-Disposition: form-data; name="user"
247Content-Type: application/json; charset=utf-8
248Content-Length: %(content_length)s
249\r\n%(user)s
250--%(boundary)s--
251 """ % {
252 "boundary": boundary,
253 "content_length": len(user),
254 "user": user
255 }).replace("\n", "\r\n") # HTTP uses DOS-style line endings.
256
257 # update current headers
258 self.session.headers["Content-Type"] = "multipart/mixed; boundary=\"%s\"" % boundary
259 return data
260
261 def prepare_profile_data(self, user_setting_dto, bio, gender, handle, nick_name, user_id):
262 user = '''{"userSettingDTO":%s,"instagramID":"%s","userDesc":"%s","gender":"%s","handle":"%s","nickName":"%s","userId":"%s"}'''%(user_setting_dto,handle,bio,gender,handle,nick_name,user_id)
263 data = (
264 """
265--2b8a2224-07c6-4463-bb4b-364576e556ad
266Content-Disposition: form-data; name="user"
267Content-Type: application/json; charset=utf-8
268Content-Length: %(content_length)s
269\r\n%(user)s
270--2b8a2224-07c6-4463-bb4b-364576e556ad--
271 """ % {
272 "content_length": len(user),
273 "user": user
274 }).replace("\n","\r\n")
275 self.session.headers["Content-Type"] = '''multipart/mixed; boundary="2b8a2224-07c6-4463-bb4b-364576e556ad"'''
276 return data
277
278 def register_accounts(self, count):
279 output_fp = open('success.csv', 'w')
280 output_writer = csv.writer(output_fp, delimiter=',')
281
282 all_users = self.generate_user()
283 for i in xrange(count):
284 user_data = all_users.next()
285 self.get_a_phone(random.choice(self.phone_profiles))
286 country = user_data["country"]
287 proxy = self.get_proxy(country)
288 if not proxy:
289 proxy = self.get_proxy("US")
290
291 if not proxy:
292 continue
293
294 method = "POST"
295 url = "https://www.musical.ly/rest/v2/users/register"
296 self.prepare_header(url, method)
297 handle = user_data["handle"]
298 email = user_data["email"]
299 password = user_data["password"]
300 data = self.prepare_registration_data(handle, email, password)
301
302 try:
303 response = self.session.post(url, data=data, proxies=proxy, headers=self.session.headers)
304 print response.content
305 print response.status_code
306 # profile edit
307 if response.status_code == 200:
308 response_status = response.json().get('success', False)
309 if response_status:
310 output_writer.writerow([handle, password, email])
311 args = {
312 "username": "@"+handle,
313 "password": password,
314 "remember_me": "on"
315 }
316 login_url = "http://www.musical.ly/v2/login.do"
317 self.prepare_header(login_url, "POST")
318 response = self.session.post(login_url, params=args, headers=self.session.headers, proxies=proxy)
319 print response.content
320 print response.status_code
321 if response.status_code == 200:
322 response_status = response.json().get('success', False)
323 if response_status:
324 self.signature_data["app"].pop("-r",None)
325 self.signature_data["app"]["slider-show-cookie"] = self.session.cookies["SLIDER_SHOW_COOKIE"]
326 user_setting_dto = response.json()["result"]["userSettingDTO"]
327 gender = response.json()["result"]["gender"]
328 user_id = response.json()["result"]["userId"]
329 bio = user_data["bio"]
330 nick_name = user_data["nick_name"].decode('string-escape').decode("utf-8")
331 edit_url = "http://www.musical.ly/rest/v2/users/edit"
332 self.prepare_header(edit_url, "POST")
333 data = self.prepare_profile_data(user_setting_dto, bio, gender, handle, nick_name, user_id)
334 response = self.session.post(edit_url, headers = self.session.headers, data = data, proxies = proxy)
335 print self.signature_data
336 print self.session.headers
337 print data
338 print response.content
339 print response.status_code
340 # exit(0)
341 except Exception, e:
342 print e
343 pass
344
345 self.session.cookies.clear()
346 self.unset_proxy()
347
348 output_fp.close()