Edited at

Chrome拡張機能:ダウンロードしたファイルをアップロードする

More than 1 year has passed since last update.


はじめに


やりたいこと

以下の操作を自動化する。


  1. Flickr等で見つけた自由利用可能な画像ファイルをダウンロードする。

  2. アップロードフォームにダウンロードした画像ファイルを指定してアップロードする。


制限事項


  • たとえChrome拡張機能がダウンロードしたものでも、ローカルのファイルにはアクセスできない。

  • アップロードフォームのファイル選択ダイアログをChrome拡張機能から操作できない。

こうした制限から、メモリ上の画像データから送信データを作成し、アップロードフォームを使わずに送信する必要がある。


手順1:画像ファイルのパスを探す

写真共有サイトは、オリジナル画像を直接表示していない。通信量削減のため縮小したものが表示されているので、まずはリンクをたどってオリジナル画像のURLを取得する。(Flickrの場合は、右下のアイコン「Download this photo」にリンクがある。)

その際、画像ファイルが置かれているドメインを確認し、manifest.jsonのpermissionsに追加する。(Flickrの場合は、「https://c1.staticflickr.com/」など。)ワイルドカードが使えないので、連番が降られている場合はすべての番号を追加する必要がある。


手順2:画像ファイルのダウンロード

XMLHttpRequestのresponseTypeblobを指定することで、画像ファイルをバイナリデータとして取得できる。


background.js

const DownloadBlob = (url) => {

const p = new Promise(resolve => {
const xhr = new XMLHttpRequest();
xhr.open('GET', url, true);
xhr.responseType = 'blob';
xhr.addEventListener('loadend', () => {resolve(xhr.response);});
xhr.send();
});

return p;
}

const DownloadImage = async (url) => {
const imageFile = await DownloadBlob(url);
}



手順3:送信データを作成する


フォーム

<body>

<form>
<input type="file" name="file" value=""/><br/>
<input type="text" name="title" value="タイトル"/><br/>
<input type="hidden" name="session_id" value="123456789"/>
<input type="submit" name="submit" value="送信"/>
</form>
</body>


background.js

const formData = new FormData();

formData.append('file', imageFile, 'ファイル名');
formData.append('title', 'タイトル');
formData.append('session_id', '123456789');
formData.append('submit', '送信'); //これはいらないかも。

FormDataオブジェクトを作成し、name属性をキーに値を追加していく。

ファイルを追加する場合は、第三引数にファイル名を指定する。ファイル名はダウンロードしたURLから切り出してもよいが、自由につけることもできる。

上記のsession_idのように、非表示になっている値も漏れなく追加する。


手順4:データを送信する

作成したFormDataオブジェクトをフォームのURLに送信する。cookieを必要とする場合は、XMLHttpRequestのwithCredentialstrueを指定して、フォームを受信してから送信する。


background.js

const GetForm = (url) => {

const p = new Promise(resolve => {
const xhr = new XMLHttpRequest();
xhr.open('Get', url, true);
xhr.responseType = 'text';
xhr.withCredentials = true;
xhr.addEventListener('loadend', () => {resolve(xhr.response);});
xhr.send();
});

return p;
}

const PostForm = (url, formData) => {
const p = new Promise(resolve => {
const xhr = new XMLHttpRequest();
xhr.open('POST', url, true);
xhr.responseType = 'text';
xhr.withCredentials = true;
xhr.addEventListener('loadend', () => {resolve(xhr.response);});
xhr.send(formData);
});

return p;
}

const UploadImage = async (url, formData) => {
await GetForm (url);
await PostForm (url, formData);
}



注意

フォームデータを自作するため、アップロードフォームに備わっているバリデーションチェックが行われない。送信前にフォームデータの整合性を確認する必要がある。