Skip to content

Instantly share code, notes, and snippets.

@noelleleigh
Last active November 15, 2017 18:11
Show Gist options
  • Save noelleleigh/349db90901062500a5acd5e45a207e3a to your computer and use it in GitHub Desktop.
Save noelleleigh/349db90901062500a5acd5e45a207e3a to your computer and use it in GitHub Desktop.
Function for extracting the asker, question, and question details from Yahoo Answer question pages.
/** Pass an object with `asker`, `question`, and `details` properties for the given Yahoo Answers
* question page URL to the callback function.
*/
(function getYahooQuestion(url, callback) {
/** Error to throw when a user data ID cannot be found. */
class NoUserDataIdError extends Error {
constructor() {
super();
this.name = 'NoUserDataIdError';
}
}
/** Resolve promise if response is OK, otherwise, reject with an error. */
const checkStatus = function checkResponseStatus(res) {
return res.ok ?
Promise.resolve(res) :
Promise.reject(new Error(`${res.url} returned ${res.status} (${res.statusText})`));
};
/** Convenience function for creating a DOM from HTML text. */
const makeDOM = function makeDomFromHTMLString(htmlString) {
const domTree = document.createElement('html');
domTree.innerHTML = htmlString;
return domTree;
};
/** Resolve promise if a data ID of the question asker exists in the provided DOM, otherwise
* reject with a NoUserDataIdError.
*/
const getUserDataId = function getUserDataIdFromDOM(dom) {
if (dom.querySelector('#yq-question-detail-profile-img .profileImage') !== null) {
const askerDataId = dom
.querySelector('#yq-question-detail-profile-img .profileImage')
.getAttribute('data-id');
return Promise.resolve(askerDataId);
}
return Promise.reject(new NoUserDataIdError('Unable to find asker data ID'));
};
/** Return a URL query string from a given object. */
const buildQueryString = function buildQueryStringFromObject(params) {
// Shorten this function name for convenience
const enc = encodeURIComponent;
return Object.keys(params)
.map(key => `${enc(key)}=${enc(params[key])}`)
.join('&')
}
/** Return a fetch promise for the URL containing profile information for the given user
* data ID.
*/
const fetchProfileCard = function fetchProfileCard(dataId) {
const requestParams = {name: 'YAProfileCardModule', show: dataId};
const requestUrl = `https://answers.yahoo.com/_module?${buildQueryString(requestParams)}`;
return fetch(requestUrl);
};
/** Return the user name from the profile information returned by `fetchProfileCard()`. */
const getNameFromProfileCard = function getNameFromProfileCard(profileCardJson) {
return makeDOM(profileCardJson.YAProfileCardModule.html)
.querySelector('#profile-nickname').textContent;
};
/** Resolve promise with the question title from the DOM of a Yahoo Answers question page. */
const getQuestionFromDom = function getQuestionFromDom(dom) {
return Promise.resolve(dom.querySelector('#ya-question-detail h1').textContent.trim());
};
/** Resolve promise with the question details from the DOM of a Yahoo Answers question page.
*
* If no question details found, reject promise with Error.
*/
const getQuestionDetailsFromDom = function getQuestionDetailsFromDom(dom) {
if (dom.querySelector('#ya-question-detail .ya-q-show-more') !== null) {
return Promise.resolve(
dom.querySelector('#ya-question-detail .ya-q-full-text').textContent.trim()
);
}
if (dom.querySelector('#ya-question-detail .ya-q-text') !== null) {
return Promise.resolve(
dom.querySelector('#ya-question-detail .ya-q-text').textContent.trim()
);
}
return Promise.reject(new Error('No question details found'));
};
/** Return the question asker name from the DOM of a Yahoo Answers question page.
*
* If the user is anonymous, return "Anonymous".
*
* If the user no longer exists, return "<Error: User not found>"
*/
const getAskerNameFromDom = function getAskerNameFromDom(dom) {
return getUserDataId(dom)
.then(fetchProfileCard)
.then(checkStatus)
.then(response => response.json())
.then(getNameFromProfileCard)
.catch(error => (
error.name === 'NoUserDataIdError' ?
'Anonymous' :
'<Error: User not found>'
));
};
// Don't even try to run this function on a non-Yahoo Answers page
const yahooRegex = /^https:\/\/answers\.yahoo\.com\/question\/index\?qid=\w+/g;
if (!yahooRegex.test(url)) {
throw new Error('This script only accepts Yahoo Answer URLs');
}
// Fetch the page HTML and extract the information
fetch(url)
.then(checkStatus)
.then(response => response.text())
.then(makeDOM)
.then(pageDom => (
Promise.all([
getAskerNameFromDom(pageDom),
getQuestionFromDom(pageDom),
getQuestionDetailsFromDom(pageDom).catch(''),
])
))
.then((promises) => {
const [asker, question, details] = promises;
return {asker, question, details}
})
.then(callback);
}(window.location.href, console.log));
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment