From e8a804c7ff08a90de34739d4ceb58e555994f623 Mon Sep 17 00:00:00 2001 From: David Teather <34144122+davidteather@users.noreply.github.com> Date: Tue, 5 Nov 2019 11:03:03 -0600 Subject: [PATCH 1/2] Update Readme.md --- README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index f9576abd..f33644c1 100644 --- a/README.md +++ b/README.md @@ -3,7 +3,8 @@ This is an unoffical api wrapper for tiktok.com in python. With this api you are able to call most trending and fetch specific user information. - [![GitHub release (latest by date)](https://img.shields.io/github/v/release/davidteather/TikTok-Api)](https://github.com/davidteather/TikTok-Api/releases) [![Build Status](https://travis-ci.com/davidteather/TikTok-Api.svg?branch=master)](https://travis-ci.com/davidteather/TikTok-Api) [![GitHub](https://img.shields.io/github/license/davidteather/TikTok-Api)](https://github.com/davidteather/TikTok-Api/blob/master/LICENSE) [![PyPI - Downloads](https://img.shields.io/pypi/dm/TikTokApi)](https://pypi.org/project/TikTokApi/) + [![GitHub release (latest by date)](https://img.shields.io/github/v/release/davidteather/TikTok-Api)](https://github.com/davidteather/TikTok-Api/releases) [![Build Status](https://travis-ci.com/davidteather/TikTok-Api.svg?branch=master)](https://travis-ci.com/davidteather/TikTok-Api) [![GitHub](https://img.shields.io/github/license/davidteather/TikTok-Api)](https://github.com/davidteather/TikTok-Api/blob/master/LICENSE) +[![Downloads](https://pepy.tech/badge/tiktokapi)](https://pypi.org/project/TikTokApi/) ## Important Information * If this API stops working for any reason open an issue. From 2810e65a9ef29c3968fd1470a1dacf1e57c4c355 Mon Sep 17 00:00:00 2001 From: davidteather Date: Sun, 17 Nov 2019 15:50:08 -0600 Subject: [PATCH 2/2] V2.2 --- README.md | 33 +- TikTokApi/__pycache__/tiktok.cpython-37.pyc | Bin 8901 -> 6700 bytes TikTokApi/tiktok.py | 398 +++++++----------- setup.py | 2 +- ...est_VideoByUrl.cpython-37-pytest-5.1.2.pyc | Bin 1632 -> 1656 bytes .../test_hashtag.cpython-37-pytest-5.1.2.pyc | Bin 3322 -> 1821 bytes .../test_trending.cpython-37-pytest-5.1.2.pyc | Bin 3423 -> 1822 bytes .../test_user.cpython-37-pytest-5.1.2.pyc | Bin 1941 -> 1710 bytes tests/test_VideoByUrl.py | 2 +- tests/test_hashtag.py | 15 +- tests/test_trending.py | 10 +- tests/test_user.py | 9 +- 12 files changed, 174 insertions(+), 295 deletions(-) diff --git a/README.md b/README.md index f33644c1..d250040b 100644 --- a/README.md +++ b/README.md @@ -69,24 +69,21 @@ headless - True/False - True means it will run a headless chrome browser, could api.trending(count, verbose) ``` -Trending returns an array of json objects. Example structure [here](https://gist.github.com/davidteather/0be2e495e2de54098e8f2a9594581d27) - -JSON object tree [here](https://gist.github.com/davidteather/bc4baef0edb621dd322c8ad128a31ac1) +Trending returns an array of json objects. Example structure [here](https://gist.github.com/davidteather/1844d21d07f290be91fd9e56e41f925e) ##### The userPosts Method ``` -# Where count is how many results you want -# Verbose is optional, default=0. Set it to 1 to get more information -# userid is the tiktok userid, can be found through response json tree or in the tiktok url -api.userPosts(userid, count, verbose) +api.userPosts(username, count, verbose) ``` -Since this isn't an offical TikTok API the TikTok servers don't know what to do. This method specifically will throw a lot of errors if you have verbose on. It takes a lot longer than trending, however it will still end up working. Just give it a few minutes. +username - the username of the user + +count - the amount you want -Trending returns an array of json objects. Example structure [here](https://gist.github.com/davidteather/a5c1e54de353353f77a78139d2e5a9f9) +verbose - 0/1 if you want it to display things -It has the same JSON object tree as trending. It's [here](https://gist.github.com/davidteather/bc4baef0edb621dd322c8ad128a31ac1) anyways. +Trending returns an array of json objects. Example structure [here](https://gist.github.com/davidteather/1844d21d07f290be91fd9e56e41f925e) ##### The search_by_hashtag Method @@ -100,9 +97,19 @@ count - The number of results you want Since this isn't an offical TikTok API the TikTok servers don't know what to do with my bad solutions, this takes a bit longer as it needs to find the hashtagID and stuff. -Search by hashtag returns an array of json objects. Example structure [here](https://gist.github.com/davidteather/a5c1e54de353353f77a78139d2e5a9f9) +Search by hashtag returns an array of json objects. Example structure [here](https://gist.github.com/davidteather/1844d21d07f290be91fd9e56e41f925e) + + +##### The get_song Method + +``` +api.get_song(url) +``` + +url - The url of the TikTok, can be found via trending. + +This returns a dictionary. Example structure [here](https://gist.github.com/davidteather/777befde18641f44d90fbf008082ec02) -It has the same JSON object tree as trending. It's [here](https://gist.github.com/davidteather/bc4baef0edb621dd322c8ad128a31ac1) anyways. ##### The get_Video_By_Url Method @@ -114,7 +121,7 @@ video_url - The video you want to get url. return_bytes - The default value is 0, when it is set to 1 the function instead returns the bytes from the video rather than just the direct url. -##### The get_trending_hashtags Method +##### The get_trending_hashtags Method ( not working as of now ) ``` api.get_trending_hashtags() diff --git a/TikTokApi/__pycache__/tiktok.cpython-37.pyc b/TikTokApi/__pycache__/tiktok.cpython-37.pyc index c7fc09d198839604d248044335ae78af044c49ed..80f6ff462acb9687a9568e8110f6664d91f3ccd8 100644 GIT binary patch literal 6700 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 literal 8901 zcmc&(OK=-kcI|F7fX0^~Nb#dDL`$?NlOQ$vcr2N+t*;%+8jVSr9z-5g6R$}&*+7%8 z8zR_gY$PR?r{XHDW-*loxJha@vr4@7Dx1tA$s&uc>{2yV%EFs$Qd-10_ceZ`KGt}u z5}^9^`@ef%-*@l1_g%?kk`jI^fA{SdXRk@pe^8}O-QSpv8V|``SidEyyxab?Tv}&TM$&xSoQaRZ;;j69Gu5?ZMVyv0) z6Rq^F#9|u?zlVHgSCXZzdrK0FGtHEnNk4*7NtXCp!Pu-Xt!G;U)W?staxA$E%0%7Z zF5cyQUv0cKv@11JeyTOhQlej~C3a<1-c>M)>a(p8jLxs;cja!60oo-q?4z*!hVn$_ zInjGa^og&J`YAU2HSsb=qg&(bK%0)S)!6 zM9rabX(RSTc3gINZw#yL2}bFgvL&w-PXX5Jrc75sebID0ePy(h}n2*wX$t_h#M)*IpXW)h_B z)NSwPZDYGov2@2NaAU>bMy+B@7go#~Gi$4b`?_Vaf@7}MbhplpVqtO3bP82-bQ@K z0(H~ouKAl|7_Ok8yK6z*4tqb9F{w8^Gs8?rU$%@Hz3$poon|Tx7>$ZmXU4*|=~mVZ z#~UgnU3pCthw%{b8&WddwaX+nj5aYQLNb2S)(@VVk2n> zgNS9X263b2auYP3?2M@P_jlHGZp@mlQJtlE-wWd0*s2?j8${~d^4{zW+PBR9Vcy{z zcD>g3xuy#hyXNBifRJL4!jybx0fc}owFY*BWV!okgDAdr-3X*-^1P>9Dm?w4@4x@v zJ3c$RcJ|NT7xFPbQ6}ojL}%GGUCWsGVpb2LB0F^=h;CwLHyG%BVDWu9DX}27>C|1* z3e%g!6GCY>itT;pQR+C3usxS_j7ITS&V4oNI!u8ObR7S&Q(XRNIA z)p`}5uQW;}qp@jl&|Y(Ot1S#cY{lk~$xA@_kuodpN+}bH`5kVr;D`h&(_J0H z8&VR)LIDb5A)zI$y|7bCw{stGuJ7<7CjYI(&*Sy%;`NL7Zkq0g^<_-Dj&J4MyMyDt zVq2ztFSK+sA8eZKEalqgXmcmf%4M@=y5%x`b%!C56irUcTKk_yKBi<9yiuZ{3l`Gl+~c{z)=Y$PV<?<6=8CL+S1fkZcFjUsBvgcN%ls1 zOZRu#vpkU?Z~y@US{`~F%gSQgU$WoIv(td9tAk`QB50Zx+b z@yV}b(LeQ-1eg*dXd++=!3aPT76nYHA)gg6r3OS-)44Z4Gq+%rKxy%9mk`)1#8;pIskm4lt>iYplUgXJGWR0t9^C z9ApFjAj_dO6f+Hg!vd(21$D$PfC-xz zmzpDuLc8>a;3U@^^@m!={88E?0G9tI$kVWP{=KvQhWbR|e`t?6fmu#&0POYgG5I1s zKz~lq{UTo86#R{d_ESHaFNOc-9=;}D!I!f2&r4EG^@kQDydTRr^Lu!h`oHAiiL#yh zg;Y~MmjLi`0%ER#D$Omh(+}kbIBif1Z`~Fr7D|E6C|-1Q@gjZtJP_lgP}(?*$C2lB zx_N?<6cX>yOK=Em_o~74TuL6L$d}rRM@idLg(74wFJ)G1jAD{uR3wU^rhLEl2 zjLED{Exn+bX&Eu4Pwr%eh?a4t+}2#GC7E{VQ>!V^r>%YN06spkxv}^segOV1nCA18Tt)($`X1%q5Az>T{t6`oF*uo2 zP8M+&PiL3MUdFDM?&tUah0cHIqx0BZ;j|Q7yFj1bH45&UQD}=p;iGF)#{;eH3^;t8 zIHjY!AI=@2I)UkqQjR1(+#s=41uBYDa-4Dk8NNZe6O^2!WQr1!G=7?rwvx{feOpknG+o7N2)!bs=7wQXm8g?jQ@lx>9EtTIh$}e4StU5NU!jl z)DUxpqb6hrg4Giy0nG-VJCk2vkn;eE1OV9spOh!qsqF!v1U&HobPfZWs*$`r(T1C8 zMMbR&$eC47E9uCvlEn;p08|ywHH&&`xd@=zX~{=408&v4h&wEgMZ80=&>h`i5$Vw` zE_)2EBe0XyjEJ`^@R?*O2oUYTW?vzglvQ zPCyT62UgI4AvC-bt)#CBbQEi)L^;jkzz`W=h=iN<6BIN7ib?tjriFNd-#|Wrd=h9P zh2TY4N(nTP1#U~WfZAxzt=}z4m?KGZ08{+^6L}}=M-gNat!NQpFgNQCQXlH&%V8dv zL+1b1o*76D_^)qGmL+b&o^5nA07Mb@Q-VVvs4j=yUMwx<{AF)kGgDJp8sQ__n~WIQ zKg(d>EI+VMpsl?(pgL$w?%9!C|Be7(eJgNCl5oh@??W8Yqe)PyaJ5&{rSi3T{?qx{ z{{1gN+vj*dUuq=D+36v3hb0^dUdo9Yp5=}&)DtYhq&R)lp>Y3}% zBQBG@=Q`pMy_T*a$D-uw@mokJ(B+t(!An$-#nO0DNtm-Bw|~NaL6e{aUgGp0Ly33! zkA)5)a5&!q4#hr8I=2Tmbdf^8MQx)7ew}!^K?!MH{vnd5LXUrhoOj{1h$1W_P)wJY z(U%aj*Q$FXJrvVV+f+U@G*^fs5eE?w5n%$lV1s``tz`WA4C2qIc!!doQ$k`U>|1C; zZ=*Ps4b9sEH7!yiY}&r1?oorVMP#}7XOxKjSwb#|+}C+%mqL*UWkKtR+drX?Loz~^ zsPjJlF)Yqo>1qr9b%5 zS+?u&lM_IQo3NHsz_Dl>7C3i}98+*kL-P=UB9(nbs6$n#K!EHf8J372Wlu96ZxAY%fVTX!Of4tHIKt^XnvfWYB-`1{#Sm4qW}Dn8)I;6VIb0I z6;3o%d;+ED`xjle^hjR|-6 z*U$44j%gc$Rl& z-J(+D=JiEy_(e;WqN3KjPXKjx&8=F~h^bm8fH$rbW*b!VR%3r{)w;AbKUaKb+N|oU z#w?=Ko9(Q=SzDbxJ$qWT|8&n>6zMhC3@$0w2s>Z8Kfip|8(j6w&FKO&R&e)#YnEm1 zWsTa*-GynR7OvruZ#9Eu=HXtR@!(B)2x9BA=ZkZNQ%i^o=&YnN}cJb_m!l{oxT>RwLbip!lQ*+a(Y}iwUFi1W7_POF* z@$B0_d8c^h!aIcpeMRSHd)QR6l)yd9n$1mjCx}%IWSIyElwuBUTB=4VrdJ5ndjsKn z2A4)Q-F9>Br$7ha~KW5^8MLvY*j#_OA_TxZ6N31nWujnYiVx$%;9V0GfWhOlWV zPM0qRtg^5p6oc>%epCyuqZT^XQH4(p1RJpKK10LF#sumjuN&U$S&XSfsIGgupZp+P z7C<=MFmB${`9j^Ngt`wDlkt5jpVWIGbK#rp)9|6g+Qk?_f_T1TJFatBhE62|L%Lm6 z4kD$8JPZ{Yn|z8;vy-=QLOCtk+CAV&K$}OBXwk@LpjI&hMl0S>4=r?8>-q{rD}{Q5 zO1}&mUg0Y!mQqC|w;hw+8_RuR?ABK(cF4a4l1{c#EGm2iX+7P__~FGa>esWt|2J@T z8-s$63#EObnckUT8ltvs4`Cz5|F&0ZX6_K~eGsa*?FUdh51@7)EJ=Q5fl&La*ZOeJ zT0g~FC-$xdWjg%aYTvb2`wpvpht5}?Ge z%eY(&(%it!ZVk@6YdAl!Cc*45xIpM7h+;;*6T%sTnuK8Yq&r7937?6TuI!ZWa_g5Q z len(response): - data['body']['hasMore'] == True - cookie = ''.join(random.choice( - string.ascii_uppercase + string.digits) for _ in range(40)) - - url = "https://m.tiktok.com/share/item/list?secUid=&id=" + str(hashtagId) + "&type=3&count=" + \ - str(count - len(response)) + "&minCursor=-1&maxCursor=" + str(maxCursor) + "&_signature=" + \ - self.signature + "&shareUid=" - - - self.driver.get(url) - data = json.loads(self.driver.find_element_by_xpath("//pre").text) - - if data["statusCode"] == 0: - maxCursor = data['body']['maxCursor'] - for tiktok in data["body"]["itemListData"]: - response.append(tiktok) - - else: - return response - - except: - cookie = ''.join(random.choice( - string.ascii_uppercase + string.digits) for _ in range(40)) - - url = "https://m.tiktok.com/share/item/list?secUid=&id=" + str(hashtagId) + "&type=3&count=" + \ - str(count - len(response)) + "&minCursor=-1&maxCursor=" + str(maxCursor) + "&_signature=" + \ - self.signature + "&shareUid=" - - self.driver.get(url) - data = json.loads(self.driver.find_element_by_xpath("//pre").text) - continue - + self.driver.get("https://www.tiktok.com/tag/" + + hashtag.replace("#", "") + "?lang=en") + time.sleep(2) + + self.driver.execute_script( + "window.scrollTo(0, document.body.scrollHeight);") + time.sleep(2) + TikToks = self.driver.find_elements_by_xpath( + "//div[@class='jsx-1410658769 video-feed-item']") + TikToksUrls = self.driver.find_elements_by_xpath( + "//div[@class='jsx-1410658769 video-feed-item']/div/div/div/a") + TikToksViews = self.driver.find_elements_by_xpath( + "//div[@class='jsx-1410658769 video-feed-item']/div/div/div/a/div/div/div/div/div/span") + + returnArr = [] + if count > len(TikToks): + lower = len(TikToks) else: - raise Exception('Unable to locate the hashtag ID') + lower = count + for i in range(0, lower): + if "k" in TikToksViews[i].text.strip(): + likes = float( + TikToksViews[i].text.strip().replace("k", "")) * 1000 + elif "m" in TikToksViews[i].text.strip(): + likes = float( + TikToksViews[i].text.strip().replace("m", "")) * 1000000 + else: + likes = TikToksViews[i].text.strip() + + returnArr.append({ + "link": TikToksUrls[i].get_attribute("href"), + "author": TikToksUrls[i].get_attribute("href").split("/")[3], + "likes": likes + }) + return returnArr # # Gets trending results @@ -206,139 +143,114 @@ def trending(self, count=10, verbose=0): import time import json import random - def cookie_generator(size=100, chars=string.ascii_uppercase + string.digits): - return ''.join(random.choice(chars) for _ in range(size)) - - while True: - # TODO: Max Cursor Issue - # https://m.tiktok.com/share/item/list?secUid=&id=&type=5&count=2&minCursor=0&maxCursor=1000005823613&shareUid=&_signature=0NDOfgAgEB-lIUUg-oc9StDQz2AAI10 - # https://m.tiktok.com/share/item/list?secUid=&id=&type=5&count=5&minCursor=0&maxCursor=0&shareUid=&_signature=Oo2r.AAgEBtPfCCiX9JspzqNquAAGc9 - url = "https://m.tiktok.com/share/item/list?secUid=&id=&type=5&count=" + str(count) + "&minCursor=0&maxCursor=0&shareUid=&_signature=" + self.signature - - # https://m.tiktok.com/share/item/list?secUid=&id=&type=5&count=5&minCursor=0&maxCursor=0&shareUid=&_signature=DGZaZAAgEB95l9E6AB.J8gxmW3AAFHi - - - self.driver.get(url) - data = json.loads(self.driver.find_element_by_xpath("//pre").text) - print(data) - - response = [] - if data["statusCode"] == 0: - maxCursor = data['body']['maxCursor'] - for tiktok in data["body"]["itemListData"]: - response.append(tiktok) - print(response) - while True: - try: - time.sleep(5) - print(count) - print(len(response)) - if count > len(response): - var = data['body']['hasMore'] - maxCursor = data['body']['maxCursor'] - url = "https://m.tiktok.com/share/item/list?id=&type=5&count=" + \ - str(count - len(response)) + "&minCursor=0&maxCursor=" + \ - str(maxCursor) + \ - "&_signature=" + self.signature - - if count - len(response) > 5: - var = count - len(response) - else: - var = 5 - - url = "https://m.tiktok.com/share/item/list?secUid=&id=&type=5&count=" + str(var) + "&minCursor=0&maxCursor=" + str(maxCursor) + "&shareUid=&_signature=" + self.signature - - self.driver.get(url) - data = json.loads(self.driver.find_element_by_xpath("//pre").text) - if data["statusCode"] == 0: - for tiktok in data["body"]["itemListData"]: - response.append(tiktok) - else: - return response - except: - - if count - len(response) > 5: - var = count - len(response) - else: - var = 5 - - url = "https://m.tiktok.com/share/item/list?id=&type=5&count=" + \ - str(count - len(response)) + "&minCursor=0&maxCursor=" + \ - str(maxCursor) + \ - "&_signature=" + self.signature - - url = "https://m.tiktok.com/share/item/list?secUid=&id=&type=5&count=" + str(var) + "&minCursor=0&maxCursor=" + str(maxCursor) + "&shareUid=&_signature=" + self.signature - - self.driver.get(url) - data = json.loads(self.driver.find_element_by_xpath("//pre").text) - - continue + + self.driver.get("https://www.tiktok.com/en/trending") + time.sleep(2) + + self.driver.execute_script( + "window.scrollTo(0, document.body.scrollHeight);") + time.sleep(2) + TikToks = self.driver.find_elements_by_xpath( + "//div[@class='jsx-1410658769 video-feed-item']") + TikToksUrls = self.driver.find_elements_by_xpath( + "//div[@class='jsx-1410658769 video-feed-item']/div/div/div/a") + TikToksViews = self.driver.find_elements_by_xpath( + "//div[@class='jsx-1410658769 video-feed-item']/div/div/div/a/div/div/div/div/div/span") + + returnArr = [] + if count > len(TikToks): + lower = len(TikToks) + else: + lower = count + for i in range(0, lower): + if "k" in TikToksViews[i].text.strip(): + likes = float( + TikToksViews[i].text.strip().replace("k", "")) * 1000 + elif "m" in TikToksViews[i].text.strip(): + likes = float( + TikToksViews[i].text.strip().replace("m", "")) * 1000000 + else: + likes = TikToksViews[i].text.strip() + + returnArr.append({ + "link": TikToksUrls[i].get_attribute("href"), + "author": TikToksUrls[i].get_attribute("href").split("/")[3], + "likes": likes + }) + + return returnArr # - # Gets a user's post + # Gets the song of a tiktok url # - # count - the count of results - # verbose - 1 is high logging + # url - url of the tiktok # - def userPosts(self, id, count=10, verbose=0): + def get_song(self, url): import requests - while True: - url = "https://m.tiktok.com/share/item/list?id=" + str(id) + "&type=1&count=" + \ - str(count) + "&minCursor=0&maxCursor=0&_signature=" + \ - self.signature - r = requests.get(url, headers={"authority": "m.tiktok.com", "method": "GET", "path": url.split("https://m.tiktok.com")[0], "scheme": "https", "accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3", - "accept-encoding": "gzip, deflate, br", "accept-language": "en-US,en;q=0.9", "cache-control": "max-age=0", "upgrade-insecure-requests": "1", - "user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.169 Safari/537.36"}) - - data = r.json() - response = [] - - if data["statusCode"] != 0: - if verbose == 1: - print("Invalid Signature Retrying") - else: - maxCursor = data['body']['maxCursor'] - for tiktok in data["body"]["itemListData"]: - response.append(tiktok) - while True: - try: - if count > len(response) and str(data['body']['hasMore']) == "True": - url = "https://m.tiktok.com/share/item/list?id=" + str(id) + "&type=1&count=" + \ - str(count - len(response)) + "&minCursor=0&maxCursor=" + maxCursor + "&_signature=" + \ - self.signature - maxCursor = data['body']['maxCursor'] - - r = requests.get(url, headers={"authority": "m.tiktok.com", "method": "GET", "path": url.split("https://m.tiktok.com")[0], "scheme": "https", "accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3", - "accept-encoding": "gzip, deflate, br", "accept-language": "en-US,en;q=0.9", "cache-control": "max-age=0", "upgrade-insecure-requests": "1", - "user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.169 Safari/537.36"}) - - data = r.json() + import string + import time + import json + import random - if data["statusCode"] == 0: - for tiktok in data["body"]["itemListData"]: - response.append(tiktok) + self.driver.get(url) + time.sleep(2) - else: - if verbose == 1: - print( - "Invalid Signature Retrying") + return { + "song_name": self.driver.find_element_by_xpath("//a[@tag='a']").text.strip(), + "song_link": self.driver.find_element_by_xpath("//a[@class='jsx-1861775669 jsx-537314381']").get_attribute("href"), + } - else: - return response + # + # Gets a user's post + # + # count - the count of results + # verbose - 1 is high logging + # - except: - url = "https://m.tiktok.com/share/item/list?id=" + str(id) + "&type=1&count=" + \ - str(count - len(response)) + "&minCursor=0&maxCursor=" + maxCursor + "&_signature=" + \ - self.signature + def userPosts(self, username, count=10, verbose=0): + import requests + import string + import time + import json + import random - r = requests.get(url, headers={"authority": "m.tiktok.com", "method": "GET", "path": url.split("https://m.tiktok.com")[0], "scheme": "https", "accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3", - "accept-encoding": "gzip, deflate, br", "accept-language": "en-US,en;q=0.9", "cache-control": "max-age=0", "upgrade-insecure-requests": "1", - "user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.169 Safari/537.36"}) + self.driver.get("https://www.tiktok.com/@" + + username.replace("@", "") + "?") + time.sleep(2) + + self.driver.execute_script( + "window.scrollTo(0, document.body.scrollHeight);") + time.sleep(2) + TikToks = self.driver.find_elements_by_xpath( + "//div[@class='jsx-1410658769 video-feed-item']") + TikToksUrls = self.driver.find_elements_by_xpath( + "//div[@class='jsx-1410658769 video-feed-item']/div/div/div/a") + TikToksViews = self.driver.find_elements_by_xpath( + "//div[@class='jsx-1410658769 video-feed-item']/div/div/div/a/div/div/div/div/div/span") + + returnArr = [] + if count > len(TikToks): + lower = len(TikToks) + else: + lower = count + for i in range(0, lower): + if "k" in TikToksViews[i].text.strip(): + likes = float( + TikToksViews[i].text.strip().replace("k", "")) * 1000 + elif "m" in TikToksViews[i].text.strip(): + likes = float( + TikToksViews[i].text.strip().replace("m", "")) * 1000000 + else: + likes = TikToksViews[i].text.strip() - data = r.json() + returnArr.append({ + "link": TikToksUrls[i].get_attribute("href"), + "author": TikToksUrls[i].get_attribute("href").split("/")[3], + "likes": likes + }) - continue + return returnArr # # Gets the source url of a given url for a tiktok @@ -362,30 +274,10 @@ def get_Video_By_Url(self, video_url, return_bytes=0): if return_bytes == 0: self.proxy.new_har("vid") self.driver.get(video_url) - data = self.proxy.har - - for entry in data['log']['entries']: - try: - if "muscdn.com" in entry['response']['redirectURL']: - url = entry['response']['redirectURL'] - break - except: - continue - - return url + return self.driver.find_element_by_xpath("//video[@class='jsx-3382097194 video-player']").get_attribute("src") + else: self.proxy.new_har("vid") self.driver.get(video_url) - data = self.proxy.har - - for entry in data['log']['entries']: - try: - if "muscdn.com" in entry['response']['redirectURL']: - url = entry['response']['redirectURL'] - break - except: - continue - - r = requests.get(url) - + r = requests.get( self.driver.find_element_by_xpath("//video[@class='jsx-3382097194 video-player']").get_attribute("src") ) return r.content diff --git a/setup.py b/setup.py index ac0d60d5..cfe02088 100644 --- a/setup.py +++ b/setup.py @@ -8,7 +8,7 @@ setuptools.setup( name = 'TikTokApi', packages = ['TikTokApi'], - version = '2.1.9', + version = '2.2.0', license='MIT', description = 'The Unoffical TikTok API Wrapper in Python 3.', author = 'David Teather', diff --git a/tests/__pycache__/test_VideoByUrl.cpython-37-pytest-5.1.2.pyc b/tests/__pycache__/test_VideoByUrl.cpython-37-pytest-5.1.2.pyc index 7e408adc973d9379836be3c4713a809491f3a6d5..ba50bd2607eb7c909869ef79082defe3c44aa86c 100644 GIT binary patch delta 81 zcmV-X0IvVw4EPKQLJbWHNW9TqT9FBQ0cf#=UjYbw0H6?|0097#;{h%KMzazE3IYKU nlN|)h4q6Oxb!l{8VsdYHb7gXq=mg3EAd|BNAp#Hqlhg%_3MCnz delta 54 zcmV-60LlOO4B!k2LJbWH@Bf)yL6Hf10bsF&UjdWr0WJYlvl;>l0s#<{B?QZp{shVa M9+SxhA(QL{j12Y@6aWAK diff --git a/tests/__pycache__/test_hashtag.cpython-37-pytest-5.1.2.pyc b/tests/__pycache__/test_hashtag.cpython-37-pytest-5.1.2.pyc index 84a566b089bb71e5940b2a7ab812284389ff5f38..dbc2eb016e140f0fd54156b22b71f94edd29a007 100644 GIT binary patch delta 860 zcmbW0J%|%Q6vyYyeod0iCHIkVa&Q)hLJEy~Dsl>*3JMlBUbP@0VUlxAvdPU%I3v3T zyhe+IleMr=$%2)IV4;{Je4?Uk+x}43X zQ|~|B`VNGAArluxy^6P7dAzh@!A(+f-rQM$!4EVl!hut6Y}1H@WC+|$AOci0AwZN7 z!WKl7Tagjc&}h=g3{6g&OfLO)J=@mu?Frif{wJ*DaRn>~Ntb2oavs*GC;6EnMoO1H1-QXSu{iog%nE2`hE zOX2Dq8?Q-`jhCHA=RBj@^@W8gFSFY1SE>@nR;MO|Gn2vTQ5!7Yb1r7iVi^IKrh&y5 zSb0_~Vq8k^vRcn?DL;^6K9=tCf*#sSt@+KhPV*9Or%%WTLM+A~-J>qUn2{Oc8qEC# D;Sl3V literal 3322 zcmc&%&2Jk;6rb5$uh))a=c7rRiVqWL$yRNYq@*9HL2YS)Qxrj^N>-|6<5|bstar`K zx{b}QRMDQ0igMt9P!Guk2~LP3;t$})743lwr`$OAfOv0q?V2Q@N>swuzIpTJ?acgU zJip)g`sir!OgFysi$cinWatBRauptN9SkFkdZb2WskBsuP}0(BIf^Zcr?>L8JoqZp z9+8^Ca!iM^!1Bz1vdHL1#4PMXKV;RUN#T~ebt~Ai+ism=3_e=+ybGnc0%nuM6dq;! zOhj&wJF~GGsS(}M`RPd6C6T&EDfy%v(P#c`64FR{h(pm;Q%Q8Y-FAGIsGj4STB34C zB)PEZ`kS>J>$IV!L#X40-x6-Xh)=KFe0%+UH~gTpvBrbDPCXRsYXJ`%f#(M6>6Fi1 zYrE^ABcKVb)wD%3v^VG5-K1D=I`yp^*fD|;WiW(l@GVkix8<}7(WGg^6*H+ zzp8|Uu*6JZ>SHA)5xGm5hRX;w8Y&TeNMnWNU=@@|-BMyL(iqt?_y#Vqr?#{hw<6C9 zUaqCbIwg@FP+Uk{yfkE(PBRN1?SG z8GC@{GnknM`wNd2t6?QWm_LYchw}HH3*%HD;|>+S!8nIePWLfDMh`MZ!pa_n{vY9- z(FYvU&yYgaE@mM@$odYmUJTl7caI;~-Q$O_EByL%VLvgzu80KYc^La(hj$cl4^iRH z?kM~LqB^|Gko5$!BzA>=gIO;I`@ih8$`_ss?aTnJDt?BU9Y*_Xr&YlahumqE`-tO+ zomR!?m?hDw{7cMwF=!b9HafZ58{6Q)ec|v{uyL-`%lcbe+(z8CPv*3oy~xE6Qkh*=h`hN z(LL99{J^A7m6a8f_7+afwY%p{QT#M>sw-9W7ECdR<)SIfVq9HGqZdrUkxO|FM*s?k zL^O+N&eyL63a}@iMf?4iMiTDDELki|sNE;cImRV(x@jYfl1O)R(%s>x>rXqci7FiAnr>tur zpkq&T6iqhHCL%)$Xdx5O!jOQ{Ohi>Eb1_^BfN&;{CLBHjYqu{CRLU*#*I-ild-#8- z<5ifEsq%3s_yn3s3{Wm9h4uuV>Wh840OtT*Eccth$(oKJ7a*1SO((QM4%b0E)!D60 z6yrHyn<2tk1RhEm=QPek=aNXKabm~8Ah|4~xmeSHg%*01A@W&V0`|f1l37VvX6nd6 z)Baz=K9N`W%V>~N_$z2|MR*m>YiMTCypHA#G^fCrMUJ!MZ=#t4Gkn}H3|B4>S1t{m zeaTMg*eJpD8B^dE%;Aqbo^Qh`o%pn<=W!2@~d`B}&?M-rpYh7w&e)2G^W z34zn*c`9y6VGv64Sxl}?E&Ja9cW}ADk_06~$T5ayj@NlE$;-IX3RuT;-oanIKmswy L1SzRT$te8=`Pf{& diff --git a/tests/__pycache__/test_trending.cpython-37-pytest-5.1.2.pyc b/tests/__pycache__/test_trending.cpython-37-pytest-5.1.2.pyc index f909ad03f2cfaf18999f602f33d4d918a146c7ef..cced4dbd008c5f0e4ca5debabfd877a2ebab7a9c 100644 GIT binary patch delta 458 zcmcaFHIGl(iIzj0`CZKw*)|wpY3n~pjgdvD91`(zp!W=|cMzH`TjH>t( zi;Gi>N)%KzfLs&JVz98uOD>>=FWG>Era%$M0Z|+!MX7lynR)3&T$5k1N(-<61#fYb zCl=)a#fpnqCyTN*)kpCZmS&d3Cl%$F0}a*WF5(7h<#s5jjE7ibgv>EP=9nRKETVW2 zdJGLwcm_ovtBY7cCWBR_3YGoE+8 zxxY&Z`9Yc<2J;CR&b4|v7YlK1i!4Mqy+iD9eZgiz`SNO($PP?X$!3pP!vd2DJlBDLr6Sgr+-&}sHTsD#F(`k9 z=IK3oTbq`y*4-_JVABH_!D9mPiqkNh+4|OU+TiA4?Wq%o`szIDX)Bb+P^uNSqw=_n z(3BGAmK>ldYRL+-&6c;}4pNQqR^BFSbhJHjg4_xDosOlGNAa1H`%nA~O9%09vGj@Y zhYoaZN1gjXXQ9CH8##c04kh5g^1urVBxjVzJq;AWRs`xNbVLLlRN&?1zVfIhuoQt- zc38x49!FS+7DOwe4Uqu+(=Q_E4-QKW+MjZ8oxQONeV(7cebkU}Pv^p19h;!%dShiX$U6F(oIp zxHw86D={TCuOuTiJ2Nl6I48AIlkpa7a(-!Ei6%=C69WT76lZC1YEeLbaY=C$Phn|h zNqkaKemPKRvIJu;HwRD!10xS3A0x-)K1La)HH@3rFs^3gUTEzU21Xu6 zKBgj0AS)Tf1py8qW(Q(tATDlU+I*04H6yQJEkg-I4MQ_yEn|w{&hRtf6@&Ju=&j1!oOOeWhhg>x_jGiVC?z2ur)!n}%+ zd$K%B54Q-=^p`v!LT>XK79&PBE|7J8lb^7fPiAD37E%CmHMwqaB$a07lw{@=7fDUl iV>6bP018KOhGb@k