Using Javascript to scan JSON data from youtube API - javascript
I am trying my hand at searching youtube with the youtube API via Javascript, and as per the google docs on the matter:
<div id="agenda"></div>
<script>
function listEvents(root) {
var feed = root.feed;
var entries = feed.entry || [];
var html = ['<ul>'];
for (var i = 0; i < entries.length; ++i) {
var entry = entries[i];
console.log(entry);
var title = (entry.title.type == 'html') ? entry.title.$t : escape(entry.title.$t);
var start = (entry['gd$when']) ? entry['gd$when'][0].startTime : "";
//var id = id.video;
//alert(id);
html.push('<li>', start, ' ', title, '</li>');
}
html.push('</ul>');
document.getElementById("agenda").innerHTML = html.join("");
}
</script>
<script src="https://gdata.youtube.com/feeds/api/videos?q=all the small things&max-results=2&v=2&format=5&orderby=relevance&safeSearch=none&alt=json-in-script&callback=listEvents">
</script>
this should return data on the song(query) all the small things. and it does! however what im trying to do with this data is grab the id from the json data, but as i am completely new to json (and js for that matter) i seem to be having a hard time doing this. viewing the page with the network tools i can clearly see the section that contains the id:
"id":{"$t":"tag:youtube.com,2008:video:9Ht5RZpzPqw"}
and i can clearly see the data that i want(9Ht5RZpzPqw) however no matter how much i scoure json tutorials it makes no sense to me, google seems to do json different than every tutorial ive read. I threw together a jsbin so you can see the results yourself: jsbin
Anyone have anyideas? you can see in my code one of the many things i have tried to retrieve that data. Nothing I do seems to work though... Anyone have any ideas or pointers?
listEvents({"version":"1.0","encoding":"UTF-8","feed":{"xmlns$app":"http://www.w3.org/2007/app","xmlns":"http://www.w3.org/2005/Atom","xmlns$media":"http://search.yahoo.com/mrss/","xmlns$openSearch":"http://a9.com/-/spec/opensearch/1.1/","xmlns$gd":"http://schemas.google.com/g/2005","xmlns$yt":"http://gdata.youtube.com/schemas/2007","gd$etag":"W/\"DkEBRn08fip7I2A9WhBaFE8.\"","id":{"$t":"tag:youtube.com,2008:videos"},"updated":{"$t":"2013-05-24T19:44:17.376Z"},"category":[{"scheme":"http://schemas.google.com/g/2005#kind","term":"http://gdata.youtube.com/schemas/2007#video"}],"title":{"$t":"Videos matching: all the small things"},"logo":{"$t":"http://www.youtube.com/img/pic_youtubelogo_123x63.gif"},"link":[{"rel":"alternate","type":"text/html","href":"https://www.youtube.com"},{"rel":"http://schemas.google.com/g/2005#feed","type":"application/atom+xml","href":"https://gdata.youtube.com/feeds/api/videos?v=2"},{"rel":"http://schemas.google.com/g/2005#batch","type":"application/atom+xml","href":"https://gdata.youtube.com/feeds/api/videos/batch?v=2"},{"rel":"self","type":"application/atom+xml","href":"https://gdata.youtube.com/feeds/api/videos?alt=json-in-script&q=all+the+small+things&start-index=1&max-results=2&format=5&safeSearch=none&orderby=relevance&v=2"},{"rel":"service","type":"application/atomsvc+xml","href":"https://gdata.youtube.com/feeds/api/videos?alt=atom-service&v=2"},{"rel":"next","type":"application/atom+xml","href":"https://gdata.youtube.com/feeds/api/videos?alt=json-in-script&q=all+the+small+things&start-index=3&max-results=2&format=5&safeSearch=none&orderby=relevance&v=2"}],"author":[{"name":{"$t":"YouTube"},"uri":{"$t":"http://www.youtube.com/"}}],"generator":{"$t":"YouTube data API","version":"2.1","uri":"http://gdata.youtube.com"},"openSearch$totalResults":{"$t":1000000},"openSearch$startIndex":{"$t":1},"openSearch$itemsPerPage":{"$t":2},"entry":[{"gd$etag":"W/\"C0IMSH47eCp7I2A9WhBaFE8.\"","id":{"$t":"tag:youtube.com,2008:video:9Ht5RZpzPqw"},"published":{"$t":"2009-06-16T23:16:07.000Z"},"updated":{"$t":"2013-05-24T18:53:09.000Z"},"app$control":{"yt$state":{"$t":"Syndication of this video was restricted.","name":"restricted","reasonCode":"limitedSyndication"}},"category":[{"scheme":"http://schemas.google.com/g/2005#kind","term":"http://gdata.youtube.com/schemas/2007#video"},{"scheme":"http://gdata.youtube.com/schemas/2007/categories.cat","term":"Music","label":"Music"}],"title":{"$t":"blink-182 - All The Small Things"},"content":{"type":"application/x-shockwave-flash","src":"https://www.youtube.com/v/9Ht5RZpzPqw?version=3&f=videos&app=youtube_gdata"},"link":[{"rel":"alternate","type":"text/html","href":"https://www.youtube.com/watch?v=9Ht5RZpzPqw&feature=youtube_gdata"},{"rel":"http://gdata.youtube.com/schemas/2007#video.responses","type":"application/atom+xml","href":"https://gdata.youtube.com/feeds/api/videos/9Ht5RZpzPqw/responses?v=2"},{"rel":"http://gdata.youtube.com/schemas/2007#video.related","type":"application/atom+xml","href":"https://gdata.youtube.com/feeds/api/videos/9Ht5RZpzPqw/related?v=2"},{"rel":"http://gdata.youtube.com/schemas/2007#uploader","type":"application/atom+xml","href":"https://gdata.youtube.com/feeds/api/users/f2WBemooP2gBBx3lrraNQw?v=2"},{"rel":"self","type":"application/atom+xml","href":"https://gdata.youtube.com/feeds/api/videos/9Ht5RZpzPqw?v=2"}],"author":[{"name":{"$t":"blink-182"},"uri":{"$t":"https://gdata.youtube.com/feeds/api/users/blink182VEVO"},"yt$userId":{"$t":"f2WBemooP2gBBx3lrraNQw"}}],"yt$accessControl":[{"action":"comment","permission":"allowed"},{"action":"commentVote","permission":"allowed"},{"action":"videoRespond","permission":"allowed"},{"action":"rate","permission":"allowed"},{"action":"embed","permission":"allowed"},{"action":"list","permission":"allowed"},{"action":"autoPlay","permission":"allowed"},{"action":"syndicate","permission":"allowed"}],"gd$comments":{"gd$feedLink":{"rel":"http://gdata.youtube.com/schemas/2007#comments","href":"https://gdata.youtube.com/feeds/api/videos/9Ht5RZpzPqw/comments?v=2","countHint":47078}},"media$group":{"media$category":[{"$t":"Music","label":"Music","scheme":"http://gdata.youtube.com/schemas/2007/categories.cat"}],"media$content":[{"url":"https://www.youtube.com/v/9Ht5RZpzPqw?version=3&f=videos&app=youtube_gdata","type":"application/x-shockwave-flash","medium":"video","isDefault":"true","expression":"full","duration":173,"yt$format":5}],"media$credit":[{"$t":"blink182vevo","role":"uploader","scheme":"urn:youtube","yt$display":"blink-182","yt$type":"partner"}],"media$description":{"$t":"Music video by blink-182 performing All The Small Things. (C) 2000 Geffen Records.","type":"plain"},"media$keywords":{},"media$license":{"$t":"youtube","type":"text/html","href":"http://www.youtube.com/t/terms"},"media$player":{"url":"https://www.youtube.com/watch?v=9Ht5RZpzPqw&feature=youtube_gdata_player"},"media$restriction":[{"$t":"DE","type":"country","relationship":"deny"}],"media$thumbnail":[{"url":"http://i.ytimg.com/vi/9Ht5RZpzPqw/default.jpg","height":90,"width":120,"time":"00:01:26.500","yt$name":"default"},{"url":"http://i.ytimg.com/vi/9Ht5RZpzPqw/mqdefault.jpg","height":180,"width":320,"yt$name":"mqdefault"},{"url":"http://i.ytimg.com/vi/9Ht5RZpzPqw/hqdefault.jpg","height":360,"width":480,"yt$name":"hqdefault"},{"url":"http://i.ytimg.com/vi/9Ht5RZpzPqw/1.jpg","height":90,"width":120,"time":"00:00:43.250","yt$name":"start"},{"url":"http://i.ytimg.com/vi/9Ht5RZpzPqw/2.jpg","height":90,"width":120,"time":"00:01:26.500","yt$name":"middle"},{"url":"http://i.ytimg.com/vi/9Ht5RZpzPqw/3.jpg","height":90,"width":120,"time":"00:02:09.750","yt$name":"end"}],"media$title":{"$t":"blink-182 - All The Small Things","type":"plain"},"yt$duration":{"seconds":"173"},"yt$uploaded":{"$t":"2009-06-16T23:16:07.000Z"},"yt$uploaderId":{"$t":"UCf2WBemooP2gBBx3lrraNQw"},"yt$videoid":{"$t":"9Ht5RZpzPqw"}},"gd$rating":{"average":4.900098,"max":5,"min":1,"numRaters":144872,"rel":"http://schemas.google.com/g/2005#overall"},"yt$statistics":{"favoriteCount":"0","viewCount":"49388829"},"yt$rating":{"numDislikes":"3618","numLikes":"141254"}},{"gd$etag":"W/\"D0UCQH47eCp7I2A9WhBaFEw.\"","id":{"$t":"tag:youtube.com,2008:video:ahWmkV0mtvk"},"published":{"$t":"2007-09-19T10:10:21.000Z"},"updated":{"$t":"2013-05-24T17:07:41.000Z"},"app$control":{"yt$state":{"$t":"Syndication of this video was restricted.","name":"restricted","reasonCode":"limitedSyndication"}},"category":[{"scheme":"http://schemas.google.com/g/2005#kind","term":"http://gdata.youtube.com/schemas/2007#video"},{"scheme":"http://gdata.youtube.com/schemas/2007/categories.cat","term":"Music","label":"Music"}],"title":{"$t":"blink 182 all the small things lyrics"},"content":{"type":"application/x-shockwave-flash","src":"https://www.youtube.com/v/ahWmkV0mtvk?version=3&f=videos&app=youtube_gdata"},"link":[{"rel":"alternate","type":"text/html","href":"https://www.youtube.com/watch?v=ahWmkV0mtvk&feature=youtube_gdata"},{"rel":"http://gdata.youtube.com/schemas/2007#video.responses","type":"application/atom+xml","href":"https://gdata.youtube.com/feeds/api/videos/ahWmkV0mtvk/responses?v=2"},{"rel":"http://gdata.youtube.com/schemas/2007#video.related","type":"application/atom+xml","href":"https://gdata.youtube.com/feeds/api/videos/ahWmkV0mtvk/related?v=2"},{"rel":"http://gdata.youtube.com/schemas/2007#uploader","type":"application/atom+xml","href":"https://gdata.youtube.com/feeds/api/users/KGRY-OpB0xZLqpTZNR418w?v=2"},{"rel":"self","type":"application/atom+xml","href":"https://gdata.youtube.com/feeds/api/videos/ahWmkV0mtvk?v=2"}],"author":[{"name":{"$t":"fuckudumbcuntimnot"},"uri":{"$t":"https://gdata.youtube.com/feeds/api/users/fuckudumbcuntimnot"},"yt$userId":{"$t":"KGRY-OpB0xZLqpTZNR418w"}}],"yt$accessControl":[{"action":"comment","permission":"allowed"},{"action":"commentVote","permission":"allowed"},{"action":"videoRespond","permission":"allowed"},{"action":"rate","permission":"allowed"},{"action":"embed","permission":"allowed"},{"action":"list","permission":"allowed"},{"action":"autoPlay","permission":"allowed"},{"action":"syndicate","permission":"denied"}],"gd$comments":{"gd$feedLink":{"rel":"http://gdata.youtube.com/schemas/2007#comments","href":"https://gdata.youtube.com/feeds/api/videos/ahWmkV0mtvk/comments?v=2","countHint":5681}},"media$group":{"media$category":[{"$t":"Music","label":"Music","scheme":"http://gdata.youtube.com/schemas/2007/categories.cat"}],"media$content":[{"url":"https://www.youtube.com/v/ahWmkV0mtvk?version=3&f=videos&app=youtube_gdata","type":"application/x-shockwave-flash","medium":"video","isDefault":"true","expression":"full","duration":159,"yt$format":5}],"media$credit":[{"$t":"fuckudumbcuntimnot","role":"uploader","scheme":"urn:youtube","yt$display":"fuckudumbcuntimnot"}],"media$description":{"$t":"awsome!!!!!!!!!!!11.","type":"plain"},"media$keywords":{},"media$license":{"$t":"youtube","type":"text/html","href":"http://www.youtube.com/t/terms"},"media$player":{"url":"https://www.youtube.com/watch?v=ahWmkV0mtvk&feature=youtube_gdata_player"},"media$restriction":[{"$t":"DE","type":"country","relationship":"deny"}],"media$thumbnail":[{"url":"http://i.ytimg.com/vi/ahWmkV0mtvk/default.jpg","height":90,"width":120,"time":"00:01:19.500","yt$name":"default"},{"url":"http://i.ytimg.com/vi/ahWmkV0mtvk/mqdefault.jpg","height":180,"width":320,"yt$name":"mqdefault"},{"url":"http://i.ytimg.com/vi/ahWmkV0mtvk/hqdefault.jpg","height":360,"width":480,"yt$name":"hqdefault"},{"url":"http://i.ytimg.com/vi/ahWmkV0mtvk/1.jpg","height":90,"width":120,"time":"00:00:39.750","yt$name":"start"},{"url":"http://i.ytimg.com/vi/ahWmkV0mtvk/2.jpg","height":90,"width":120,"time":"00:01:19.500","yt$name":"middle"},{"url":"http://i.ytimg.com/vi/ahWmkV0mtvk/3.jpg","height":90,"width":120,"time":"00:01:59.250","yt$name":"end"}],"media$title":{"$t":"blink 182 all the small things lyrics","type":"plain"},"yt$duration":{"seconds":"159"},"yt$uploaded":{"$t":"2007-09-19T10:10:21.000Z"},"yt$uploaderId":{"$t":"UCKGRY-OpB0xZLqpTZNR418w"},"yt$videoid":{"$t":"ahWmkV0mtvk"}},"gd$rating":{"average":4.934968,"max":5,"min":1,"numRaters":17130,"rel":"http://schemas.google.com/g/2005#overall"},"yt$statistics":{"favoriteCount":"0","viewCount":"6287584"},"yt$rating":{"numDislikes":"278","numLikes":"16852"}}]}});
The value of $t isn't JSON, it's a String Google is using to encode information about the ID. You could do something like this:
var vidId = root.feed.id.$t.split('video:')[1];
This gets the value of $t from the ID object, then looks for the string to the right of video:.
Related
Uncaught TypeError: Cannot read property 'statistics' of undefined (jquery, youtube api v3)
Good evening. I'm calculating video ratings based on likes and dislikes of a video, on mouse hover of an element. Part of my code is below. ... $(".item-overlay").hover( function() { var video_id = $(this).find(".item-overlay-video-url").text(); var video_api = "https://www.googleapis.com/youtube/v3/videos?part=statistics&id="+video_id+"&key="+api; $.getJSON(video_api, function(data) { var likes = parseInt(data['items'][0]['statistics']['likeCount']); var dislikes = parseInt(data['items'][0]['statistics']['dislikeCount']); var total = likes+dislikes; var percentage = Math.round((likes / total) * 100); var found = false; ...do code below to display star ratings... My code works fine, the star ratings are displayed properly. However, I keep getting this error in my console: Uncaught TypeError: Cannot read property 'statistics' of undefined On this line: var likes = parseInt(data['items'][0]['statistics']['likeCount']); Can anyone tell me why I'm getting this error? The 'likes' variable cannot be null/empty, as it returns the proper number of likes for the video, and calculates properly. Not to mention, my code is working fine. Just throwing this error. Thanks. EDIT: I have added screenshots of the log output ( console.log(data['items'][0]); ), per Luiz Eduardo de Christo's request. Would it make sense that this error only shows up when I hover over different elements very quickly? Like, hovering over different songs too quickly? Perhaps faster than the code can keep up? Will adding a delay help with this error? Is that just how getJSON works if it is requested too often? EDIT 2: Added screenshot of the returned result of the 'statistics' object from youtube.
For anyone else who might be having this issue, #Akurn and #LuizEduardodeChristo suggested checking that the data exists before proceeding. It seems that YouTube does not return the 'statistics' object when it is requested too often. In my case, when a user hovers over multiple songs too quickly, the api request sometimes returns an empty object, resulting in the error. We can fix this with a simple typeof check. typeof(data['items'][0]) != 'undefined' Here is my updated code with the typeof check in place: ...some code above... $(".item-overlay").hover( function() { var video_id = $(this).find(".item-overlay-video-url").text(); var post_id = $(this).find(".item-post-id").text(); var video_api = "https://www.googleapis.com/youtube/v3/videos?part=statistics&id="+video_id+"&key="+api; $.getJSON(video_api, function(data) { if (typeof (data['items'][0]) != 'undefined') { var likes = parseInt(data['items'][0]['statistics']['likeCount']); var dislikes = parseInt(data['items'][0]['statistics']['dislikeCount']); var total = likes+dislikes; var percentage = Math.round((likes / total) * 100); var found = false; ...the rest of the code follows... This check seems to be working and I am no longer getting the error message (yet). Thanks!
How to get google search output in the google application script environment?
If I use next function to get google output: function myFunction() { var post_url, result; post_url = "http://www.google.com/search?q=stack+overflow"; result = UrlFetchApp.fetch(post_url); Logger.log(result); } doesn't work. P.S. Sorry, I have to eхplore some dependences. I take an example function scrapeGoogle() { var response = UrlFetchApp.fetch("http://www.google.com/search?q=labnol"); var myRegexp = /<h3 class=\"r\">([\s\S]*?)<\/h3>/gi; var elems = response.getContentText().match(myRegexp); for(var i in elems) { var title = elems[i].replace(/(^\s+)|(\s+$)/g, "") .replace(/<\/?[^>]+>/gi, ""); Logger.log(title); } } and it works, than I begin to do some modifications and noticed that when I have some error in code it gives me an error Request failed for http://www.google.com/search?q=labnol returned code 503. So I did some researches without error's and it solution works. But when I began to form it to the function in lib it begans to throw me an error of 503 each time! I'm very amazing of such behavior... Here is short video only for fact. https://youtu.be/Lem9eiIVY0I P.P.S. Oh! I've broke some violations, so the google engine send me to stop list so I run this: function scrapeGoogle() { var options = { 'muteHttpExceptions': true } var response = UrlFetchApp.fetch("http://www.google.com/search?q=labnol", options); Logger.log(response); } and get About this pageOur systems have detected unusual traffic from your computer network. This page checks to see if it's really you sending the requests, and not a robot. Why did this happen? As I see I have to use some special google services to get the search output and not to be prohibited?
You can use simple regex to extract Google search results. var regex = /<h3 class=\"r\">([\s\S]*?)<\/h3>/gi; var items = response.getContentText().match(regex); Alternatively, you can use the ImportXML function in sheets. =IMPORTXML(GOOGLE_URL, "//h3[#class='r']") See: Scrape Google Search with Sheets
What is the best way to parse html in google apps script
var page = UrlFetchApp.fetch(contestURL); var doc = XmlService.parse(page); The above code gives a parse error when used, however if I replace the XmlService class with the deprecated Xml class, with the lenient flag set, it parses the html properly. var page = UrlFetchApp.fetch(contestURL); var doc = Xml.parse(page, true); The problem is mostly caused because of no CDATA in the javascript part of the html and the parser complains with the following error. The entity name must immediately follow the '&' in the entity reference. Even if I remove all the <script>(.*?)</script> using regex, it still complains because the <br> tags aren't closed. Is there a clean way of parsing html into a DOM tree.
I ran into this exact same problem. I was able to circumvent it by first using the deprecated Xml.parse, since it still works, then selecting the body XmlElement, then passing in its Xml String into the new XmlService.parse method: var page = UrlFetchApp.fetch(contestURL); var doc = Xml.parse(page, true); var bodyHtml = doc.html.body.toXmlString(); doc = XmlService.parse(bodyHtml); var root = doc.getRootElement(); Note: This solution may not work if the old Xml.parse is completely removed from Google Scripts.
In 2021, the best way to parse HTML on the .gs side that I know of is... Click + next to Library Enter 1ReeQ6WO8kKNxoaA_O0XEQ589cIrRvEBA9qcWpNqdOP17i47u6N9M5Xh0 Click "Look up" Click Add Sample usage: const contentText = UrlFetchApp.fetch('https://www.somesite.com/').getContentText(); const $ = Cheerio.load(contentText); $('.some-class').first().text(); That's it -- this is probably the closest we'll get to doing jQuery-like DOM selection in GAS. The .first() is important or else you may extract more content than you expected (think of it as using querySelector() instead of querySelectorAll()). Credit where credit is due: https://github.com/tani/cheeriogs
As of May 2020, you can now use the Cheerio library for Google Apps Script to do this. Returns the content of Wikipedia's Main Page const content = getContent_('https://en.wikipedia.org'); const $ = Cheerio.load(content); Logger.log($('#mp-right').text()); Returns the content of the first paragraph <p> of Wikipedia's Main Page const content = getContent_('https://en.wikipedia.org'); const $ = Cheerio.load(content); Logger.log($('p').first().text()); To add to your project: Select Resources - Libraries... in the Google Apps Script editor. Enter the project key 1ReeQ6WO8kKNxoaA_O0XEQ589cIrRvEBA9qcWpNqdOP17i47u6N9M5Xh0 in the Add a library field, and click "Add". Select the highest version number, and click "Save".
I found that the best way to parse html in google apps is to avoid using XmlService.parse or Xml.parse. XmlService.parse doesn't work well with bad html code from certain websites. Here a basic example on how you can parse any website easily without using XmlService.parse or Xml.parse. In this example, i am retrieving a list of president from "wikipedia.org/wiki/President_of_the_United_States" whit a regular javascript document.getElementsByTagName(), and pasting the values into my google spreadsheet. 1- Create a new Google Sheet; 2- Click the menu Tools > Script editor... to open a new tab with the code editor window and copy the following code into your Code.gs: function onOpen() { var ui = SpreadsheetApp.getUi(); ui.createMenu("Parse Menu") .addItem("Parse", "parserMenuItem") .addToUi(); } function parserMenuItem() { var sideBar = HtmlService.createHtmlOutputFromFile("test"); SpreadsheetApp.getUi().showSidebar(sideBar); } function getUrlData(url) { var doc = UrlFetchApp.fetch(url).getContentText() return doc } function writeToSpreadSheet(data) { var ss = SpreadsheetApp.getActiveSpreadsheet(); var sheet = ss.getSheets()[0]; var row=1 for (var i = 0; i < data.length; i++) { var x = data[i]; var range = sheet.getRange(row, 1) range.setValue(x); var row = row+1 } } 3- Add an HTML file to your Apps Script project. Open the Script Editor and choose File > New > Html File, and name it 'test'.Then copy the following code into your test.html <!DOCTYPE html> <html> <head> </head> <body> <input id= "mButon" type="button" value="Click here to get list" onclick="parse()"> <div hidden id="mOutput"></div> </body> <script> window.onload = onOpen; function onOpen() { var url = "https://en.wikipedia.org/wiki/President_of_the_United_States" google.script.run.withSuccessHandler(writeHtmlOutput).getUrlData(url) document.getElementById("mButon").style.visibility = "visible"; } function writeHtmlOutput(x) { document.getElementById('mOutput').innerHTML = x; } function parse() { var list = document.getElementsByTagName("area"); var data = []; for (var i = 0; i < list.length; i++) { var x = list[i]; data.push(x.getAttribute("title")) } google.script.run.writeToSpreadSheet(data); } </script> </html> 4- Save your gs and html files and Go back to your spreadsheet. Reload your Spreadsheet. Click on "Parse Menu" - "Parse". Then click on "Click here to get list" in the sidebar.
Xml.parse() has an option to turn on lenient parsing, which helps when parsing HTML. Note that the Xml service is deprecated however, and the newer XmlService doesn't have this functionality.
For simple tasks such as grabbing one value from a webpage, you could use a regular expression. Regex is notoriously bad for parsing HTML as there's all sorts of weird cases it can get tripped up, but if you're confident about the HTML you're accessing this can sometimes be the simplest way. Here's an example that fetches the contents of the page's <title> tag: var page = UrlFetchApp.fetch(contestURL); var regExp = new RegExp("<title>(.*)</title>", "gi"); var result = regExp.exec(page.getContentText()); // [1] is the match group when using parenthesis in the pattern var value = result ? result[1] : 'No title found';
I know it is not exactly what OP asked, but I found this question when I was looking for some html parsing options - so it might be useful for others as well. There is an easy to use the library for TEXT parsing. It's useful if you want to get only one piece of information from the html(xml) code. EDIT 2021: The script library id is: 1Mc8BthYthXx6CoIz90-JiSzSafVnT6U3t0z_W3hLTAX5ek4w0G_EIrNw It works like in the picture above function getData() { var url = "https://chrome.google.com/webstore/detail/signaturesatori-central-s/fejomcfhljndadjlojamaklegghjnjfn?hl=en"; var fromText = '<span class="e-f-ih" title="'; var toText = '">'; var content = UrlFetchApp.fetch(url).getContentText(); var scraped = Parser .data(content) .from(fromText) .to(toText) .build(); Logger.log(scraped); return scraped; }
If you are using Cheerio library for Google Apps Script Source code Library page (⭐ star it!) Installation by library ID: 1ReeQ6WO8kKNxoaA_O0XEQ589cIrRvEBA9qcWpNqdOP17i47u6N9M5Xh0 A function to get current emojis from unicode.org: function getEmojis() { var t = new Date(); var url = 'https://unicode.org/emoji/charts/full-emoji-list.html'; var fetch = UrlFetchApp.fetch(url); var contentText = fetch.getContentText(); //console.log(new Date() - t); // Cherio var $ = Cheerio.load(contentText); var data = []; $("table > tbody > tr").each((index, element) => { var row = []; $(element).find("td").each((index, child) => { row.push($(child).text()); }); if (row.length > 0) { data.push(row); } }); //console.log(data); //console.log(new Date() - t); // Result return data; } ↑ Sample code shows how to parse table and put it into [[array]] May be used as a custom function: Bonus Parsing the site may be a time-consuming operation + you may reach the limit. Here's a test file with a full version of the script: https://docs.google.com/spreadsheets/d/1iO7YjYWyfseQu_YCfRbGDPg7NskOgMu_iO1iGjr7KxY/edit#gid=93365395 ↑ it uses CasheService to reduce the number of calls.
Natively there's no way unless you do what you already tried which wont work if the html doesnt conform with the xml format.
There are two options a) One is to use JavaScript's string functions. First locate your tag using string.indexOf() and then extract the data you want using string.substring(). b) The other option is to make use of the Xml Service.
It's not possible to create an HTML DOM server-side in Apps Script. Using regular expressions is likely your best option, at least for simple parsing.
MOSS 07 editform.aspx fails to commit and goes to blank html page
Found solution from Microsoft Blog... see below OK, to start I don't like the word random but I cannot find any correlation in test cases for this problem so I am going to use random to describe parts of this problem. The setup: I have a list where i have crated a customized UI for the EditForm.aspx and NewForm.aspx. I use the same JS file and JavaScript between the two of them. I have added in a google map to help illustrate the location selection. I have added extra code to the "OK" button for some dynamic validation. I have done a lot of dynamic menu things as well. All users use IE 9 and the site is on a MOSS 2007 server. The problem: Only on the EditForm.aspx, clicking OK "Randomly" results in an immediate white screen. The form is not saved and when viewing the source code of the white screen i find a blank html page. What I have tried to find this problem: - I tried to narrow down the user and computer this happens on and found that it happens for everyone on every computer(once again "Randomly"). - I tried disabling the code that is pre-pended to the "OK" button - I tried following the code with the IE9's external script debugged and found no errors I can provide the code but it is a bit long and I really do not know where to begin. So i can provide it if needed. Thanks for the help ahead of time. Edit: This is the code re-wiring my OK button(i reset the value to "Save" earlier) var okBtns = $('input[value="Save"]') $.each(okBtns, function(index,value){ okFunction=$(value).attr('onclick'); $(value).attr('onclick','return false;') $(value).bind('click', function(){ if ($('#'+StatusBox).val()=='Draft') {$('#'+StatusBox).val('New Request')} var err = clickOKbutton(); if(err==0) {okFunction()}; }); }); This is the clickOKbutton function witch is th code prepended to the orgianal sharepoint operations: function clickOKbutton() { //all of the imput validation i could ever wish for!!!! var NoteVal = '' var NameAry = $('#'+PersonnelBox).parent().children(":first").children("SPAN").children("SPAN"); $.each(NameAry, function(index,value){ var $n=$(value).html(); if(NoteVal.length==0) {NoteVal=$n} else {NoteVal=NoteVal+';'+$n}; }); //$('#'+AddNotes).val(NoteVal); var plh = $('#'+PersonnelBox).parent().html() userNameTx = $('#zz8_Menu').text(); userNameTx = userNameTx.replace('Welcome ',''); $.each(OICUsers, function(i,v){ if(plh.indexOf(v) > -1 && st=='New Request'){ $('#'+StatusBox).val('OIC Bypassed') $('#'+CommentsBox).val('OIC is travling on this TDY/TAD and cannot approve. So this request is bypassing the "OIC Approval" step') } }); /*userNameTx = $('#zz8_Menu').text(); userNameTx = userNameTx.replace('Welcome ','') $('#' + ModBox).closest('TR').show();*/ var message='' message = detectFieldChanges(AllFieldsArray,AllOrgValArray,"Draft,New Request,Modified") if(message.length>0){ $('#'+ModBox).val(message); AutoResizeTextarea(ModBox); } message = detectFieldChanges(ValFieldsArray,OrgValuesArray,"Draft,New Request,Modified,OIC Approved,OIC Bypassed,Pending RFI,Ready for COS") userNameTx = $('#zz8_Menu').text(); userNameTx = userNameTx.replace('Welcome ',''); if(message.length>0&&$.inArray(userNameTx,COSUsers)==-1){ $('#'+StatusBox).val('Modified').change; $('#'+StatusLongBox).val('Modified').change; } //Subject box var pb = NoteVal; var ep = $('#'+ExtPersonnel).val(); var ab = $('#'+AddressBox).val(); var sd = $('#'+sDateBox).val(); var ed = $('#'+eDateBox).val(); var st = $('#'+StatusBox).val(); var p = pb+';'+ep; var p = p.replace(/mossaspnetmembershipprovider:/g,''); var p = p.slice(0,-1); var ad = ab+' '+sd+' to '+ed; var s = 'eTDY | '+st+' - '+p+' - '+ad; if(s.length>255){ var l = s.length-255; p = p.substring(0,p.length-l); s = 'eTDY | '+p+' - '+ad; } $('#'+Subject).val(s); //check Lat/Lng value if($('#'+LatBox).val()=='' || $('#'+LngBox).val()==''){ //alert("Cannot continue unless the Lat Lng has a vallid coordinate"); if($('#LatLngError').length==0){ errorHTML='<br><span class="ms-error" id="LatLngError">You must specify a value for Lat and Lng</span>' $('#'+AddressBox).closest('TD').append(errorHTML) } return -1 } return 0 }; It is messy but hopefully you can make sense of it. Edit 2: I think I have tracked the randomness down... I completely turned off all custom code and still have the problem. I then tried comparing a working record with a non working record. Everything looked normal until i got to the field with a multiple people picker. If i have more than 2 people in that field it will save normal but when i go to make a modification on that record with more than 2 people in the people picker field is causes this problem. I am going to do some more research and will post my results. Edit 3: http://blogs.msdn.com/b/jorman/archive/2009/12/22/mystery-of-the-sharepoint-white-screens.aspx This problem all boils down to IIS configuration and the Impersonation Level. Apparently our server admins decided to change it without telling anyone.
Usually, when you get [seemingly random] behavior from a web page (especially in MOSS), it means that you have ambiguous events defined on the page. Usually, I get this when I add some kind of JScript to a button or form on_submit. Without seeing your code, I can't really narrow it down further than that. I recommend: look for JavaScript events on your HTML form or on your button click events or look for anchor [a] tags that point to nowhere (href=#) but have javascript. Then decide to do it (strictly) the HTML way (forms, submit buttons) or the javascript way, (no forms, no asp:button) and un-wire the other.
This problem all boils down to IIS configuration and the Impersonation Level. Apparently our server admins decided to change it without telling anyone. http://blogs.msdn.com/b/jorman/archive/2009/12/22/mystery-of-the-sharepoint-white-screens.aspx
Google Javascript Data API for Calendar - Event times not available
I would like to use the gdata API to retrieve some event entries from a public calendar feed. Here is the code that I'm using: var calendarService = new google.gdata.calendar.CalendarService('GoogleInc-jsguide-1.0'); var feedUri = 'http://www.google.com/calendar/feeds/.../public/basic'; var gquery = new google.gdata.calendar.CalendarEventQuery(feedUri); gquery.setFutureEvents(true); gquery.setMaxResults(10); var callback = function(result) { var entries = result.feed.entry; for (var i = 0; i < entries.length; i++ ) { var entry = entries[i]; var title = entry.getTitle().getText(); var times = entry.getTimes(); alert("Title: " + title + " | Times: " + times); } } calendarService.getEventsFeed(gquery, callback); (Feed URI is the public (or private) XML-Feed for a Google Apps Calendar) I expected to find the event times in times but it is an empty array. Which is in some way logical, because the actual feed in feedUri doesn't contain any time information. Questions: What am I doing wrong? How to retreive calendar entries which include event times? Why is there a method getTimes() if it's completely useless?
EDIT: I've just seen you're using the "basic" feed - have you tried the "full" feed instead? The description of the basic feed is: Basic Atom feed without any extension elements. Its and properties contain pre-rendered HTML. Additionally, you need to be aware of single events vs recurrent events. Information about recurrent events is available via getRecurrence(). For individual events, getTimes() will give the right information. If you don't see the information via the API, try looking at the source data directly and see whether you can see it there.