Skip to content

Instantly share code, notes, and snippets.

@book000
Last active February 6, 2025 13:14
Show Gist options
  • Save book000/b06fd4b59201e39a6fd0630ba3e99e6c to your computer and use it in GitHub Desktop.
Save book000/b06fd4b59201e39a6fd0630ba3e99e6c to your computer and use it in GitHub Desktop.
/**
* DLsite の購入履歴ページ HTML をパースし、購入履歴情報をリストとして返す
*
* @param doc DLsite の購入履歴ページの HTML ドキュメント
* @returns 購入履歴情報のリストと、次のページがあるかどうかの真偽値
*/
function parseUserBuyPage(doc) {
const elements = Array.from(
doc.querySelectorAll("div#buy_history_this > table.work_list_main tr:not(:first-child)")
);
const items = elements.map((item) => {
const buyDate = item.querySelector("td.buy_date").textContent.trim();
const itemWorkNameTag = item.querySelector("td.work_content dt.work_name");
if (!itemWorkNameTag) {
throw new Error("Item work name not found");
}
const itemName = itemWorkNameTag.textContent.trim();
const itemLinkTag = itemWorkNameTag.querySelector("a");
const itemLink = itemLinkTag ? itemLinkTag.href : null;
const itemMarkerNameTag = item.querySelector(
"td.work_content dd.maker_name"
);
if (!itemMarkerNameTag) {
throw new Error("Item marker name not found");
}
const itemMarkerName = itemMarkerNameTag.textContent.trim();
const itemMarkerTag = itemMarkerNameTag.querySelector("a");
const itemMarkerLink = itemMarkerTag ? itemMarkerTag.href : null;
const genreTags = Array.from(
item.querySelectorAll("td.work_content dd.work_genre > span")
);
const genres = genreTags.map((tag) => tag.textContent.trim());
const price = item.querySelector("td.work_price").textContent.trim();
return {
buyDate,
itemLink,
itemName,
itemMarkerLink,
itemMarkerName,
genres,
price,
};
});
const paginationLastElement = doc.querySelector("table.global_pagination td.page_no ul li:last-child");
const hasNextPage =
paginationLastElement &&
paginationLastElement.textContent.trim() === "最後へ";
return {
items,
hasNextPage,
};
}
/**
* DLsite の購入履歴ページを取得し、購入履歴情報をリストとして返す
*
* @param page 取得するページ番号
* @returns 購入履歴情報のリストと、次のページがあるかどうかの真偽値
*/
async function getUserBuys(page) {
const url =
`https://www.dlsite.com/maniax/mypage/userbuy/=/type/all/start/all/sort/1/order/1/page/${page}`;
const response = await fetch(url);
const html = await response.text();
const parser = new DOMParser();
const doc = parser.parseFromString(html, "text/html");
return parseUserBuyPage(doc);
}
/**
* DLsite の全ての購入履歴情報を取得する
*
* @returns 購入履歴情報のリスト
*/
async function getAllUserBuys() {
const allItems = [];
let page = 1;
let hasNextPage = true;
while (hasNextPage) {
console.log(`Fetching page ${page}...`);
const { items, hasNextPage: nextPage } = await getUserBuys(page);
console.log(`Fetched ${items.length} items from page ${page}. hasNextPage: ${nextPage}`);
allItems.push(...items);
hasNextPage = nextPage;
page++;
}
return allItems;
}
function isViewingUserBuysPage() {
return location.href.startsWith(
"https://www.dlsite.com/maniax/mypage/userbuy"
);
}
/**
* DLsite の全ての購入履歴情報を JSON ファイルとしてダウンロードする
*/
async function downloadUserBuys() {
if (!isViewingUserBuysPage()) {
console.error("このスクリプトは DLsite の購入履歴ページで実行する必要があります。");
console.error("3 秒後にユーザー購入履歴ページにリダイレクトします...");
console.error("ページが読み込まれた後に再度このスクリプトを実行してください。");
setTimeout(() => {
location.href = "https://www.dlsite.com/maniax/mypage/userbuy";
}, 3000);
return;
}
const items = await getAllUserBuys();
const json = JSON.stringify(items, null, 2);
const jsonBlob = new Blob([json], { type: "application/json" });
const jsonUrl = URL.createObjectURL(jsonBlob);
const jsonLink = document.createElement("a");
jsonLink
.setAttribute("href", jsonUrl);
jsonLink.setAttribute("download", "dlsite_user_buys.json");
jsonLink.click();
console.log("Downloaded dlsite_user_buys.json");
}
await downloadUserBuys();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment