Extraire une section d'une page Web a apparemment des informations périmées ; le web scraping de février 2020 ne semble plus fonctionner en juillet 2021. Eh bien, c'est normal car il n'y a aucune raison pour que YouTube ne puisse pas modifier le code HTML qui formate la page Web. @LNitz m'a incité à jeter un autre regard et à montrer comment utiliser une API plus officielle pour obtenir les données et comment stocker ces données dans une table de données.
Les commentaires dans le JSL vous dirigeront vers une page où vous pourrez obtenir une clé API. Google/YouTube utilise la clé pour limiter le nombre de requêtes que vous pouvez effectuer. Construire ce code a apparemment utilisé environ 500/10 000 de mon quota quotidien. Je l'ai beaucoup couru. https://console.cloud.google.com/apis/dashboard .
La question initiale concernait l'intégration des descriptions de vidéos YouTube dans un tableau de données. La réponse a téléchargé le HTML de la page Web (~ 500 Ko) et le modèle correspondant aux mots-clés... qui semblent avoir changé, donc la correspondance ne fonctionne plus. L'API devrait être plus robuste. Il renvoie des données JSON, bien plus faciles à analyser que HTML. Plus petit aussi. Le problème consiste désormais à lire la documentation de l'API pour comprendre comment cela fonctionne. Heureusement, la plupart des questions peuvent être recherchées sur Google.
Video links, descriptions, thumbnails.Video links, descriptions, thumbnails.Video links, descriptions, thumbnails.Video links, descriptions, thumbnails.Liens vidéo, descriptions, vignettes.
JSL, ci-joint, ajoute également les liens bleus à la colonne ID.
Le JSL utilise plusieurs API :
- chaînes - trouvez ma chaîne et l'identifiant de la liste de téléchargement de ma chaîne.
- playlistItems - la liste de téléchargement est une liste de lecture. Obtenez les identifiants vidéo de cette liste de lecture.
- vidéos - obtenez des informations sur une vidéo en utilisant son identifiant.
Les identifiants de vidéo YouTube sont les valeurs cryptées des liens bleus dans l'image. Le JSL est un peu idiot car les informations stockées dans la table de données étaient disponibles à partir des éléments de la liste de lecture, mais vous commencez peut-être avec des identifiants vidéo qui ne figurent pas dans une liste de lecture.
L'API offre bien d'autres fonctionnalités ; à peu près tout ce que vous pouvez faire à partir de l'interface Web (télécharger, supprimer, etc.) peut être effectué via l'API.
Modifier: @bryan_boone publié plus d'informations dans Intégration de Google Drive avec JMP à l'aide d'une requête HTTP -- lié aux clés que vous pouvez obtenir depuis la console Google.
merci beaucoup! @Craige_Hales ,
C'est très utile. Je me suis basé sur cela pour créer une liste de playlists d'une chaîne et une liste de vidéos dans ces playlists.
Cette tâche peut devenir plus compliquée lorsqu'il y a plus de 50 vidéos dans une playlist, plus de 50 playlists, certaines vidéos sont privées, manquent de description ou toutes sortes de clés dans les travaux de YouTube.
Mon script aborde certains de ces problèmes et bien d'autres dans le but de le rendre robuste.
//create a JMP data table with all playlists of https://www.youtube.com/c/JMPSoftwareFromSAS
// this script produces 2 data tables:
// 1) A list of playlists on a channel.
// 2) A list of videos from all the playlists.
Names Default To Here( 1 );
// in order to use API tools from google registration is required and an API key is needed.
// in order to get an api key.
// go to https://console.cloud.google.com/
// create new project (YouTube data api V3)
// create crdentials - YouTube data api V3 - Public data.
// Define Google API Key directly or in a separate file
apikey = "aaabbbcccdddeeefffggghhhiiijjjkkklllmmmnnnoooppp"; // directly
// Define channel id for which to get the list of Playlists - get it from Youtube
// Open ("https://www.youtube.com/c/JMPSoftwareFromSAS");// JMP Software From SAS
// if channel id is not explicit search it at https://commentpicker.com/youtube-channel-id.php
Channelid = "UCPOQfD32PLMVdTg-38OwjCA";
// set up a data table for the list of playlists
dtplaylists = New Table( "JMP Software From SAS - list of playlists",
New Column( "Playlist name", Character, "Nominal" ),
New Column( "Playlist description", Character, "Nominal" ),
New Column( "Playlist link", Character, "Nominal" ),
New Column( "Playlistid", Character, "Nominal" ),
);
// this youtube api query brings a list of playlists from the channel using channelid and apikey
// if there are more than 50 playlists this needs to be in a loop
jsonplaylistslist = Parse JSON(
Open( "https://youtube.googleapis.com/youtube/v3/playlists?part=snippet&channelId=" || Channelid || "&maxResults=50&key=" || apikey )
);
nplaylists = jsonplaylistslist["pageInfo"]["totalResults"];
Show( nplaylists );
resultsperpage = N Items( jsonplaylistslist["items"] );
Show( resultsperpage );
// extract the title, description and id of each list into the data table.
For( playlistspage = 1, playlistspage <= Ceiling( nplaylists / 50 ), playlistspage++,
For( iplaylists = 1, iplaylists <= resultsperpage, iplaylists++,
dtplaylists << add rows( 1 );
dtplaylists:Playlist name[N Rows()] = jsonplaylistslist["items"][iplaylists]["snippet"]["title"];
dtplaylists:Playlist description[N Rows()] = jsonplaylistslist["items"][iplaylists]["snippet"]["description"];
dtplaylists:Playlistid[N Rows()] = jsonplaylistslist["items"][iplaylists]["id"];
dtplaylists:Playlist link[N Rows()] = "https://www.youtube.com/playlist?list=" || jsonplaylistslist["items"][iplaylists]["id"];
playlistid = jsonplaylistslist["items"][iplaylists]["id"];
);
// inspect whether the list is complete or has a next page with more playlists
jsonplaylistslistkeys = jsonplaylistslist << get keys;
// if no nextPageToken exists - break the loop
If( Contains( jsonplaylistslistkeys, "nextPageToken" ) == 0,
Break()
);
// if nextPageToken is present get the next page
nextpagetoken = jsonplaylistslist["nextPageToken"];
jsonplaylistslist = Parse JSON(
Open(
"https://youtube.googleapis.com/youtube/v3/playlists?part=snippet&channelId=" || Channelid || "&maxResults=50&pageToken=" ||
nextpagetoken || "&key=" || apikey
)
);
// set the number of internal loops according to the number of items.
resultsperpage = N Items( jsonplaylistslist["items"] );
Show( resultsperpage );
);
// set up a data table to host the videos in all play lists
dt = New Table( "JMP Software From SAS - YouTube Playlist",
Set Cell Height( 100 ), // make cells taller to show description and picture
New Column( "Videoname", Character, "Nominal" ),
// new column for individual video tags
New Column( "Tags", Character, "Nominal", Set Display Width( 150 ) ),
New Column( "Playlist name", Character, "Nominal" ),
New Column( "Playlist description", Character, "Nominal" ),
New Column( "playlist link",
Character,
"Nominal",
Set Property(
"Event Handler",
Event Handler(
Click(JSL Quote(Function( {thisTable, thisColumn, iRow}, { },
Web( Char( thisTable:thisColumn[ iRow ] ) ); // open a web page
);) ),
Tip(JSL Quote(Function( {thisTable, thisColumn, iRow}, // 3 parameters
{ }, "Open " || Char( thisTable:thisColumn[ iRow ] ) || " in your browser."; // return the tool tip string
); ) ),
Color(JSL Quote(Function( {thisTable, thisColumn, iRow}, // 3 parameters
{ },
RGBColor("link"););
) )
)
),
),
New Column( "id",
Character,
"Nominal",
Set Property(
"Event Handler",
Event Handler( // use the column properties GUI to create this code
Click(JSL Quote(Function( {thisTable, thisColumn, ivids},
// add the youtube bit to the link...most of this was generated by the GUI
Web( Char( "https://youtu.be/"||thisTable:thisColumn[ ivids ] ) );
); ) ),
Tip(JSL Quote(Function( {thisTable, thisColumn, ivids},
"Open " || Char( thisTable:thisColumn[ ivids ] ) || " in your browser.";
); ) ),
Color(JSL Quote(Function( {thisTable, thisColumn, ivids},
RGBColor("link");
); ) )
)
),
),
// a column for the description text
New Column( "Description", character, "Nominal", Set Display Width( 350 ) ),
// a column for image link
New Column( "Image", Character, "Nominal", Set Display Width( 150 ) ),
);
// Here is where we start scraping the data per video
// this first youtube api query is to get the channel's uploads playlist ID
// Note: if there are less than 51 such videos this will suffice. otherwise a loop is required.
jsonChannel = Parse JSON(
Open( "https://youtube.googleapis.com/youtube/v3/channels?part=snippet,contentDetails,statistics&id=" || Channelid || "&key=" || apikey )
);
// extract channel description for later use
channel_description = jsonChannel["items"][1]["snippet"]["description"];
Show( channel_description );
For( ilist = 1, ilist <= nplaylists, ilist++,
// get the playlists one by one
currentplaylist = dtplaylists:Playlist id[ilist];
// this next api query gets the video IDs (and a lot of other info, which will be
// re-obtained below. You might have some other way to get video IDs, not from a playlist.)
jsonPlayList = Parse JSON(
Open( "https://www.googleapis.com/youtube/v3/playlistItems?part=snippet&maxResults=50&playlistId=" || currentplaylist || "&key=" || apikey )
);
//extract plylist length
playlistlenghth = jsonPlayList["pageInfo"]["totalResults"];
Show( playlistlenghth );
For( playlistpage = 1, playlistpage <= Ceiling( playlistlenghth / 50 ), playlistpage++,
// fill up the table
nvids = N Items( jsonPlayList["items"] );
Show( playlistpage, nvids );
// i presents video number
For( i = 1, i <= nvids, i += 1,
dt << add rows( 1 );
dt:Playlist name[N Row()] = dtplaylists:Playlist name[ilist];
dt:Playlist description[N Row()] = dtplaylists:Playlist description[ilist];
dt:playlist link[N Row()] = dtplaylists:Playlist link[ilist];
dt:id[N Row()] = jsonPlayList["items"][i]["snippet"]["resourceId"]["videoId"];
dt:Videoname[N Row()] = videotitle = jsonPlayList["items"][i]["snippet"]["title"];
Show( videotitle );
// string together the url for the api to get info about the video id on this row
json = Open( "https://www.googleapis.com/youtube/v3/videos?id=" || dt:id[N Row()] || "&key=" || apikey || "&part=snippet" );
// convert the JSON string to an associative array we can index with keys to extract parts of interest
jsonvideo = Parse JSON( json ); // make associative array
//extract the description itself and set it in the data table - Private vidos have no description...
If( jsonvideo["items"] != {},
If( Contains( jsonvideo["items"][1]["snippet"], "description" ) > 0,
dt:Description[N Row()] = jsonvideo["items"][1]["snippet"]["description"],
dt:Description[N Row()] = ""
)
);
// use the default / medium / high / maxres / medium / standard thumb nail url to fetch a pic via open()
dt:Image[N Row()] = "https://youtu.be/" || jsonPlayList["items"][i]["snippet"]["resourceId"]["videoId"];
// extract video tags
If( jsonvideo["items"] != {},
If( Contains( jsonvideo["items"][1]["snippet"], "tags" ) > 0,
dt:Tags[N Row()] = Substitute( Char( jsonvideo["items"][1]["snippet"]["tags"] ), "{\!"", "#", ", ", ", #", "}", "", "\!"", "" ),
dt:Tags[N Row()] = ""
)
);
Wait( 0 );
);
// inspect whether the list is complete or has a next page with more videos.
playlistkeys = jsonPlayList << get keys;
If( Contains( playlistkeys, "nextPageToken" ) == 0,
Break()
);
nextPage = jsonPlayList["nextPageToken"];
jsonPlayList = Parse JSON(
Open(
"https://www.googleapis.com/youtube/v3/playlistItems?part=snippet&maxResults=50&pageToken=" || nextPage || "&playlistId=" ||
currentplaylist || "&key=" || apikey
)
);
);
);
dt << Optimize Display;
Vous pouvez également effectuer une recherche par nom de chaîne plutôt que par ID :
Veritasium uses 1Veritasium for the actual channel name. There is a re-direct easter egg at the other one.Veritasium uses 1Veritasium for the actual channel name. There is a re-direct easter egg at the other one.Veritasium uses 1Veritasium for the actual channel name. There is a re-direct easter egg at the other one.Veritasium uses 1Veritasium for the actual channel name. There is a re-direct easter egg at the other one.Veritasium utilise 1Veritasium pour le nom réel du canal. Il y a un œuf de Pâques redirigé vers l'autre.