Qiita API v2をPowerShellから実行してQiita記事をエクスポートしてみる

[Qiita API v2をPowerShellから実行してみる
](https://qiita.com/SAITO_Keita/items/9d31af30bf838abbf1a0)の記事で`PowerShell`で`Qiita API v2`を実行して、記事の一覧を取得してみましたが。

今回はスクリプトに引数としてアクセストークンを渡す事により、認証したユーザの公開記事と限定公開記事を一括でダウンロードしてみます。
なお下書きについては、下書きを取得できるAPIが無いようなので非対応。

APIで取得した内容から記事ごとにフォルダを作り、記事本文と画像をダウンロードしています。

例としては下記画像のような感じとなっており。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1670622/24846d71-89e4-994d-8085-af3d6dd7df38.png)

フォルダの中には、`body.md`と本文で利用されている画像が保存されまいます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1670622/665d0280-2de4-7f55-d5c2-49be05b18ae3.png)

```PowerShell:Copy-AuthQiitaItems.ps1
#!/usr/bin/env pwsh

<#
.SYNOPSIS
    qiita アクセストークン認証ユーザの記事をダウンロードするやつ
.DESCRIPTION
    qiitaのアクセストークン認証したユーザの記事一覧をダウンロードします。
    ダウンロード対象は公開記事と限定公開の記事のみ。
    下書きについては、下書きを取得できるAPIが存在しないようなので対象外。

    qiitaのapi v2を利用しているので利用制限に引っかかるととまります
    https://qiita.com/api/v2/docs#利用制限
    .EXAMPLE
    PS C:\> ./Copy-AuthQiitaItems.ps1 -Token <<access token>>
    PS C:\> "<<Token>>" | ./Copy-AuthQiitaItems.ps1
.INPUTS
    System.String
.OUTPUTS
    System.Collections.ArrayList
.NOTES
    None
#>

param (
    [Parameter(ValueFromPipeline = $True, Mandatory = $True)]
    [String]$Token
)
PROCESS {

    Set-StrictMode -Version Latest
    $ErrorActionPreference = "stop"

    # 認証用
    $headers = @{Authorization = "Bearer $Token" }

    # 一時配列
    $workArray = New-Object System.Collections.ArrayList

    # 1ページ目取得
    $uri = 'https://qiita.com/api/v2/authenticated_user/items?page=1&per_page=100'
    $1stResponse = Invoke-WebRequest -Headers $headers -Uri $uri
    $workArray += ($1stResponse | Select-Object -ExpandProperty Content | ConvertFrom-Json ) | Select-Object created_at, url, title, updated_at, private , tags , body

    #ページ処理
    #レスポンスヘッダから記事数を取得
    $totalCount = ([int[]]$1stResponse.Headers["Total-Count"])[0]
    # ページ数を計算
    $maxPage = [Math]::Ceiling($totalCount / 100)
    # 2ページ以降があったら取得
    for ($nowPage = 2; $nowPage -le $maxPage; $nowPage++) {
        $uri = 'https://qiita.com/api/v2/authenticated_user/items?page={1}&per_page=100' -f $userId, $nowPage
        $workArray += $(Invoke-WebRequest -Headers $headers -Uri $uri | Select-Object -ExpandProperty Content | ConvertFrom-Json) `
        | Select-Object created_at, url, title, updated_at, private
    }

    # 各記事と画像をダウンロード
    foreach ($workObj in $workArray) {

        # タイトル名で記事ごとにフォルダ分け
        $downloadFolderName = $workObj.title
        # ファイルに利用できない文字を削除
        [RegEx]::Replace($downloadFolderName, "[{0}]" -f [RegEx]::Escape([string][System.IO.Path]::GetInvalidFileNameChars()) , '')

        # 保存用フォルダパス
        $downloadFolderPath = Join-Path -Path $PsScriptRoot -ChildPath $downloadFolderName
        # フォルダ生成
        New-Item -ItemType Directory -Path $downloadFolderPath -Force

        # body出力用パス
        $mdPath = Join-Path -Path $downloadFolderPath -ChildPath "body.md"
        # bodyをutf8で保存
        $workObj.body | Out-File -Force $mdPath -Encoding utf8

        # imageをダウンロードして保存
        # bodyからurlを抽出
        $imageUrls = $workObj.body | Select-String '\!\[.*\]\((?<url>.*)\)' -AllMatches | ForEach-Object Matches | ForEach-Object groups | Where-Object name -EQ url | ForEach-Object value
        foreach ($imageUrl in $ImageUrls) {
            $imageName = Split-Path $imageUrl -Leaf
            $imagePath = Join-Path -Path $downloadFolderPath -ChildPath $imageName
            Invoke-WebRequest $imageUrl -OutFile $imagePath
        }
    }

    $workArray | Select-Object created_at, url, title, updated_at, private , tags | ConvertTo-json -Depth 3 | out-file -path $(Join-Path -Path $PsScriptRoot -ChildPath index.json) -Encoding utf8

}
```

## やっていること

- APIから取得したtitleからファイル利用できない文字を削除してフォルダ作成
- APIから取得できたbodyから画像ファイルのURLを抽出してダウンロード
- APIから取得できたbodyをutf8でbody.mdとしてダウンロード
- APIから取得できたメタ情報をindex.jsonとしてダウンロード

APIを実行して、ファイル保存しているくらいです。