※社内専用

Yahooストアから画像を抜く

ただの備忘録。
YahooストアクリエイターPro画像管理からすべての画像をダウンロードする。
  • 全画像一覧の概念が無くフォルダ分けされているため、フォルダごとにダウンロードを実行する必要がある。
  • ブラウザで実行するため、ローカルにフォルダを作ることができない。フォルダごとのダウンロード完了毎に、ローカルにフォルダを作り退避させる必要がある。
  • 登録画像には拡張子がないため、全てjpgとしてダウンロードする(image/jpeg)

やること

  1. YahooストアクリエイターProの画像管理を開いておく
  2. 画像のフォルダをすべて空けた状態にする(+をクリックしておく)
  3. 各フォルダのIDとに最大画像枚数を知る(後述)
  4. 落とし始める(後述)

3. 各フォルダのIDとに最大画像枚数を知る

画像リストの動的取得にはフォルダのIDが必要。内部設定なので表には出ていない。
下記JSをコンソールで実行する。
コンソールにフォルダ名、ID、格納画像総数が表示されるので、メモしておくこと。
;(async () => {
  const titles = Array.from(document.querySelectorAll('.dynatree-title'))
  const range = 1000
  for (const title of titles) {
    const dtnode = $.ui.dynatree.getNode(title)
    const { id } = dtnode.data
    const url = document.querySelector('[name="list_url"]').value;
    const res = await fetch(
      url,
      {
        headers: {
          'content-type': 'application/x-www-form-urlencoded; charset=UTF-8',
        },
        body: `_token=&DispForm=List&pagekey=${id}&searchword=&searchrange=Item&searchtarget=undefined&start=1&range=${range}&sortkind=RegistTime&sort=desc&displaystatus=undefined&searchmode=List`,
        method: 'POST',
      }
    ).catch((e) => e)
    const dom = document.createElement('div')
    dom.innerHTML = await res.text()
    const items = Array.from(dom.getElementsByTagName('Item'))
    const totalElems = dom.getElementsByTagName('Total')
    const unitElems = dom.getElementsByTagName('Unit')
    console.log('Folder: ', title.textContent)
    console.log('ID: ', id)
    if (!totalElems.length) {
      console.log('Image is Nothing')
      console.log('----------------------------------------------')
      continue
    }
    console.log('Total: ', totalElems[0].textContent)
    console.log('----------------------------------------------')
    await new Promise((r) => setTimeout(r, 1000))
  }
})()

4. 落とし始める

前述のとおりフォルダごとにダウンロード作業を行う。

注意点

ブラウザのダウンロード設定の「ダウンロード前に各ファイルの保存場所を確認する」のチェックを外しておくこと。
ダウンロードごとにダイアログが出ると作業にならないので、必ず外しておく。

実行

下記JS最上部のrangeid書き換えて実行する。
コンソールにダウンロードの進捗が表示され、完了するとAleartが表示される。
;(async () => {
  const range = 全フォルダの中の画像数の最大値(数値)
  const id = 'フォルダID(文字列)'
  const url = document.querySelector('[name="list_url"]').value;
  const res = await fetch(
    url,
    {
      headers: {
        'content-type': 'application/x-www-form-urlencoded; charset=UTF-8',
      },
      body: `_token=&DispForm=List&pagekey=${id}&searchword=&searchrange=Item&searchtarget=undefined&start=1&range=${range}&sortkind=RegistTime&sort=desc&displaystatus=undefined&searchmode=List`,
      method: 'POST',
    }
  ).catch((e) => e)
  const dom = document.createElement('div')
  dom.innerHTML = await res.text()
  const items = Array.from(dom.getElementsByTagName('Item'))
  const totalElems = dom.getElementsByTagName('Total')
  const unitElems = dom.getElementsByTagName('Unit')
  if (!totalElems.length) {
    console.log('nothing')
    return
  }
  console.log('Images', unitElems[0].textContent+'/'+totalElems[0].textContent)
  for (let index = 0; index < items.length; index++) {
    const item = items[index]

    let imageFile = null
    imageFile = item.getElementsByTagName('ImageFile')[0]
    if (!imageFile) {
      imageFile = item.getElementsByTagName('RealFileName')[0]
    }
    console.log(index + 1 + '/' + items.length)
    const src = `https://item-shopping.c.yimg.jp/i/l/${imageFile.textContent}`
    let result = await getBlobUrl(src)
    await downloadImage(result)
  }
  alert('complete')

  function getBlobUrl(url) {
    return new Promise((resolve) => {
      let ext = url.replace(/^.+\.([^\.]+?)$/, '$1').replace(/jpg/, 'jpeg')
      let fileName = url.replace(/^.+\/([^\/]+?)$/, '$1')
      // let contentType = 'image/' + ext
      let contentType = 'image/jpeg'
      let form_data = new FormData()
      form_data.append('url', url)
      form_data.append('contentType', contentType)
      let xhr = new XMLHttpRequest()
      xhr.open(
        'POST',
        'https://www.iflag-moo.com/tools/common/server/image.php',
        true
      )
      xhr.onload = function (oEvent) {
        let contentType = xhr.getResponseHeader('Content-Type')
        let blob = new Blob([this.response], { type: contentType })
        let blobUrl = window.URL.createObjectURL(blob)
        resolve({ blobUrl, contentType, fileName })
      }
      xhr.responseType = 'arraybuffer'
      xhr.send(form_data)
    })
  }

  async function downloadImage(result) {
    let { blobUrl, fileName } = result
    let btn = $(`<a href="${blobUrl}" download="${fileName}">`).get(0)
    let evt = document.createEvent('MouseEvents')
    evt.initEvent('click', false, true)
    btn.dispatchEvent(evt)
    await new Promise((r) => setTimeout(r, 200))
  }
})()