31
loading...
This website collects cookies to deliver better user experience
POST
request to this url, application/x-www-form-urlencoded
content-type, so in this case, our key will videos
, which probably means, that's just Netflix differentiates this data. Looking at the url (https://www.netflix.com/browse?jbv=80097140) we can see that the ID is being passed next, and finally we have a list of what we want to get in response. Cool, looks like we have some of the info we need, but we need to a find a way to get these video IDs, we're not going to manually go over and copy them..POST
data in request, memclid={id}SecureNetflixId={SecureNetflixID}; NetflixId={NetflixId}; playerPerfMetrics=%7B%22uiValue%22%3A%7B%22throughput%22%3A6231.89%2C%22throughputNiqr%22%3A0.5994435164694499%7D%2C%22mostRecentValue%22%3A%7B%22throughput%22%3A6233.69%2C%22throughputNiqr%22%3A0.39654013276722966%7D%7D; OptanonConsent=isIABGlobal=false&datestamp=Wed+Jul+22+2020+11%3A06%3A12+GMT%2B0200+(Central+European+Summer+Time)&version=6.3.0&consentId=f0aa447b-7bc0-468f-a12e-e8f7f8acde23&interactionCount=1&landingPath=NotLandingPage&groups=C0001%3A1%2CC0002%3A1%2CC0004%3A1&hosts=H1%3A1%2CH2%3A1%2Cjyl%3A1%2CH7%3A1%2CH4%3A1%2CH6%3A1&AwaitingReconsent=false; _ga=GA1.2.616486459.1595596356; pas=%7B%22supplementals%22%3A%7B%22muted%22%3Atrue%7D%7D; profilesNewSession=0; clSharedContext=f89661b7-8d71-48cf-80ce-f53d4f1e959c; lhpuuidh-browse-ADZ4LPN6MZAN3MDBZ4OUFKDW6A=US%3AEN-US%3A648428ac-7104-4e30-83d9-b412c71e1910_ROOT; lhpuuidh-browse-ADZ4LPN6MZAN3MDBZ4OUFKDW6A-T=1596565541035
{
"jsonGraph":{
"genres":{
"6721":{
"name":{
"$type":"atom",
"value":"Anime Series"
}
}
}
},
"paths":[
[
"genres",
6721,
"name"
]
]
}
["genres",6721,"subgenres",{"from":0,"to":30},["id","name"]]
["genres", 6721, {"from":0,"to":30}, "videos"]
Hey netflix, give me 30 videos from the genre ID 6721
I'm not going to paste the whole response here, because it is quite long, but here's an example when fetching 3 videos,{
"jsonGraph":{
"genres":{
"6721":{
"0":{
"$type":"ref",
"value":[
"videos",
"81002438"
]
},
"1":{
"$type":"ref",
"value":[
"videos",
"70205012"
]
},
"2":{
"$type":"ref",
"value":[
"videos",
"80050063"
]
},
"3":{
"$type":"ref",
"value":[
"videos",
"80095241"
]
}
}
},
"videos":{
"70205012":{
"videos":{
"$type":"atom"
}
},
"80050063":{
"videos":{
"$type":"atom"
}
},
"80095241":{
"videos":{
"$type":"atom"
}
},
"81002438":{
"videos":{
"$type":"atom"
}
}
}
},
"paths":[
[
"genres",
6721,
{
"from":0,
"to":2
},
"videos"
]
]
}
["genres",{id_here},{"from":0,"to":30}, "videos"]
$type: "error"
, which looks something like this.{
"jsonGraph":{
"genres":{
"4":{
"0":{
"$type":"error",
"value":{
"message":"Cannot invoke method withAnnotation() on null object",
"cause":"java.lang.NullPointerException: Cannot invoke method withAnnotation() on null object"
}
},
"1":{
"$type":"error",
"value":{
"message":"Cannot invoke method withAnnotation() on null object",
"cause":"java.lang.NullPointerException: Cannot invoke method withAnnotation() on null object"
}
}
}
}
},
"paths":[
[
"genres",
4,
{
"from":0,
"to":1
},
"videos"
]
]
}
["genres",[1, 2, 3, 4, 5, 6, 7, 8],{"from":0,"to":30}, "videos"]
["genreList",{"from":0,"to":1000}]
Hey Netflix, gimme genre list that has 1000 objects!!
path
,["videos",{video_ids},["title", "runtime", "summary", "seasons", "releaseYear", "availability", "maturity", "mostWatchedData", "seasonCount", "episodeCount"]]
path
you can see we're asking for some info like title of the show, the runtime etc.["videos",80189685,["title", "runtime", "summary", "seasons", "releaseYear", "availability", "maturity", "mostWatchedData", "seasonCount", "episodeCount"]]
["videos",80189685,"seasonList",{"from":0,"to":8},"id"]
{
"jsonGraph":{
"videos":{
"80189685":{
"title":{
"$type":"atom",
"value":"The Witcher"
},
"runtime":{
"$type":"atom",
"value":null
},
"summary":{
"$type":"atom",
"$size":41,
"value":{
"id":80189685,
"type":"show",
"isOriginal":true
}
},
"releaseYear":{
"$type":"atom",
"value":2019
},
"availability":{
"$type":"atom",
"$size":84,
"value":{
"isPlayable":true,
"availabilityStartTime":1576828800000,
"availabilityDate":"December 20"
}
},
"maturity":{
"$type":"atom",
"$size":591,
"value":{
"rating":{
"value":"TV-MA",
"maturityDescription":"For Mature Audiences. May not be suitable for ages 17 and under.",
"maturityLevel":110,
"specificRatingReason":"violence, sex, nudity, language, gore, smoking",
"board":"US TV",
"boardId":10,
"reasons":[
{
"id":7415,
"reasonDescription":"violence",
"levelDescription":null
},
{
"id":7417,
"reasonDescription":"sex",
"levelDescription":null
},
{
"id":7421,
"reasonDescription":"nudity",
"levelDescription":null
},
{
"id":7426,
"reasonDescription":"language",
"levelDescription":null
},
{
"id":7429,
"reasonDescription":"gore",
"levelDescription":null
},
{
"id":7430,
"reasonDescription":"smoking",
"levelDescription":null
}
]
}
}
},
"mostWatchedData":{
"$type":"atom",
"value":null
},
"seasonCount":{
"$type":"atom",
"value":1
},
"seasonList":{
"0":{
"$type":"ref",
"value":[
"seasons",
"80189598"
]
},
"1":{
"$type":"atom"
},
"2":{
"$type":"atom"
},
"3":{
"$type":"atom"
},
"4":{
"$type":"atom"
},
"5":{
"$type":"atom"
},
"6":{
"$type":"atom"
},
"7":{
"$type":"atom"
},
"8":{
"$type":"atom"
}
},
"episodeCount":{
"$type":"atom",
"value":8
}
}
},
"seasons":{
"80189598":{
"id":{
"$type":"atom"
}
}
}
},
"paths":[
[
"videos",
80189685,
[
"availability",
"episodeCount",
"maturity",
"mostWatchedData",
"releaseYear",
"runtime",
"seasonCount",
"seasons",
"summary",
"title"
]
],
[
"videos",
80189685,
"seasonList",
{
"from":0,
"to":8
},
"id"
]
]
}
["seasons",{season_list}, "episodes", {{"from":0,"to":{total_episodes}}},["title","runtime", "summary", "releaseYear", "availability", "maturity", "mostWatchedData"]]
"80244465":{
"title":{
"$type":"atom",
"value":"Betrayer Moon"
},
"runtime":{
"$type":"atom",
"value":4022
},
"summary":{
"$type":"atom",
"$size":89,
"value":{
"idx":3,
"id":80244465,
"type":"episode",
"isOriginal":true,
"episode":3,
"season":1,
"isPlayable":true
}
},
"releaseYear":{
"$type":"atom",
"value":2019
},
"availability":{
"$type":"atom",
"$size":84,
"value":{
"isPlayable":true,
"availabilityStartTime":1576828800000,
"availabilityDate":"December 20"
}
},
"maturity":{
"$type":"atom",
"$size":591,
"value":{
"rating":{
"value":"TV-MA",
"maturityDescription":"For Mature Audiences. May not be suitable for ages 17 and under.",
"maturityLevel":110,
"specificRatingReason":"violence, sex, nudity, language, gore, smoking",
"board":"US TV",
"boardId":10,
"reasons":[
{
"id":7415,
"reasonDescription":"violence",
"levelDescription":null
},
{
"id":7417,
"reasonDescription":"sex",
"levelDescription":null
},
{
"id":7421,
"reasonDescription":"nudity",
"levelDescription":null
},
{
"id":7426,
"reasonDescription":"language",
"levelDescription":null
},
{
"id":7429,
"reasonDescription":"gore",
"levelDescription":null
},
{
"id":7430,
"reasonDescription":"smoking",
"levelDescription":null
}
]
}
}
},
"mostWatchedData":{
"$type":"atom",
"value":null
}
}
requests
,(venv) $ pip install requests
config.py
, where we'll copy our headers and urls. Next we need to somehow construct these 'paths' aka the POST
body. Let's create a file path.py
and write this class,class Path(object):
def __init__ (self, name):
self.name = name
def __str__ (self):
return self.name
def __repr__ (self):
return "'" + self.name + "'"
paths
, as we know, dictionaries can't have duplicate keys. This class allows us to create multiple keys, because we're going to pass an object, a string: 'path'
, which makes the keys 'different'. Let's create our main.py
or whatever you want to call it. We need to import our Path
class and our config, so let's add an empty __init__.py
in our directory, For the sake of simplicity, I'm going to define one function only and put everything there. Also, I would recommend using proxies.from .path import Path
from .config import url, PROXIES, headers
import requests
videos_id_list = []
# Note: We don't actually have to use the Path class here, since we have only one key-value pair.
payload = {
Path('path') : f'["genres", {list(range(1, 1000))}, {{"from":0, "to":300}}, "videos"]'
}
try:
response = requests.post(url, proxies=PROXIES, headers=headers, data=payload)
for obj in response.json().get('jsonGraph').get('videos'):
# NOTE: This most likely won't work, because `obj` is still json we need to parse.
videos_id_list.append(obj)
except Exception:
# Do something
pass
videos_payload = {
Path('path'): f"["videos",{videos_id_list},["title", "runtime", "summary", "seasons", "releaseYear", "availability", "maturity", "mostWatchedData", "seasonCount", "episodeCount"]]",
Path('path'): f"["videos", {videos_id_list}, "seasonList",{{"from":0,"to":8}},"id"]",
}
# After we get the video IDs we'll send