Created
August 13, 2020 07:59
-
-
Save ci7lus/29efeac02148c2a68eaa4169cff5f924 to your computer and use it in GitHub Desktop.
https://booth.pm の検索結果における新規商品を取得
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
import { defineComponent } from "ironpipe" | |
import axios from "axios" | |
import domino from "domino" | |
/** | |
* booth-search.ts | |
* MIT License (c) 2020 ci7lus | |
*/ | |
module.exports = defineComponent({ | |
name: "booth-search", | |
version: "0.0.1", | |
props: { | |
timer: { | |
type: "$.interface.timer", | |
default: { | |
intervalSeconds: 60 * 15, | |
}, | |
}, | |
searchUrl: { | |
type: "string", | |
label: "Search page url", | |
description: | |
"Booth's search page url (example: https://booth.pm/ja/browse/%E3%82%B9%E3%83%9E%E3%83%9B%E3%82%B1%E3%83%BC%E3%82%B9%E3%83%BB%E3%82%AB%E3%83%90%E3%83%BC?adult=only&new_arrival=true&sort=new )", | |
}, | |
maxPage: { | |
type: "string", | |
description: "page to fetch (number)", | |
optional: true, | |
}, | |
ng: { | |
type: "string", | |
label: "NG Shops", | |
description: "shops list to exclude (separate with ,)", | |
optional: true, | |
}, | |
}, | |
dedupe: "unique", | |
async run() { | |
const ng = this.ng?.split(",") || [] | |
const url = new URL(this.searchUrl) | |
;[ | |
["adult", "include"], | |
["new_arrival", "true"], | |
["sort", "new"], | |
].map(([k, v]) => { | |
if (!url.searchParams.has(k)) url.searchParams.set(k, v) | |
}) | |
for (let page of [...Array(parseInt(this.maxPage || "2") || 2).keys()] | |
.reverse() | |
.map((n) => n + 1)) { | |
if (page && page !== 1) { | |
url.searchParams.set("page", page.toString()) | |
} else { | |
url.searchParams.delete("page") | |
} | |
const r = await axios.get(url.href, { | |
headers: { | |
"User-Agent": | |
"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.149 Safari/537.36", | |
Cookie: "adult=t", | |
}, | |
responseType: "text", | |
timeout: 5000, | |
}) | |
if (r.status !== 200) { | |
console.error(`ステータスコードが${r.status}でした`) | |
return | |
} | |
try { | |
const document = domino.createDocument(r.data) | |
const container = document.querySelector("div.market-items") | |
if (!container) { | |
console.error("アイテムコンテナが見つかりませんでした") | |
continue | |
} | |
const itemsElement = container.querySelectorAll("li.item-card") | |
const items = Array.from(itemsElement) | |
.filter((item) => { | |
const brand = item.getAttribute("data-product-brand") | |
return !brand || !ng.includes(brand) | |
}) | |
.map((item) => { | |
const brand = item.getAttribute("data-product-brand") | |
const itemTitleNode: HTMLLinkElement | null = item.querySelector( | |
"div.item-card__title a" | |
) | |
if (!itemTitleNode) { | |
throw new Error("div.item-card__title a") | |
} | |
const title = itemTitleNode.textContent! | |
const itemLink = itemTitleNode.href! | |
const id = item.getAttribute("data-product-id") || itemLink | |
const price = item.getAttribute("data-product-price") | |
const isAdult = !!item.querySelector("div.adult") | |
const shopImage = | |
(item.querySelector( | |
"div.item-card__shop-info a div img" | |
) as HTMLImageElement | null)?.src?.replace("48x48", "128x128") || | |
null | |
const shopName = | |
item | |
.querySelector("div.item-card__shop-name") | |
?.textContent?.trim() || null | |
const eventName = | |
item.querySelector(".eventname-flag__name")?.textContent || null | |
const imagesNode = item.querySelector( | |
".item-card__thumbnail-images" | |
) | |
const images = Array.from( | |
imagesNode?.querySelectorAll(".item-card__thumbnail-image") || [] | |
) | |
.map((imageNode) => { | |
return imageNode | |
.getAttribute("data-original") | |
?.replace("c/300x300_a2_g5/", "") | |
}) | |
.filter((s) => typeof s === "string") as string[] | |
return { | |
title, | |
id, | |
link: itemLink, | |
isAdult, | |
eventName, | |
price, | |
image: images[0], | |
author: { | |
name: shopName, | |
link: brand && `http://${brand}.booth.pm`, | |
email: brand && `http://${brand}.booth.pm`, | |
image: shopImage, | |
}, | |
} | |
}) | |
items | |
.sort((a, b) => (a.id < b.id ? -1 : 1)) | |
.map((item) => { | |
this.$emit(item, { | |
id: item.link, | |
summary: item.title, | |
}) | |
}) | |
} catch (error) { | |
console.error(error) | |
break | |
} | |
} | |
}, | |
}) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment