private void GetUrlsFromPlayListWrapper(HtmlNodeCollection mp3AnchorSet, ref ParserResult parserResult) { /* * <div class="sm2-playlist-wrapper"> * <ul class="sm2-playlist-bd"> * <li> * <div part="1" class="sm2-row sm2-wide" id="file-8490384"> * ===> <a href="https://vltava.rozhlas.cz/sites/default/files/audios/8823b0fd947daa76167e9014d6ed4014.mp3?uuid=5c17536947ad0"> * <div class="filename" title="Steinar Bragi: Planina"> * <div class="filename__text" title="Steinar Bragi: Planina">1. díl: Steinar Bragi: Planina</div> * </div> * </a> * <div class="audio-info-wrap"> * <span class="playlist-audio-time-to-expire"> * <span class="caption__desktop-only">k poslechu </span>ještě 3 dny</span> * <span class="playlist-audio-length">28:14</span> * </div> * </div> * </li> */ if (parserResult == null) { return; } if (mp3AnchorSet != null || mp3AnchorSet.Any()) { foreach (var mp3A in mp3AnchorSet) { // each single anchor: // <a href = "https://vltava.rozhlas.cz/sites/default/files/audios/8823b0fd947daa76167e9014d6ed4014.mp3?uuid=5c17536947ad0" > // <div class="filename" title="Steinar Bragi: Planina"> // <div class="filename__text" title="Steinar Bragi: Planina">1. díl: Steinar Bragi: Planina</div> // </div> // </a> var url = mp3A.Attributes["href"]?.Value; var filenameTextNode = mp3A.ChildNodes.SelectMany(p => p.ChildNodes).FirstOrDefault(p => p.Attributes.Any(a => a.Name == "class" && a.Value == "filename__text")); // verze - napr cetba, serial - vice dilu var title = filenameTextNode?.InnerHtml?.Trim(); if (string.IsNullOrEmpty(title)) { // verze - jen jeden dil nejakeho poradu title = mp3A?.InnerHtml; } parserResult.AddUrl(url, title); } } else { parserResult.AddLog($"ParsePrehrat2018Html - mp3AnchorSet is null."); } }
public override ParserResult ParseHtml(string html) { var parserResult = new ParserResult(); try { // html nemusi byt validni xml, takze je potreba pro parsovani pouzit Html Agility Pack var htmlDoc = new HtmlDocument(); htmlDoc.LoadHtml(html); // get all <script> under <head> var xpathNodes = htmlDoc.DocumentNode.SelectNodes(@"//head//script"); if (xpathNodes != null && xpathNodes.Any()) { var croplayerJson = xpathNodes.FirstOrDefault(p => p.InnerText.Contains("croplayer"))?.InnerText; if (!string.IsNullOrEmpty(croplayerJson)) { // select inner json data from <script> element var json = croplayerJson.RemoveStartTextTo('{').RemoveEndTextTo('}'); json = "{" + json + "}"; var jObject = JObject.Parse(json); // main id for download mp3 var trackId = GetJsonAttributeValue(jObject, "track"); if (!string.IsNullOrEmpty(trackId)) { var fullMp3Url = GetIRadioMp3Url(trackId); parserResult.AddUrl(fullMp3Url, ""); // parserResult.RozhlasUrlSet[0].SiteName = GetJsonAttributeValue(jObject, "station"); parserResult.RozhlasUrlSet[0].Title = GetMetaTagContent(htmlDoc, @"//meta[@name='og:title']"); // parserResult.RozhlasUrlSet[0].Description = GetMetaTagContent(htmlDoc, @"//meta[@name='description']"); } else { parserResult.AddLog("Chyba při parsování html - nepodařilo se dohledat trackID v json datech."); } } else { parserResult.AddLog("Chyba při parsování html - nepodařilo se dohledat 'Drupal.Setings' json data."); } } else { parserResult.AddLog("Chyba při parsování html - nepodařilo se dohledat //head//script nody."); } } catch (Exception ex) { parserResult.AddLog($"ParsePrehrat2018Html error: {ex.Message}."); } return(parserResult); }
//public async Task<ParserResult> Parse(string url) //{ // var html = await DownloadHtml(url); // if (string.IsNullOrEmpty(html)) // return new ParserResult(null).AddLog($"Nepodařilo se stažení hlavní stránky: '{url}'"); // no source html - no fun // //Parse(parserResult); // else // return ParseHtml(html); // try to parse //} // private async Task<string> DownloadHtml(string url) // { // var asyncDownloader = new AsyncDownloader(); // var downloaderOutput = await asyncDownloader.GetString(url); // return downloaderOutput.DownloadOk ? downloaderOutput.Output : null; // { // //return new ParserResult(downloaderOutput.Output); // } //// return new ParserResult(null).AddLog($"Nepodařilo se stažení hlavní stránky: '{url}'"); // } //private async Task<ParserResult> TryDecodeUrl(string url) //{ // var asyncDownloader = new AsyncDownloader(); // var downloader = await asyncDownloader.GetString(url); // if (downloader.DownloadOk) // { // return Parse(downloader.Output); // } // else // { // return new ParserResult().AddLog($"Nepodařilo se stažení: '{url}'"); // } //} public override ParserResult ParseHtml(string html) { var parserResult = new ParserResult(); try { // html nemusi byt validni xml, takze je potreba pro parsovani pouzit Html Agility Pack var htmlDoc = new HtmlDocument(); htmlDoc.LoadHtml(html); // hlavni title cele stranky - tj je-li vice dilu, tak spolecny nazev - nasledne bych ho mel pouzit pro folder kam budu ukladat // mozna by slo pouzit i <h1>, ale zatim beru tohle: // <meta property="og:title" content="Steinar Bragi: Planina" /> var metaTitle = htmlDoc.DocumentNode.SelectSingleNode(@"//meta[@property='og:title']"); if (metaTitle != null) { parserResult.MetaTitle = metaTitle.Attributes.FirstOrDefault(p => p.Name == "content")?.Value?.Trim(); } if (string.IsNullOrEmpty(parserResult.MetaTitle)) { parserResult.MetaTitle = "DESCRIPTION_NOT_FOUND"; } // hlavni description cele stranky - asi nebude potreba? // <meta property="og:description" content="Sugestivní a výborně napsaný příběh o vině a nevinnosti, hranicích lidskosti a střetnutí s chladnou krutostí islandské přírody i vlastním nitrem – dílo, které v sobě spojuje prvky psychologického thrilleru a islandské lidové pověsti. Četbu na pokračování z románu současného islandského spisovatele poslouchejte on-line po dobu jednoho týdne po odvysílání." /> parserResult.MetaDescription = htmlDoc.DocumentNode.SelectSingleNode(@"//meta[@property='og:description']") ?.Attributes ?.FirstOrDefault(p => p.Name == "content") ?.Value ?.Trim(); // <meta property="og:site_name" content="Radiožurnál" /> var siteNameItem = htmlDoc.DocumentNode.SelectSingleNode(@"//meta[@property='og:site_name']"); if (siteNameItem != null) { parserResult.MetaSiteName = siteNameItem.Attributes.FirstOrDefault(p => p.Name == "content")?.Value?.Trim(); } else { parserResult.MetaSiteName = "UNKNOWN_SITE_NAME"; } // jednotlive podary (dily serialu) jsou pod <div class="sm2-playlist-wrapper"> < ul class="sm2-playlist-bd"> // get all <script> under <head> var headScriptSet = htmlDoc.DocumentNode.SelectNodes(@"//head//script"); if (headScriptSet != null && headScriptSet.Any()) { // < div class="sm2-playlist-wrapper"> //var divSetXXX = htmlDoc.DocumentNode.SelectNodes(@"//div[@part and class='sm2-row sm2-wide']"); //var divPlaylistSet = htmlDoc.DocumentNode.SelectNodes(@"//div[@class='sm2-playlist-wrapper']"); var mp3AnchorSet = htmlDoc.DocumentNode.SelectNodes(@"//div[@class='sm2-playlist-wrapper']//ul//li//div//a"); GetUrlsFromPlayListWrapper(mp3AnchorSet, ref parserResult); if (parserResult.RozhlasUrlSet.Any()) { return(parserResult); } // if (divPlaylistSet != null && divPlaylistSet.Any()) // { // foreach(var divPlaylistRoot in divPlaylistSet) // { // // Get(divPlaylistRoot, ref parserResult); // //var divSet = divPlaylistRoot.SelectNodes(@".//div[@part and class='sm2 - row sm2 - wide']"); // //var div1 = divPlaylistRoot.ChildNodes.FirstOrDefault(p => p.Attributes["part"] != null); //// ...SelectNodes(@".//div[@part]"); // } // } // jiny zpusob ziskani z Drupal.settings var drupalSettingsJson = headScriptSet.FirstOrDefault(p => p.InnerText.Contains("jQuery.extend(Drupal.settings"))?.InnerText; if (!string.IsNullOrEmpty(drupalSettingsJson)) { // select inner json data from <script> element var json = drupalSettingsJson.RemoveStartTextTo('{').RemoveEndTextTo('}'); json = "{" + json + "}"; var jObject = JObject.Parse(json); // ajaxPageState "soundmanager2":{ var downloadItem = jObject.SelectToken("soundmanager2.playtime"); if (downloadItem != null) { foreach (JToken item in downloadItem.Children()) { // takhle to vypada: "https://region.rozhlas.cz/sites/default/files/audios/68919bf46b77f6246089a1dd38b35bf9.mp3": "https://region.rozhlas.cz/audio-download/sites/default/files/audios/68919bf46b77f6246089a1dd38b35bf9-mp3" // mp3 se da stahnout z obou url ... zatim tedy budu pouzivat ten prvni var urlToken = item.ToString(); if (!string.IsNullOrEmpty(urlToken)) { var urlSet = urlToken.Split('"'); if (urlSet.Count() > 2) { parserResult.AddUrl(urlSet[1], ""); } } } } // nektere 'prehrat' html stranky nemaji prehravac s json daty a mp3 url musim dohledat jinde ve strance if (!parserResult.RozhlasUrlSet.Any()) { // najit prislusny div var parentDiv = htmlDoc.DocumentNode.SelectSingleNode(@"//div[@aria-labelledby='Audio part']"); // pod nim by mel byt jeden <a> s href atributem - url k mp3 if (parentDiv != null) { var aHref = parentDiv.ChildNodes.FirstOrDefault(p => p.Name == "a")?.Attributes["href"]?.Value; if (!string.IsNullOrEmpty(aHref)) { parserResult.AddUrl(aHref, null); } } } // po vsechn pokusech nic nenalezeno? if (parserResult.RozhlasUrlSet.Any()) { // title jen vykousnu ze stranky GetTitleFromH1(htmlDoc, ref parserResult); } else { parserResult.AddLog("Chyba při parsování html - nepodařilo se dohledat seznam url z json dat."); } } else { parserResult.AddLog("Chyba při parsování html - nepodařilo se dohledat 'Drupal.Setings' json data."); } } else { parserResult.AddLog("Chyba při parsování html - nepodařilo se dohledat //head//script nody."); } } catch (Exception ex) { parserResult.AddLog($"ParsePrehrat2018Html error: {ex.Message}."); } return(parserResult); }