Last active
November 15, 2017 18:11
-
-
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.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** 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
Sample URLs: