Skip to content

Instantly share code, notes, and snippets.

@Nydhal
Created July 25, 2020 11:24
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Nydhal/65a6750151c3bb56c2fed611208a8efa to your computer and use it in GitHub Desktop.
Save Nydhal/65a6750151c3bb56c2fed611208a8efa to your computer and use it in GitHub Desktop.
Scrape all your HN upvoted links and Export to CSV or HTML (from your browser).
/*
Search HN upvoted from your browser and Export to CSV or HTML.
1. Navigate your browser to https://news.ycombinator.com/user?id=YOUR_USER_ID
2. Copy code to the browser console and run.
4. Look for the popup window in the upper-left corner of your browser.
*/
(function () {
const popup = createPopup('HN upvoted');
const base = 'news.ycombinator.com';
if (location.host != base || !(location.pathname == '/user' || location.pathname == '/upvoted')) {
popup.innerHTML = 'ERROR: Unknown URL, Go to HN user page and try again.';
return;
}
const id = location.search.split('=')[1];
const types = {
csv: {
header: 'Title,Link',
filename: id + "_HN_upvoted",
totype: a => toCSV(a.title, a.link)
},
html: {
header: '<title>' + id + " HN upvoted</title><h1>" + id + " HN upvoted</h1>",
filename: id + "-HN-upvoted",
totype: a => `<p><a href="${a.link}" target="_blank" rel="noopener">${a.title}</a>`
}
};
const upvoted = [];
popup.innerHTML =
'<button id=exportToCsv data-filetype=csv>Export to CSV</button><br><br>' +
'<button id=exportToHtml data-filetype=html>Export to HTML</button><br><br>' +
'<input id=query> <button id=search>Search</button><br><br>' +
'<div id=results></div>';
exportToCsv.onclick = exportToHtml.onclick = async function () {
const filetype = this.dataset.filetype;
await getupvoted();
downloadFile(types[filetype].header, upvoted.map(types[filetype].totype), types[filetype].filename, filetype);
results.innerHTML = 'Finished exporting.';
};
search.onclick = async function () {
const re = new RegExp(query.value, 'i');
await getupvoted();
const found = upvoted.map(types.html.totype).filter(f => f.match(re));
if (found.length == 0) {
results.innerHTML = 'not found';
} else {
results.innerHTML = found.join('');
}
};
async function getupvoted() {
if (upvoted.length > 0) return;
const url = `https://${base}/upvoted?id=${id}&p=`;
for (var p = 1; true; p++) {
results.innerHTML = 'Fetching page #' + p + '<br><br>';
const response = await fetch(url + p);
const html = await response.text();
const parser = new DOMParser();
const doc = parser.parseFromString(html, "text/html");
doc.querySelectorAll('a.storylink').forEach(a => upvoted.push({title: a.innerText, link: a.href}));
if (doc.querySelector('a.morelink') == null) break;
}
}
function createPopup(title) {
const div = document.body.appendChild(document.createElement("div"));
div.innerHTML = title + " <a onclick='document.body.removeChild(this.parentNode)' style='cursor: pointer; padding: 4px'>X</a><br><br>";
div.style.position = "absolute";
div.style.zIndex = "1000";
div.style.left = "8px";
div.style.top = "8px";
div.style.backgroundColor = "white";
return div.appendChild(document.createElement("div"));
}
function toCSV(...fields) {
return fields.map(field => `"${field == undefined ? "" : field.toString().replace(/"/g, '""')}"`).join(',');
}
function downloadFile(header, lines, filename, filetype) {
const a = document.body.appendChild(document.createElement('a'));
a.href = URL.createObjectURL(new Blob([header + "\n" + lines.join("\n")], {type: 'text/' + filetype}));
const date = (new Date()).toISOString().replace(/[T:]/g, "-").substr(0, 19);
a.download = `${filename}-${date}.${filetype}`;
a.click();
}
})();
@Nydhal
Copy link
Author

Nydhal commented Jul 25, 2020

Credit goes to Gabriel Sroka at https://gabrielsroka.github.io/

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment